diff --git a/system_tests/vision.py b/system_tests/vision.py index 3d0c029370f5e..f23f0a275b6ef 100644 --- a/system_tests/vision.py +++ b/system_tests/vision.py @@ -474,13 +474,16 @@ def tearDown(self): value.delete() def _assert_color(self, color): - self.assertIsInstance(color.red, int) - self.assertIsInstance(color.green, int) - self.assertIsInstance(color.blue, int) + self.assertIsInstance(color.red, (int, float)) + self.assertIsInstance(color.green, (int, float)) + self.assertIsInstance(color.blue, (int, float)) + if not isinstance(color.alpha, float): + self.assertIsInstance(color.alpha.value, float) + else: + self.assertIsInstance(color.alpha, float) self.assertNotEqual(color.red, 0.0) self.assertNotEqual(color.green, 0.0) self.assertNotEqual(color.blue, 0.0) - self.assertIsInstance(color.alpha, float) def _assert_properties(self, image_property): from google.cloud.vision.color import ImagePropertiesAnnotation @@ -493,8 +496,6 @@ def _assert_properties(self, image_property): self.assertNotEqual(color_info.score, 0.0) def test_detect_properties_content(self): - self._pb_not_implemented_skip( - 'gRPC not implemented for image properties detection.') client = Config.CLIENT with open(FACE_FILE, 'rb') as image_file: image = client.image(content=image_file.read()) @@ -504,8 +505,6 @@ def test_detect_properties_content(self): self._assert_properties(image_property) def test_detect_properties_gcs(self): - self._pb_not_implemented_skip( - 'gRPC not implemented for image properties detection.') client = Config.CLIENT bucket_name = Config.TEST_BUCKET.name blob_name = 'faces.jpg' @@ -523,8 +522,6 @@ def test_detect_properties_gcs(self): self._assert_properties(image_property) def test_detect_properties_filename(self): - self._pb_not_implemented_skip( - 'gRPC not implemented for image properties detection.') client = Config.CLIENT image = client.image(filename=FACE_FILE) properties = image.detect_properties() diff --git a/vision/google/cloud/vision/annotations.py b/vision/google/cloud/vision/annotations.py index bb26d413751a1..d93352ed6c7f4 100644 --- a/vision/google/cloud/vision/annotations.py +++ b/vision/google/cloud/vision/annotations.py @@ -123,12 +123,14 @@ def _process_image_annotations(image): 'labels': _make_entity_from_pb(image.label_annotations), 'landmarks': _make_entity_from_pb(image.landmark_annotations), 'logos': _make_entity_from_pb(image.logo_annotations), + 'properties': _make_image_properties_from_pb( + image.image_properties_annotation), 'texts': _make_entity_from_pb(image.text_annotations), } def _make_entity_from_pb(annotations): - """Create an entity from a gRPC response. + """Create an entity from a protobuf response. :type annotations: :class:`~google.cloud.grpc.vision.v1.image_annotator_pb2.EntityAnnotation` @@ -141,7 +143,7 @@ def _make_entity_from_pb(annotations): def _make_faces_from_pb(faces): - """Create face objects from a gRPC response. + """Create face objects from a protobuf response. :type faces: :class:`~google.cloud.grpc.vision.v1.image_annotator_pb2.FaceAnnotation` @@ -153,6 +155,20 @@ def _make_faces_from_pb(faces): return [Face.from_pb(face) for face in faces] +def _make_image_properties_from_pb(image_properties): + """Create ``ImageProperties`` object from a protobuf response. + + :type image_properties: :class:`~google.cloud.grpc.vision.v1.\ + image_annotator_pb2.ImagePropertiesAnnotation` + :param image_properties: Protobuf instance of + ``ImagePropertiesAnnotation``. + + :rtype: list + :returns: List of ``ImageProperties``. + """ + return ImagePropertiesAnnotation.from_pb(image_properties) + + def _entity_from_response_type(feature_type, results): """Convert a JSON result to an entity type based on the feature. diff --git a/vision/google/cloud/vision/color.py b/vision/google/cloud/vision/color.py index 7c6aa4a74e4e8..2d060977ff51c 100644 --- a/vision/google/cloud/vision/color.py +++ b/vision/google/cloud/vision/color.py @@ -26,20 +26,38 @@ def __init__(self, colors): self._colors = colors @classmethod - def from_api_repr(cls, response): + def from_api_repr(cls, image_properties): """Factory: construct ``ImagePropertiesAnnotation`` from a response. - :type response: dict - :param response: Dictionary response from Vision API with image - properties data. + :type image_properties: dict + :param image_properties: Dictionary response from Vision API with image + properties data. - :rtype: :class:`~google.cloud.vision.color.ImagePropertiesAnnotation`. - :returns: Populated instance of ``ImagePropertiesAnnotation``. + :rtype: list of + :class:`~google.cloud.vision.color.ImagePropertiesAnnotation`. + :returns: List of ``ImagePropertiesAnnotation``. """ - raw_colors = response.get('dominantColors', {}).get('colors', ()) - colors = [ColorInformation.from_api_repr(color) - for color in raw_colors] - return cls(colors) + colors = image_properties.get('dominantColors', {}).get('colors', ()) + return cls([ColorInformation.from_api_repr(color) + for color in colors]) + + @classmethod + def from_pb(cls, image_properties): + """Factory: construct ``ImagePropertiesAnnotation`` from a response. + + :type image_properties: :class:`~google.cloud.grpc.vision.v1.\ + image_annotator_pb2.ImageProperties` + :param image_properties: Protobuf response from Vision API with image + properties data. + + :rtype: list of + :class:`~google.cloud.vision.color.ImagePropertiesAnnotation` + :returns: List of ``ImagePropertiesAnnotation``. + """ + colors = getattr(image_properties.dominant_colors, 'colors', ()) + if len(colors) == 0: + return () + return [cls([ColorInformation.from_pb(color) for color in colors])] @property def colors(self): @@ -93,6 +111,22 @@ def from_api_repr(cls, response): return cls(red, green, blue, alpha) + @classmethod + def from_pb(cls, color): + """Factory: construct a ``Color`` from a protobuf response. + + :type color: :class:`~google.type.color_pb2` + :param color: ``Color`` from API Response. + + :rtype: :class:`~google.cloud.vision.color.Color` + :returns: Instance of :class:`~google.cloud.vision.color.Color`. + """ + red = getattr(color, 'red', 0.0) + green = getattr(color, 'green', 0.0) + blue = getattr(color, 'blue', 0.0) + alpha = getattr(color.alpha, 'value', 0.0) + return cls(red, green, blue, alpha) + @property def red(self): """Red component of the color. @@ -149,19 +183,34 @@ def __init__(self, color, score, pixel_fraction): self._pixel_fraction = pixel_fraction @classmethod - def from_api_repr(cls, response): - """Factory: construct ``ColorInformation`` for a color found. + def from_api_repr(cls, color_information): + """Factory: construct ``ColorInformation`` for a color. - :type response: dict - :param response: Color data with extra meta information. + :type color_information: dict + :param color_information: Color data with extra meta information. :rtype: :class:`~google.cloud.vision.color.ColorInformation` :returns: Instance of ``ColorInformation``. """ - color = Color.from_api_repr(response.get('color')) - score = response.get('score') - pixel_fraction = response.get('pixelFraction') + color = Color.from_api_repr(color_information.get('color')) + score = color_information.get('score') + pixel_fraction = color_information.get('pixelFraction') + return cls(color, score, pixel_fraction) + @classmethod + def from_pb(cls, color_information): + """Factory: construct ``ColorInformation`` for a color. + + :type color_information: :class:`~google.cloud.grpc.vision.v1.\ + image_annotator_pb2.ColorInfo` + :param color_information: Color data with extra meta information. + + :rtype: :class:`~google.cloud.vision.color.ColorInformation` + :returns: Instance of ``ColorInformation``. + """ + color = Color.from_pb(color_information.color) + score = color_information.score + pixel_fraction = color_information.pixel_fraction return cls(color, score, pixel_fraction) @property diff --git a/vision/unit_tests/test_color.py b/vision/unit_tests/test_color.py index eec7ceefb778e..73716148e54b4 100644 --- a/vision/unit_tests/test_color.py +++ b/vision/unit_tests/test_color.py @@ -36,6 +36,32 @@ def test_rgb_color_data(self): self.assertEqual(colors.blue, 255) self.assertEqual(colors.alpha, 0.5) + def test_pb_rgb_color_data(self): + from google.protobuf.wrappers_pb2 import FloatValue + from google.type.color_pb2 import Color + + alpha = FloatValue(value=1.0) + color_pb = Color(red=1.0, green=2.0, blue=3.0, alpha=alpha) + color_class = self._get_target_class() + color = color_class.from_pb(color_pb) + self.assertEqual(color.red, 1.0) + self.assertEqual(color.green, 2.0) + self.assertEqual(color.blue, 3.0) + self.assertEqual(color.alpha, 1.0) + + def test_pb_rgb_color_no_alpha_data(self): + from google.protobuf.wrappers_pb2 import FloatValue + from google.type.color_pb2 import Color + + alpha = FloatValue() + color_pb = Color(red=1.0, green=2.0, blue=3.0, alpha=alpha) + color_class = self._get_target_class() + color = color_class.from_pb(color_pb) + self.assertEqual(color.red, 1.0) + self.assertEqual(color.green, 2.0) + self.assertEqual(color.blue, 3.0) + self.assertEqual(color.alpha, 0.0) + def test_missing_rgb_values(self): colors = {} color_class = self._get_target_class() @@ -45,3 +71,38 @@ def test_missing_rgb_values(self): self.assertEqual(colors.green, 0) self.assertEqual(colors.blue, 0) self.assertEqual(colors.alpha, 0.0) + + +class TestImagePropertiesAnnotation(unittest.TestCase): + @staticmethod + def _get_target_class(): + from google.cloud.vision.color import ImagePropertiesAnnotation + return ImagePropertiesAnnotation + + def test_color_annotation_from_pb(self): + from google.cloud.grpc.vision.v1 import image_annotator_pb2 + from google.protobuf.wrappers_pb2 import FloatValue + from google.type.color_pb2 import Color + + alpha = FloatValue(value=1.0) + color_pb = Color(red=1.0, green=2.0, blue=3.0, alpha=alpha) + color_info_pb = image_annotator_pb2.ColorInfo(color=color_pb, + score=1.0, + pixel_fraction=1.0) + dominant_colors = image_annotator_pb2.DominantColorsAnnotation( + colors=[color_info_pb]) + + image_properties_pb = image_annotator_pb2.ImageProperties( + dominant_colors=dominant_colors) + + color_info = self._get_target_class() + image_properties_result = color_info.from_pb(image_properties_pb) + + self.assertEqual(len(image_properties_result), 1) + image_properties = image_properties_result[0] + self.assertEqual(image_properties.colors[0].pixel_fraction, 1.0) + self.assertEqual(image_properties.colors[0].score, 1.0) + self.assertEqual(image_properties.colors[0].color.red, 1.0) + self.assertEqual(image_properties.colors[0].color.green, 2.0) + self.assertEqual(image_properties.colors[0].color.blue, 3.0) + self.assertEqual(image_properties.colors[0].color.alpha, 1.0)