def test_ext_detection(self): image_data = np.zeros((3, 4)) for ext in ('.bmp', '.jpg', '.png'): with self.subTest(ext=ext): image = ByteImage(data=encode_image(image_data, ext)) self.assertEqual(image.ext, ext)
def test_ctors(self): with TestDir() as test_dir: path = osp.join(test_dir, 'path.png') image = np.ones([2, 4, 3]) image_bytes = encode_image(image, 'png') for args in [ { 'data': image_bytes }, { 'data': lambda _: image_bytes }, { 'data': lambda _: image_bytes, 'ext': '.jpg' }, { 'data': image_bytes, 'path': path }, { 'data': image_bytes, 'path': path, 'size': (2, 4) }, { 'data': image_bytes, 'path': path, 'size': (2, 4) }, { 'path': path }, { 'path': path, 'size': (2, 4) }, ]: with self.subTest(**args): img = ByteImage(**args) # pylint: disable=pointless-statement self.assertEqual('data' in args, img.has_data) if img.has_data: np.testing.assert_array_equal(img.data, image) self.assertEqual(img.get_bytes(), image_bytes) img.size if 'size' in args: self.assertEqual(img.size, args['size']) if 'ext' in args or 'path' in args: self.assertEqual(img.ext, args.get('ext', '.png'))
def test_lazy_image_shape(self): data = encode_image(np.ones((5, 6, 3)), 'png') image_lazy = ByteImage(data=data, size=(2, 4)) image_eager = ByteImage(data=data) self.assertEqual((2, 4), image_lazy.size) self.assertEqual((5, 6), image_eager.size)
def _save_image(self, item, path=None): dst_ext = osp.splitext(osp.basename(path))[1] fmt = DetectionApiPath.IMAGE_EXT_FORMAT.get(dst_ext) if not fmt: log.warning("Item '%s': can't find format string for the '%s' " "image extension, the corresponding field will be empty." % \ (item.id, dst_ext)) buffer = encode_image(item.image.data, dst_ext) return buffer, fmt
def test_can_save_dataset_with_unknown_image_formats(self): test_dataset = Dataset.from_iterable([ DatasetItem(id=1, image=ByteImage(data=encode_image(np.ones((5, 4, 3)), 'png'), path='1/q.e'), attributes={'source_id': ''} ), DatasetItem(id=2, image=ByteImage(data=encode_image(np.ones((6, 4, 3)), 'png'), ext='qwe'), attributes={'source_id': ''} ) ], categories={ AnnotationType.label: LabelCategories(), }) with TestDir() as test_dir: self._test_save_and_load(test_dataset, partial(TfDetectionApiConverter.convert, save_images=True), test_dir)
def _archive_image(self, zipfile, item): image_name = self._make_image_filename(item) if osp.isfile(item.image.path): zipfile.write(item.image.path, arcname=image_name) elif isinstance(item.image, ByteImage): zipfile.writestr(image_name, item.image.get_bytes()) elif item.image.has_data: zipfile.writestr( image_name, encode_image(item.image.data, osp.splitext(image_name)[1]))
def _make_tf_example(self, item): features = { 'image/source_id': bytes_feature(str(item.id).encode('utf-8')), } filename = '' if item.has_image: filename = item.image.filename if not filename: filename = item.id + DetectionApiPath.IMAGE_EXT features['image/filename'] = bytes_feature(filename.encode('utf-8')) if not item.has_image: raise Exception("Failed to export dataset item '%s': " "item has no image info" % item.id) height, width = item.image.size features.update({ 'image/height': int64_feature(height), 'image/width': int64_feature(width), }) features.update({ 'image/encoded': bytes_feature(b''), 'image/format': bytes_feature(b'') }) if self._save_images: if item.has_image and item.image.has_data: fmt = DetectionApiPath.IMAGE_FORMAT buffer = encode_image(item.image.data, DetectionApiPath.IMAGE_EXT) features.update({ 'image/encoded': bytes_feature(buffer), 'image/format': bytes_feature(fmt.encode('utf-8')), }) else: log.warning("Item '%s' has no image" % item.id) instances = self._find_instances(item.annotations) instances = [ self._find_instance_parts(i, width, height) for i in instances ] features.update(self._export_instances(instances, width, height)) tf_example = tf.train.Example(features=tf.train.Features( feature=features)) return tf_example
def _save_image(self, item, path=None): src_ext = item.image.ext.lower() dst_ext = osp.splitext(osp.basename(path))[1].lower() fmt = DetectionApiPath.IMAGE_EXT_FORMAT.get(dst_ext, '') if not fmt: log.warning("Item '%s': can't find format string for the '%s' " "image extension, the corresponding field will be empty." % \ (item.id, dst_ext)) if src_ext == dst_ext and isinstance(item.image, ByteImage): buffer = item.image.get_bytes() else: buffer = encode_image(item.image.data, dst_ext) return buffer, fmt
def test_can_extract_voc(self): # TFDS is unable to generate fake examples for object detection # datasets. See <https://github.com/tensorflow/datasets/issues/3633>. tfds_example = { 'image/filename': 'test.png', 'image': encode_image(np.ones((20, 10)), '.png'), 'objects': { 'bbox': [[0.1, 0.2, 0.3, 0.4]], 'label': [5], 'is_difficult': [True], 'is_truncated': [False], 'pose': [0], } } with mock_tfds_data(example=tfds_example): tfds_info = tfds.builder('voc/2012').info pose_names = tfds_info.features['objects'].feature['pose'].names expected_dataset = Dataset.from_iterable( [ DatasetItem( id='test', subset='train', image=np.ones((20, 10)), annotations=[ Bbox(2, 2, 2, 4, label=5, attributes={ 'difficult': True, 'truncated': False, 'pose': pose_names[0].title(), }), ], ), ], categories=tfds_info.features['objects'].feature['label'].names ) extractor = make_tfds_extractor('voc/2012') actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, require_images=True)
def test_encode_and_decode_backends(self): backends = image_module._IMAGE_BACKENDS for save_backend, load_backend, c in product(backends, backends, [1, 3]): if c == 1: src_image = np.random.randint(0, 255 + 1, (2, 4)) else: src_image = np.random.randint(0, 255 + 1, (2, 4, c)) image_module._IMAGE_BACKEND = save_backend buffer = image_module.encode_image(src_image, '.png', jpeg_quality=100) # lossless image_module._IMAGE_BACKEND = load_backend dst_image = image_module.decode_image(buffer) self.assertTrue(np.array_equal(src_image, dst_image), 'save: %s, load: %s' % (save_backend, load_backend))
def _export_instances(self, instances, width, height): xmins = [ ] # List of normalized left x coordinates of bounding boxes (1 per box) xmaxs = [ ] # List of normalized right x coordinates of bounding boxes (1 per box) ymins = [ ] # List of normalized top y coordinates of bounding boxes (1 per box) ymaxs = [ ] # List of normalized bottom y coordinates of bounding boxes (1 per box) classes_text = [] # List of class names of bounding boxes (1 per box) classes = [] # List of class ids of bounding boxes (1 per box) masks = [] # List of PNG-encoded instance masks (1 per box) for leader, mask, box in instances: label = _make_printable(self._get_label(leader.label)) classes_text.append(label.encode('utf-8')) classes.append(self._get_label_id(leader.label)) xmins.append(box[0] / width) xmaxs.append((box[0] + box[2]) / width) ymins.append(box[1] / height) ymaxs.append((box[1] + box[3]) / height) if self._save_masks: if mask is not None: mask = encode_image(mask, '.png') else: mask = b'' masks.append(mask) result = {} if classes: result = { 'image/object/bbox/xmin': float_list_feature(xmins), 'image/object/bbox/xmax': float_list_feature(xmaxs), 'image/object/bbox/ymin': float_list_feature(ymins), 'image/object/bbox/ymax': float_list_feature(ymaxs), 'image/object/class/text': bytes_list_feature(classes_text), 'image/object/class/label': int64_list_feature(classes), } if masks: result['image/object/mask'] = bytes_list_feature(masks) return result
def test_can_extract_coco(self): tfds_example = { 'image': encode_image(np.ones((20, 10)), '.png'), 'image/filename': 'test.png', 'image/id': 123, 'objects': { 'bbox': [[0.1, 0.2, 0.3, 0.4]], 'label': [5], 'is_crowd': [True], } } with mock_tfds_data(example=tfds_example): tfds_info = tfds.builder('coco/2014').info expected_dataset = Dataset.from_iterable( [ DatasetItem( id='test', subset='train', image=np.ones((20, 10)), annotations=[ Bbox(2, 2, 2, 4, label=5, attributes={'is_crowd': True}), ], attributes={'id': 123}, ), ], categories=tfds_info.features['objects'].feature['label'].names ) extractor = make_tfds_extractor('coco/2014') actual_dataset = Dataset(extractor) compare_datasets(self, expected_dataset, actual_dataset, require_images=True)