def test_save_crop_overlapping(self): "Save a crop that is partially overlapping the image" i = InselectImage(TESTDATA / 'shapes.png') temp = tempfile.mkdtemp() try: # A crop that is partially overlapping the image p = Path(temp) / 'overlapping.png' i.save_crops([Rect(-0.1, -0.1, 0.4, 0.3)], [p]) crop = InselectImage(p).array # Crop should have this shape self.assertEqual((131, 184, 3), crop.shape) # Non-intersecting regions should be all zeroes self.assertTrue(np.all(0 == crop[0:44, 0:46])) self.assertTrue(np.all(0 == crop[0:44, ])) self.assertTrue(np.all(0 == crop[:, 0:46])) coords = list(i.from_normalised([Rect(-0.1, -0.1, 0.4, 0.3)])) expected = i.array[0:87, 0:138, ] self.assertTrue(np.all(expected == crop[44:, 46:, ])) finally: shutil.rmtree(temp)
def test_from_normalised(self): "Crops from normalised coordinates are as expected" i = InselectImage(TESTDATA / 'shapes.png') h, w = i.array.shape[:2] boxes = [Rect(0, 0, 1, 1), Rect(0, 0.2, 0.1, 0.8)] self.assertEqual([Rect(0, 0, 459, 437), Rect(0, 87, 46, 350)], list(i.from_normalised(boxes)))
def test_comparison(self): a = Rect(0, 1, 2, 3) self.assertEqual(a, self.R) b = Rect(9, 1, 2, 3) self.assertNotEqual(b, self.R) with self.assertRaises(NotImplementedError): a == '' with self.assertRaises(NotImplementedError): a == Point(1, 1)
def test_set_items(self): "Items are set as expected" # TODO LH Check field validation path = TESTDATA / 'test_segment.inselect' doc = InselectDocument.load(path) items = [ {'fields': {}, 'rect': Rect(0, 0, 0.5, 0.5)}, ] doc.set_items(items) self.assertEqual(items, doc.items) # Not normalised items = [ {'fields': {}, 'rect': Rect(0, 0, 1, 2)}, ] self.assertRaises(InselectError, doc.set_items, items)
def test_set_items(self): "Items are set as expected" # TODO LH Check field validation path = TESTDATA / 'shapes.inselect' doc = InselectDocument.load(path) items = [{'fields': {}, 'rect': Rect(0, 0, 0.5, 0.5)}] doc.set_items(items) self.assertEqual(items, doc.items)
def test_save_crops(self): "Cropped images are as expected" i = InselectImage(TESTDATA / 'test_segment.png') temp = tempfile.mkdtemp() try: # A crop that is the entire image p = Path(temp) / 'whole.png' i.save_crops([Rect(0, 0, 1, 1)], [p]) self.assertTrue(np.all(i.array == InselectImage(p).array)) # A crop that is a portion of the image # Make sure that existing file is overwritten p = Path(temp) / 'partial.png' p.open('w') # File just needs to exist i.save_crops([Rect(0.1, 0.2, 0.4, 0.3)], [p]) expected = i.array[87:218, 45:228] self.assertTrue(np.all(expected == InselectImage(p).array)) finally: shutil.rmtree(temp)
class TestRect(unittest.TestCase): R = Rect(0, 1, 2, 3) def test_rect(self): self.assertEqual(0, self.R.left) self.assertEqual(1, self.R.top) self.assertEqual(2, self.R.width) self.assertEqual(3, self.R.height) def test_iter(self): left, top, width, height = self.R self.assertEqual([0, 1, 2, 3], [left, top, width, height]) def test_area(self): self.assertEqual(6, self.R.area) def test_coordinates(self): self.assertEqual(Coordinates(0, 1, 2, 4), self.R.coordinates) def test_topleft(self): self.assertEqual(Point(0, 1), self.R.topleft) def test_bottomright(self): self.assertEqual(Point(2, 4), self.R.bottomright) def test_x_centre(self): self.assertEqual(1, self.R.x_centre) def test_y_centre(self): self.assertEqual(2.5, self.R.y_centre) def test_centre(self): self.assertEqual(Point(1, 2.5), self.R.centre) def test_padded(self): r = Rect(0, 0, 100, 100) self.assertEqual(Rect(-10, -10, 120, 120), r.padded(10.0)) def test_intersect(self): a = Rect(-10, -10, 110, 110) b = Rect(0, 0, 100, 100) self.assertEqual(Rect(0, 0, 100, 100), a.intersect(b)) def test_comparison(self): a = Rect(0, 1, 2, 3) self.assertEqual(a, self.R) b = Rect(9, 1, 2, 3) self.assertNotEqual(b, self.R) with self.assertRaises(NotImplementedError): a == '' with self.assertRaises(NotImplementedError): a == Point(1, 1)
def test_save_crops_progress(self): "Check values passed to callable of save_crops" i = InselectImage(TESTDATA / 'test_segment.png') temp = tempfile.mkdtemp() try: progress = Mock(return_value=None) i.save_crops([Rect(0, 0, 1, 1)], [Path(temp) / 'whole.png'], progress) progress.assert_called_once_with('Writing crop 1') finally: shutil.rmtree(temp)
def test_save_crops_read_only_directory(self): "Can't write crops to a read-only directory" # This case is doing more than simply testing filesystem behavour # because it tests the failure code in InselectImage temp = tempfile.mkdtemp() try: make_readonly(temp) i = InselectImage(TESTDATA / 'test_segment.png') with self.assertRaises(InselectError): i.save_crops([Rect(0, 0, 1, 1)], [Path(temp) / 'x.png']) finally: rmtree_readonly(temp)
def test_save(self): "Document save writes items" source = TESTDATA / 'test_segment.inselect' temp = tempfile.mkdtemp() with temp_directory_with_files(TESTDATA / 'test_segment.inselect', TESTDATA / 'test_segment.png') as tempdir: items = [ {'fields': {}, 'rect': Rect(0.1, 0.2, 0.5, 0.5) }, ] doc_temp = tempdir / 'test_segment.inselect' d = InselectDocument.load(doc_temp) d.set_items(items) d.save() self.assertEqual(items, InselectDocument.load(doc_temp).items)
def test_save_crop_outside(self): "Save a crop that is a entirely outside of the image" i = InselectImage(TESTDATA / 'shapes.png') temp = tempfile.mkdtemp() try: # A crop that is a entirely outside of the image p = Path(temp) / 'outside.png' i.save_crops([Rect(-1.5, -5.0, 1.0, 3.0)], [p]) crop = InselectImage(p).array # Crop should have this shape self.assertEqual((1311, 459, 3), crop.shape) # All of the crop should be all zeroes self.assertTrue(np.all(0 == crop)) finally: shutil.rmtree(temp)
def test_save_crops_all_rotated(self): "Crops are saved with different rotations" i = InselectImage(TESTDATA / 'shapes.png') temp = tempfile.mkdtemp() try: i.save_crops(repeat(Rect(0, 0, 1, 1), 4), (Path(temp) / '{0}.png'.format(n) for n in range(0, 4)), rotation=[0, 90, 180, -90]) crop = cv2.imread(str(Path(temp) / '0.png')) self.assertTrue(np.all(i.array == crop)) crop = cv2.imread(str(Path(temp) / '1.png')) self.assertTrue(np.all(cv2.flip(cv2.transpose(i.array), 1) == crop)) crop = cv2.imread(str(Path(temp) / '2.png')) self.assertTrue(np.all(cv2.flip(i.array, -1) == crop)) crop = cv2.imread(str(Path(temp) / '3.png')) self.assertTrue(np.all(cv2.flip(cv2.transpose(i.array), 0) == crop)) finally: shutil.rmtree(temp)
def test_save_crops_all_rotated90(self): "All crops are saved with 90 degrees of clockwise rotation" i = InselectImage(TESTDATA / 'shapes.png') temp = tempfile.mkdtemp() try: i.save_crops(repeat(Rect(0, 0, 1, 1), 4), (Path(temp) / '{0}.png'.format(n) for n in range(0, 4)), rotation=90) crop = cv2.imread(str(Path(temp) / '0.png')) self.assertTrue(np.all(cv2.flip(cv2.transpose(i.array), 1) == crop)) crop = cv2.imread(str(Path(temp) / '1.png')) self.assertTrue(np.all(cv2.flip(cv2.transpose(i.array), 1) == crop)) crop = cv2.imread(str(Path(temp) / '2.png')) self.assertTrue(np.all(cv2.flip(cv2.transpose(i.array), 1) == crop)) crop = cv2.imread(str(Path(temp) / '3.png')) self.assertTrue(np.all(cv2.flip(cv2.transpose(i.array), 1) == crop)) finally: shutil.rmtree(temp)
class TestRect(unittest.TestCase): R = Rect(0, 1, 2, 3) def test_rect(self): self.assertEqual(0, self.R.left) self.assertEqual(1, self.R.top) self.assertEqual(2, self.R.width) self.assertEqual(3, self.R.height) self.assertRaises(InselectError, Rect,-1, 1, 2, 3) self.assertRaises(InselectError, Rect, 0,-1, 2, 3) self.assertRaises(InselectError, Rect, 0, 1, 0, 3) self.assertRaises(InselectError, Rect, 0, 1, 2, 0) def test_iter(self): left, top, width, height = self.R self.assertEqual([0, 1, 2, 3], [left, top, width, height]) def test_area(self): self.assertEqual(6, self.R.area) def test_coordinates(self): self.assertEqual(Coordinates(0, 1, 2, 4), self.R.coordinates) def test_topleft(self): self.assertEqual(Point(0, 1), self.R.topleft) def test_bottomright(self): self.assertEqual(Point(2, 4), self.R.bottomright) def test_centre(self): self.assertEqual(Point(1, 2), self.R.centre) def test_comparison(self): a = Rect(0, 1, 2, 3) self.assertEqual(a, self.R) b = Rect(9, 1, 2, 3) self.assertNotEqual(b, self.R) with self.assertRaises(NotImplementedError): a == '' with self.assertRaises(NotImplementedError): a == Point(1,1)
def test_save_crop_partial(self): "Save a crop that is a portion of the image" i = InselectImage(TESTDATA / 'shapes.png') temp = tempfile.mkdtemp() try: # A crop that is a portion of the image p = Path(temp) / 'partial.png' i.save_crops([Rect(0.1, 0.2, 0.4, 0.3)], [p]) crop = InselectImage(p).array # Crop should have this shape self.assertEqual((131, 184, 3), crop.shape) # Crop should have these pixels expected = i.array[87:218, 46:230] self.assertTrue(np.all(expected == InselectImage(p).array)) finally: shutil.rmtree(temp)
def test_save(self): "Save document" with temp_directory_with_files(TESTDATA / 'shapes.inselect', TESTDATA / 'shapes.png') as tempdir: items = [{ 'fields': { 'type': 'インセクト' }, 'rect': Rect(0.1, 0.2, 0.5, 0.5), }] doc_temp = tempdir / 'shapes.inselect' d = InselectDocument.load(doc_temp) d.set_items(items) d.save() self.assertEqual(items, InselectDocument.load(doc_temp).items) # Saved on time should be within last 2 seconds now = datetime.now(pytz.timezone("UTC")) saved_on = d.properties['Saved on'] self.assertLessEqual((now - saved_on).seconds, 2)
def test_overwrite_existing_crop(self): "Overwrite an existing file with a crop that is the entire image" i = InselectImage(TESTDATA / 'shapes.png') temp = tempfile.mkdtemp() try: p = Path(temp) / 'whole.png' # Create an image that is all black self.assertTrue(cv2.imwrite(str(p), np.zeros((500, 500, 3), dtype='uint8'))) # A crop that is the entire image i.save_crops([Rect(0, 0, 1, 1)], [p]) crop = InselectImage(p).array # Crop should be the same shape as the image self.assertEqual(i.array.shape, crop.shape) # Crop should have the same pixels as the image self.assertTrue(np.all(i.array == crop)) finally: shutil.rmtree(temp)
def to_normalised(self, boxes): self.validate_in_bounds(boxes) h, w = self.array.shape[:2] for left, top, width, height in boxes: yield Rect(float(left)/w, float(top)/h, float(width)/w, float(height)/h)
def test_intersect(self): a = Rect(-10, -10, 110, 110) b = Rect(0, 0, 100, 100) self.assertEqual(Rect(0, 0, 100, 100), a.intersect(b))
def test_padded(self): r = Rect(0, 0, 100, 100) self.assertEqual(Rect(-10, -10, 120, 120), r.padded(10.0))
def test_validate_normalised(self): validate_normalised([Rect(0,0,1,1)]) self.assertRaises(InselectError, validate_normalised, [(-0.1, 0, 1, 1)]) self.assertRaises(InselectError, validate_normalised, [( 0, -0.1, 1, 1)]) self.assertRaises(InselectError, validate_normalised, [( 0, 0, 1.1, 1)]) self.assertRaises(InselectError, validate_normalised, [( 0, 0, 1, 1.1)])
def test_to_normalised(self): i = InselectImage(TESTDATA / 'test_segment.png') boxes = [Rect(0, 0, 459, 437), Rect(0, 0, 153, 23)] self.assertEqual( [Rect(0, 0, 1, 1), Rect(0, 0, 1.0 / 3, 1.0 / 19)], list(i.to_normalised(boxes)))
def test_not_normalised(self): i = InselectImage(TESTDATA / 'test_segment.png') self.assertRaises(i.from_normalised([Rect(0, 0, 2, 2)]))
def from_normalised(self, boxes): validate_normalised(boxes) h, w = self.array.shape[:2] for left, top, width, height in boxes: yield Rect(int(w*left), int(h*top), int(w*width), int(h*height))
def test_crops_bad_rotation(self): "Generate crops with an illegal rotation" i = InselectImage(TESTDATA / 'shapes.png') # Need to use context manager because i.crops is a generator function with self.assertRaises(ValueError): list(i.crops([Rect(0, 0, 1, 1)], -1))