Add at new repo again
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
|
||||
import json
|
||||
import numpy as np
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
import pycocotools
|
||||
|
||||
from detectron2.data import DatasetCatalog, MetadataCatalog
|
||||
from detectron2.data.datasets.coco import convert_to_coco_dict, load_coco_json
|
||||
from detectron2.structures import BoxMode
|
||||
|
||||
|
||||
def make_mask():
|
||||
"""
|
||||
Makes a donut shaped binary mask.
|
||||
"""
|
||||
H = 100
|
||||
W = 100
|
||||
mask = np.zeros([H, W], dtype=np.uint8)
|
||||
for x in range(W):
|
||||
for y in range(H):
|
||||
d = np.linalg.norm(np.array([W, H]) / 2 - np.array([x, y]))
|
||||
if d > 10 and d < 20:
|
||||
mask[y, x] = 1
|
||||
return mask
|
||||
|
||||
|
||||
def make_dataset_dicts(mask):
|
||||
"""
|
||||
Returns a list of dicts that represents a single COCO data point for
|
||||
object detection. The single instance given by `mask` is represented by
|
||||
RLE.
|
||||
"""
|
||||
record = {}
|
||||
record["file_name"] = "test"
|
||||
record["image_id"] = 0
|
||||
record["height"] = mask.shape[0]
|
||||
record["width"] = mask.shape[1]
|
||||
|
||||
y, x = np.nonzero(mask)
|
||||
segmentation = pycocotools.mask.encode(np.asarray(mask, order="F"))
|
||||
min_x = np.min(x)
|
||||
max_x = np.max(x)
|
||||
min_y = np.min(y)
|
||||
max_y = np.max(y)
|
||||
obj = {
|
||||
"bbox": [min_x, min_y, max_x, max_y],
|
||||
"bbox_mode": BoxMode.XYXY_ABS,
|
||||
"category_id": 0,
|
||||
"iscrowd": 0,
|
||||
"segmentation": segmentation,
|
||||
}
|
||||
record["annotations"] = [obj]
|
||||
return [record]
|
||||
|
||||
|
||||
class TestRLEToJson(unittest.TestCase):
|
||||
def test(self):
|
||||
# Make a dummy dataset.
|
||||
mask = make_mask()
|
||||
DatasetCatalog.register("test_dataset", lambda: make_dataset_dicts(mask))
|
||||
MetadataCatalog.get("test_dataset").set(thing_classes=["test_label"])
|
||||
|
||||
# Dump to json.
|
||||
json_dict = convert_to_coco_dict("test_dataset")
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
json_file_name = os.path.join(tmpdir, "test.json")
|
||||
with open(json_file_name, "w") as f:
|
||||
json.dump(json_dict, f)
|
||||
# Load from json.
|
||||
dicts = load_coco_json(json_file_name, "")
|
||||
|
||||
# Check the loaded mask matches the original.
|
||||
anno = dicts[0]["annotations"][0]
|
||||
loaded_mask = pycocotools.mask.decode(anno["segmentation"])
|
||||
self.assertTrue(np.array_equal(loaded_mask, mask))
|
@@ -0,0 +1,116 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
|
||||
import copy
|
||||
import numpy as np
|
||||
import unittest
|
||||
import pycocotools.mask as mask_util
|
||||
|
||||
from detectron2.data import detection_utils
|
||||
from detectron2.data import transforms as T
|
||||
from detectron2.structures import BitMasks, BoxMode
|
||||
|
||||
|
||||
class TestTransformAnnotations(unittest.TestCase):
|
||||
def test_transform_simple_annotation(self):
|
||||
transforms = T.TransformList([T.HFlipTransform(400)])
|
||||
anno = {
|
||||
"bbox": np.asarray([10, 10, 200, 300]),
|
||||
"bbox_mode": BoxMode.XYXY_ABS,
|
||||
"category_id": 3,
|
||||
"segmentation": [[10, 10, 100, 100, 100, 10], [150, 150, 200, 150, 200, 200]],
|
||||
}
|
||||
|
||||
output = detection_utils.transform_instance_annotations(anno, transforms, (400, 400))
|
||||
self.assertTrue(np.allclose(output["bbox"], [200, 10, 390, 300]))
|
||||
self.assertEqual(len(output["segmentation"]), len(anno["segmentation"]))
|
||||
self.assertTrue(np.allclose(output["segmentation"][0], [390, 10, 300, 100, 300, 10]))
|
||||
|
||||
detection_utils.annotations_to_instances([output, output], (400, 400))
|
||||
|
||||
def test_flip_keypoints(self):
|
||||
transforms = T.TransformList([T.HFlipTransform(400)])
|
||||
anno = {
|
||||
"bbox": np.asarray([10, 10, 200, 300]),
|
||||
"bbox_mode": BoxMode.XYXY_ABS,
|
||||
"keypoints": np.random.rand(17, 3) * 50 + 15,
|
||||
}
|
||||
|
||||
output = detection_utils.transform_instance_annotations(
|
||||
copy.deepcopy(anno),
|
||||
transforms,
|
||||
(400, 400),
|
||||
keypoint_hflip_indices=detection_utils.create_keypoint_hflip_indices(
|
||||
["keypoints_coco_2017_train"]
|
||||
),
|
||||
)
|
||||
# The first keypoint is nose
|
||||
self.assertTrue(np.allclose(output["keypoints"][0, 0], 400 - anno["keypoints"][0, 0]))
|
||||
# The last 16 keypoints are 8 left-right pairs
|
||||
self.assertTrue(
|
||||
np.allclose(
|
||||
output["keypoints"][1:, 0].reshape(-1, 2)[:, ::-1],
|
||||
400 - anno["keypoints"][1:, 0].reshape(-1, 2),
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
np.allclose(
|
||||
output["keypoints"][1:, 1:].reshape(-1, 2, 2)[:, ::-1, :],
|
||||
anno["keypoints"][1:, 1:].reshape(-1, 2, 2),
|
||||
)
|
||||
)
|
||||
|
||||
def test_transform_RLE(self):
|
||||
transforms = T.TransformList([T.HFlipTransform(400)])
|
||||
mask = np.zeros((300, 400), order="F").astype("uint8")
|
||||
mask[:, :200] = 1
|
||||
|
||||
anno = {
|
||||
"bbox": np.asarray([10, 10, 200, 300]),
|
||||
"bbox_mode": BoxMode.XYXY_ABS,
|
||||
"segmentation": mask_util.encode(mask[:, :, None])[0],
|
||||
"category_id": 3,
|
||||
}
|
||||
output = detection_utils.transform_instance_annotations(
|
||||
copy.deepcopy(anno), transforms, (300, 400)
|
||||
)
|
||||
mask = output["segmentation"]
|
||||
self.assertTrue((mask[:, 200:] == 1).all())
|
||||
self.assertTrue((mask[:, :200] == 0).all())
|
||||
|
||||
inst = detection_utils.annotations_to_instances(
|
||||
[output, output], (400, 400), mask_format="bitmask"
|
||||
)
|
||||
self.assertTrue(isinstance(inst.gt_masks, BitMasks))
|
||||
|
||||
def test_transform_RLE_resize(self):
|
||||
transforms = T.TransformList(
|
||||
[T.HFlipTransform(400), T.ScaleTransform(300, 400, 400, 400, "bilinear")]
|
||||
)
|
||||
mask = np.zeros((300, 400), order="F").astype("uint8")
|
||||
mask[:, :200] = 1
|
||||
|
||||
anno = {
|
||||
"bbox": np.asarray([10, 10, 200, 300]),
|
||||
"bbox_mode": BoxMode.XYXY_ABS,
|
||||
"segmentation": mask_util.encode(mask[:, :, None])[0],
|
||||
"category_id": 3,
|
||||
}
|
||||
output = detection_utils.transform_instance_annotations(
|
||||
copy.deepcopy(anno), transforms, (400, 400)
|
||||
)
|
||||
|
||||
inst = detection_utils.annotations_to_instances(
|
||||
[output, output], (400, 400), mask_format="bitmask"
|
||||
)
|
||||
self.assertTrue(isinstance(inst.gt_masks, BitMasks))
|
||||
|
||||
def test_gen_crop(self):
|
||||
instance = {"bbox": [10, 10, 100, 100], "bbox_mode": BoxMode.XYXY_ABS}
|
||||
t = detection_utils.gen_crop_transform_with_instance((10, 10), (150, 150), instance)
|
||||
# the box center must fall into the cropped region
|
||||
self.assertTrue(t.x0 <= 55 <= t.x0 + t.w)
|
||||
|
||||
def test_gen_crop_outside_boxes(self):
|
||||
instance = {"bbox": [10, 10, 100, 100], "bbox_mode": BoxMode.XYXY_ABS}
|
||||
with self.assertRaises(AssertionError):
|
||||
detection_utils.gen_crop_transform_with_instance((10, 10), (15, 15), instance)
|
@@ -0,0 +1,62 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
|
||||
import numpy as np
|
||||
import unittest
|
||||
|
||||
from detectron2.data.transforms.transform import RotationTransform
|
||||
|
||||
|
||||
class TestRotationTransform(unittest.TestCase):
|
||||
def assertEqualsArrays(self, a1, a2):
|
||||
self.assertTrue(np.allclose(a1, a2))
|
||||
|
||||
def randomData(self, h=5, w=5):
|
||||
image = np.random.rand(h, w)
|
||||
coords = np.array([[i, j] for j in range(h + 1) for i in range(w + 1)], dtype=float)
|
||||
return image, coords, h, w
|
||||
|
||||
def test180(self):
|
||||
image, coords, h, w = self.randomData(6, 6)
|
||||
rot = RotationTransform(h, w, 180, expand=False, center=None)
|
||||
self.assertEqualsArrays(rot.apply_image(image), image[::-1, ::-1])
|
||||
rotated_coords = [[w - c[0], h - c[1]] for c in coords]
|
||||
self.assertEqualsArrays(rot.apply_coords(coords), rotated_coords)
|
||||
|
||||
def test45_coords(self):
|
||||
_, coords, h, w = self.randomData(4, 6)
|
||||
rot = RotationTransform(h, w, 45, expand=False, center=None)
|
||||
rotated_coords = [
|
||||
[(x + y - (h + w) / 2) / np.sqrt(2) + w / 2, h / 2 + (y + (w - h) / 2 - x) / np.sqrt(2)]
|
||||
for (x, y) in coords
|
||||
]
|
||||
self.assertEqualsArrays(rot.apply_coords(coords), rotated_coords)
|
||||
|
||||
def test90(self):
|
||||
image, coords, h, w = self.randomData()
|
||||
rot = RotationTransform(h, w, 90, expand=False, center=None)
|
||||
self.assertEqualsArrays(rot.apply_image(image), image.T[::-1])
|
||||
rotated_coords = [[c[1], w - c[0]] for c in coords]
|
||||
self.assertEqualsArrays(rot.apply_coords(coords), rotated_coords)
|
||||
|
||||
def test90_expand(self): # non-square image
|
||||
image, coords, h, w = self.randomData(h=5, w=8)
|
||||
rot = RotationTransform(h, w, 90, expand=True, center=None)
|
||||
self.assertEqualsArrays(rot.apply_image(image), image.T[::-1])
|
||||
rotated_coords = [[c[1], w - c[0]] for c in coords]
|
||||
self.assertEqualsArrays(rot.apply_coords(coords), rotated_coords)
|
||||
|
||||
def test_center_expand(self):
|
||||
# center has no effect if expand=True because it only affects shifting
|
||||
image, coords, h, w = self.randomData(h=5, w=8)
|
||||
angle = np.random.randint(360)
|
||||
rot1 = RotationTransform(h, w, angle, expand=True, center=None)
|
||||
rot2 = RotationTransform(h, w, angle, expand=True, center=(0, 0))
|
||||
rot3 = RotationTransform(h, w, angle, expand=True, center=(h, w))
|
||||
rot4 = RotationTransform(h, w, angle, expand=True, center=(2, 5))
|
||||
for r1 in [rot1, rot2, rot3, rot4]:
|
||||
for r2 in [rot1, rot2, rot3, rot4]:
|
||||
self.assertEqualsArrays(r1.apply_image(image), r2.apply_image(image))
|
||||
self.assertEqualsArrays(r1.apply_coords(coords), r2.apply_coords(coords))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
|
||||
import unittest
|
||||
from torch.utils.data.sampler import SequentialSampler
|
||||
|
||||
from detectron2.data.samplers import GroupedBatchSampler
|
||||
|
||||
|
||||
class TestGroupedBatchSampler(unittest.TestCase):
|
||||
def test_missing_group_id(self):
|
||||
sampler = SequentialSampler(list(range(100)))
|
||||
group_ids = [1] * 100
|
||||
samples = GroupedBatchSampler(sampler, group_ids, 2)
|
||||
|
||||
for mini_batch in samples:
|
||||
self.assertEqual(len(mini_batch), 2)
|
||||
|
||||
def test_groups(self):
|
||||
sampler = SequentialSampler(list(range(100)))
|
||||
group_ids = [1, 0] * 50
|
||||
samples = GroupedBatchSampler(sampler, group_ids, 2)
|
||||
|
||||
for mini_batch in samples:
|
||||
self.assertEqual((mini_batch[0] + mini_batch[1]) % 2, 0)
|
@@ -0,0 +1,134 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
|
||||
|
||||
import logging
|
||||
import numpy as np
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from detectron2.config import get_cfg
|
||||
from detectron2.data import detection_utils
|
||||
from detectron2.data import transforms as T
|
||||
from detectron2.utils.logger import setup_logger
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestTransforms(unittest.TestCase):
|
||||
def setUp(self):
|
||||
setup_logger()
|
||||
|
||||
def test_apply_rotated_boxes(self):
|
||||
np.random.seed(125)
|
||||
cfg = get_cfg()
|
||||
is_train = True
|
||||
transform_gen = detection_utils.build_transform_gen(cfg, is_train)
|
||||
image = np.random.rand(200, 300)
|
||||
image, transforms = T.apply_transform_gens(transform_gen, image)
|
||||
image_shape = image.shape[:2] # h, w
|
||||
assert image_shape == (800, 1200)
|
||||
annotation = {"bbox": [179, 97, 62, 40, -56]}
|
||||
|
||||
boxes = np.array([annotation["bbox"]], dtype=np.float64) # boxes.shape = (1, 5)
|
||||
transformed_bbox = transforms.apply_rotated_box(boxes)[0]
|
||||
|
||||
expected_bbox = np.array([484, 388, 248, 160, 56], dtype=np.float64)
|
||||
err_msg = "transformed_bbox = {}, expected {}".format(transformed_bbox, expected_bbox)
|
||||
assert np.allclose(transformed_bbox, expected_bbox), err_msg
|
||||
|
||||
def test_apply_rotated_boxes_unequal_scaling_factor(self):
|
||||
np.random.seed(125)
|
||||
h, w = 400, 200
|
||||
newh, neww = 800, 800
|
||||
image = np.random.rand(h, w)
|
||||
transform_gen = []
|
||||
transform_gen.append(T.Resize(shape=(newh, neww)))
|
||||
image, transforms = T.apply_transform_gens(transform_gen, image)
|
||||
image_shape = image.shape[:2] # h, w
|
||||
assert image_shape == (newh, neww)
|
||||
|
||||
boxes = np.array(
|
||||
[
|
||||
[150, 100, 40, 20, 0],
|
||||
[150, 100, 40, 20, 30],
|
||||
[150, 100, 40, 20, 90],
|
||||
[150, 100, 40, 20, -90],
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
transformed_boxes = transforms.apply_rotated_box(boxes)
|
||||
|
||||
expected_bboxes = np.array(
|
||||
[
|
||||
[600, 200, 160, 40, 0],
|
||||
[600, 200, 144.22205102, 52.91502622, 49.10660535],
|
||||
[600, 200, 80, 80, 90],
|
||||
[600, 200, 80, 80, -90],
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
err_msg = "transformed_boxes = {}, expected {}".format(transformed_boxes, expected_bboxes)
|
||||
assert np.allclose(transformed_boxes, expected_bboxes), err_msg
|
||||
|
||||
def test_print_transform_gen(self):
|
||||
t = T.RandomCrop("relative", (100, 100))
|
||||
self.assertTrue(str(t) == "RandomCrop(crop_type='relative', crop_size=(100, 100))")
|
||||
|
||||
t = T.RandomFlip(prob=0.5)
|
||||
self.assertTrue(str(t) == "RandomFlip(prob=0.5)")
|
||||
|
||||
t = T.RandomFlip()
|
||||
self.assertTrue(str(t) == "RandomFlip()")
|
||||
|
||||
def test_random_apply_prob_out_of_range_check(self):
|
||||
# GIVEN
|
||||
test_probabilities = {0.0: True, 0.5: True, 1.0: True, -0.01: False, 1.01: False}
|
||||
|
||||
# WHEN
|
||||
for given_probability, is_valid in test_probabilities.items():
|
||||
# THEN
|
||||
if not is_valid:
|
||||
self.assertRaises(AssertionError, T.RandomApply, None, prob=given_probability)
|
||||
else:
|
||||
T.RandomApply(T.NoOpTransform(), prob=given_probability)
|
||||
|
||||
def test_random_apply_wrapping_transform_gen_probability_occured_evaluation(self):
|
||||
# GIVEN
|
||||
transform_mock = mock.MagicMock(name="MockTransform", spec=T.TransformGen)
|
||||
image_mock = mock.MagicMock(name="MockImage")
|
||||
random_apply = T.RandomApply(transform_mock, prob=0.001)
|
||||
|
||||
# WHEN
|
||||
with mock.patch.object(random_apply, "_rand_range", return_value=0.0001):
|
||||
transform = random_apply.get_transform(image_mock)
|
||||
|
||||
# THEN
|
||||
transform_mock.get_transform.assert_called_once_with(image_mock)
|
||||
self.assertIsNot(transform, transform_mock)
|
||||
|
||||
def test_random_apply_wrapping_std_transform_probability_occured_evaluation(self):
|
||||
# GIVEN
|
||||
transform_mock = mock.MagicMock(name="MockTransform", spec=T.Transform)
|
||||
image_mock = mock.MagicMock(name="MockImage")
|
||||
random_apply = T.RandomApply(transform_mock, prob=0.001)
|
||||
|
||||
# WHEN
|
||||
with mock.patch.object(random_apply, "_rand_range", return_value=0.0001):
|
||||
transform = random_apply.get_transform(image_mock)
|
||||
|
||||
# THEN
|
||||
self.assertIs(transform, transform_mock)
|
||||
|
||||
def test_random_apply_probability_not_occured_evaluation(self):
|
||||
# GIVEN
|
||||
transform_mock = mock.MagicMock(name="MockTransform", spec=T.TransformGen)
|
||||
image_mock = mock.MagicMock(name="MockImage")
|
||||
random_apply = T.RandomApply(transform_mock, prob=0.001)
|
||||
|
||||
# WHEN
|
||||
with mock.patch.object(random_apply, "_rand_range", return_value=0.9):
|
||||
transform = random_apply.get_transform(image_mock)
|
||||
|
||||
# THEN
|
||||
transform_mock.get_transform.assert_not_called()
|
||||
self.assertIsInstance(transform, T.NoOpTransform)
|
Reference in New Issue
Block a user