10000 Add GAPIC support for image properties detection. · googleapis/google-cloud-python@21cda07 · GitHub
[go: up one dir, main page]

Skip to content

Commit 21cda07

Browse files
committed
Add GAPIC support for image properties detection.
1 parent 01474cc commit 21cda07

File tree

5 files changed

+153
-30
lines changed

5 files changed

+153
-30
lines changed

system_tests/vision.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,16 @@ def tearDown(self):
478478
value.delete()
479479

480480
def _assert_color(self, color):
481-
self.assertIsInstance(color.red, int)
482-
self.assertIsInstance(color.green, int)
483-
self.assertIsInstance(color.blue, int)
481+
self.assertIsInstance(color.red, (int, float))
482+
self.assertIsInstance(color.green, (int, float))
483+
self.assertIsInstance(color.blue, (int, float))
484+
if not isinstance(color.alpha, float):
485+
self.assertIsInstance(color.alpha.value, float)
486+
else:
487+
self.assertIsInstance(color.alpha, float)
484488
self.assertNotEqual(color.red, 0.0)
485489
self.assertNotEqual(color.green, 0.0)
486490
self.assertNotEqual(color.blue, 0.0)
487-
self.assertIsInstance(color.alpha, float)
488491

489492
def _assert_properties(self, image_property):
490493
from google.cloud.vision.color import ImagePropertiesAnnotation
@@ -497,8 +500,6 @@ def _assert_properties(self, image_property):
497500
self.assertNotEqual(color_info.score, 0.0)
498501

499502
def test_detect_properties_content(self):
500-
self._pb_not_implemented_skip(
501-
'gRPC not implemented for image properties detection.')
502503
client = Config.CLIENT
503504
with open(FACE_FILE, 'rb') as image_file:
504505
image = client.image(content=image_file.read())
@@ -508,8 +509,6 @@ def test_detect_properties_content(self):
508509
self._assert_properties(image_property)
509510

510511
def test_detect_properties_gcs(self):
511-
self._pb_not_implemented_skip(
512-
'gRPC not implemented for image properties detection.')
513512
client = Config.CLIENT
514513
bucket_name = Config.TEST_BUCKET.name
515514
blob_name = 'faces.jpg'
@@ -527,8 +526,6 @@ def test_detect_properties_gcs(self):
527526
self._assert_properties(image_property)
528527

529528
def test_detect_properties_filename(self):
530-
self._pb_not_implemented_skip(
531-
'gRPC not implemented for image properties detection.')
532529
client = Config.CLIENT
533530
image = client.image(filename=FACE_FILE)
534531
properties = image.detect_properties()

vision/google/cloud/vision/annotations.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,14 @@ def _process_image_annotations(image):
123123
'labels': _make_entity_from_pb(image.label_annotations),
124124
'landmarks': _make_entity_from_pb(image.landmark_annotations),
125125
'logos': _make_entity_from_pb(image.logo_annotations),
126+
'properties': _make_image_properties_from_pb(
127+
image.image_properties_annotation),
126128
'texts': _make_entity_from_pb(image.text_annotations),
127129
}
128130

129131

130132
def _make_entity_from_pb(annotations):
131-
"""Create an entity from a gRPC response.
133+
"""Create an entity from a protobuf response.
132134
133135
:type annotations:
134136
:class:`~google.cloud.grpc.vision.v1.image_annotator_pb2.EntityAnnotation`
@@ -141,7 +143,7 @@ def _make_entity_from_pb(annotations):
141143

142144

143145
def _make_faces_from_pb(faces):
144-
"""Create face objects from a gRPC response.
146+
"""Create face objects from a protobuf response.
145147
146148
:type faces:
147149
:class:`~google.cloud.grpc.vision.v1.image_annotator_pb2.FaceAnnotation`
@@ -153,6 +155,20 @@ def _make_faces_from_pb(faces):
153155
return [Face.from_pb(face) for face in faces]
154156

155157

158+
def _make_image_properties_from_pb(image_properties):
159+
"""Create ``ImageProperties`` object from a protobuf response.
160+
161+
:type image_properties: :class:`~google.cloud.grpc.vision.v1.\
162+
image_annotator_pb2.ImagePropertiesAnnotation`
163+
:param image_properties: Protobuf instance of
164+
``ImagePropertiesAnnotation``.
165+
166+
:rtype: list
167+
:returns: List of ``ImageProperties``.
168+
"""
169+
return ImagePropertiesAnnotation.from_pb(image_properties)
170+
171+
156172
def _entity_from_response_type(feature_type, results):
157173
"""Convert a JSON result to an entity type based on the feature.
158174

vision/google/cloud/vision/color.py

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,38 @@ def __init__(self, colors):
2626
self._colors = colors
2727

2828
@classmethod
29-
def from_api_repr(cls, response):
29+
def from_api_repr(cls, image_properties):
3030
"""Factory: construct ``ImagePropertiesAnnotation`` from a response.
3131
32-
:type response: dict
33-
:param response: Dictionary response from Vision API with image
34-
properties data.
32+
:type image_properties: dict
33+
:param image_properties: Dictionary response from Vision API with image
34+
properties data.
3535
36-
:rtype: :class:`~google.cloud.vision.color.ImagePropertiesAnnotation`.
37-
:returns: Populated instance of ``ImagePropertiesAnnotation``.
36+
:rtype: list of
37+
:class:`~google.cloud.vision.color.ImagePropertiesAnnotation`.
38+
:returns: List of ``ImagePropertiesAnnotation``.
3839
"""
39-
raw_colors = response.get('dominantColors', {}).get('colors', ())
40-
colors = [ColorInformation.from_api_repr(color)
41-
for color in raw_colors]
42-
return cls(colors)
40+
colors = image_properties.get('dominantColors', {}).get('colors', ())
41+
return cls([ColorInformation.from_api_repr(color)
42+
for color in colors])
43+
44+
@classmethod
45+
def from_pb(cls, image_properties):
46+
"""Factory: construct ``ImagePropertiesAnnotation`` from a response.
47+
48+
:type image_properties: :class:`~google.cloud.grpc.vision.v1.\
49+
image_annotator_pb2.ImageProperties`
50+
:param image_properties: Protobuf response from Vision API with image
51+
properties data.
52+
53+
:rtype: list of
54+
:class:`~google.cloud.vision.color.ImagePropertiesAnnotation`
55+
:returns: List of ``ImagePropertiesAnnotation``.
56+
"""
57+
colors = getattr(image_properties.dominant_colors, 'colors', [])
58+
if len(colors) == 0:
59+
return []
60+
return [cls([ColorInformation.from_pb(color) for color in colors])]
4361

4462
@property
4563
def colors(self):
@@ -93,6 +111,22 @@ def from_api_repr(cls, response):
93111

94112
return cls(red, green, blue, alpha)
95113

114+
@classmethod
115+
def from_pb(cls, color):
116+
"""Factory: construct a ``Color`` from a protobuf response.
117+
118+
:type color: :class:`~google.type.color_pb2`
119+
:param color: ``Color`` from API Response.
120+
121+
:rtype: :class:`~google.cloud.vision.color.Color`
122+
:returns: Instance of :class:`~google.cloud.vision.color.Color`.
123+
"""
124+
red = getattr(color, 'red', 0.0)
125+
green = getattr(color, 'green', 0.0)
126+
blue = getattr(color, 'blue', 0.0)
127+
alpha = getattr(color.alpha, 'value', 0.0)
128+
return cls(red, green, blue, alpha)
129+
96130
@property
97131
def red(self):
98132
"""Red component of the color.
@@ -149,19 +183,34 @@ def __init__(self, color, score, pixel_fraction):
149183
self._pixel_fraction = pixel_fraction
150184

151185
@classmethod
152-
def from_api_repr(cls, response):
153-
"""Factory: construct ``ColorInformation`` for a color found.
186+
def from_api_repr(cls, color_information):
187+
"""Factory: construct ``ColorInformation`` for a color.
154188
155-
:type response: dict
156-
:param response: Color data with extra meta information.
189+
:type color_information: dict
190+
:param color_information: Color data with extra meta information.
157191
158192
:rtype: :class:`~google.cloud.vision.color.ColorInformation`
159193
:returns: Instance of ``ColorInformation``.
160194
"""
161-
color = Color.from_api_repr(response.get('color'))
162-
score = response.get('score')
163-
pixel_fraction = response.get('pixelFraction')
195+
color = Color.from_api_repr(color_information.get('color'))
196+
score = color_information.get('score')
197+
pixel_fraction = color_information.get('pixelFraction')
198+
return cls(color, score, pixel_fraction)
164199

200+
@classmethod
201+
def from_pb(cls, color_information):
202+
"""Factory: construct ``ColorInformation`` for a color.
203+
204+
:type color_information: :class:`~google.cloud.grpc.vision.v1.\
205+
image_annotator_pb2.ColorInfo`
206+
:param color_information: Color data with extra meta information.
207+
208+
:rtype: :class:`~google.cloud.vision.color.ColorInformation`
209+
:returns: Instance of ``ColorInformation``.
210+
"""
211+
color = Color.from_pb(color_information.color)
212+
score = color_information.score
213+
pixel_fraction = color_information.pixel_fraction
165214
return cls(color, score, pixel_fraction)
166215

167216
@property

vision/unit_tests/test_annotations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def test_from_pb(self):
7777
self.assertEqual(annotations.landmarks, [])
7878
self.assertEqual(annotations.texts, [])
7979
self.assertEqual(annotations.safe_searches, ())
80-
self.assertEqual(annotations.properties, ())
80+
self.assertEqual(annotations.properties, [])
8181

8282

8383
class Test__make_entity_from_pb(unittest.TestCase):

vision/unit_tests/test_color.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,32 @@ def test_rgb_color_data(self):
3636
self.assertEqual(colors.blue, 255)
3737
self.assertEqual(colors.alpha, 0.5)
3838

39+
def test_pb_rgb_color_data(self):
40+
from google.protobuf.wrappers_pb2 import FloatValue
41+
from google.type.color_pb2 import Color
42+
43+
alpha = FloatValue(value=1.0)
44+
color_pb = Color(red=1.0, green=2.0, blue=3.0, alpha=alpha)
45+
color_class = self._get_target_class()
46+
color = color_class.from_pb(color_pb)
47+
self.assertEqual(color.red, 1.0)
48+
self.assertEqual(color.green, 2.0)
49+
self.assertEqual(color.blue, 3.0)
50+
self.assertEqual(color.alpha, 1.0)
51+
52+
def test_pb_rgb_color_no_alpha_data(self):
53+
from google.protobuf.wrappers_pb2 import FloatValue
54+
from google.type.color_pb2 import Color
55+
56+
alpha = FloatValue()
57+
color_pb = Color(red=1.0, green=2.0, blue=3.0, alpha=alpha)
58+
color_class = self._get_target_class()
59+
color = color_class.from_pb(color_pb)
60+
self.assertEqual(color.red, 1.0)
61+
self.assertEqual(color.green, 2.0)
62+
self.assertEqual(color.blue, 3.0)
63+
self.assertEqual(color.alpha, 0.0)
64+
3965
def test_missing_rgb_values(self):
4066
colors = {}
4167
color_class = self._get_target_class()
@@ -45,3 +71,38 @@ def test_missing_rgb_values(self):
4571
self.assertEqual(colors.green, 0)
4672
self.assertEqual(colors.blue, 0)
4773
self.assertEqual(colors.alpha, 0.0)
74+
75+
76+
class TestImagePropertiesAnnotation(unittest.TestCase):
77+
@staticmethod
78+
def _get_target_class():
79+
from google.cloud.vision.color import ImagePropertiesAnnotation
80+
return ImagePropertiesAnnotation
81+
82+
def test_color_annotation_from_pb(self):
83+
from google.cloud.grpc.vision.v1 import image_annotator_pb2
84+
from google.protobuf.wrappers_pb2 import FloatValue
85+
from google.type.color_pb2 import Color
86+
87+
alpha = FloatValue(value=1.0)
88+
color_pb = Color(red=1.0, green=2.0, blue=3.0, alpha=alpha)
89+
color_info_pb = image_annotator_pb2.ColorInfo(color=color_pb,
90+
score=1.0,
91+
pixel_fraction=1.0)
92+
dominant_colors = image_annotator_pb2.DominantColorsAnnotation(
93+
colors=[color_info_pb])
94+
95+
image_properties_pb = image_annotator_pb2.ImageProperties(
96+
dominant_colors=dominant_colors)
97+
98+
color_info = self._get_target_class()
99+
image_properties_result = color_info.from_pb(image_properties_pb)
100+
101+
self.assertEqual(len(image_properties_result), 1)
102+
image_properties = image_properties_result[0]
103+
self.assertEqual(image_properties.colors[0].pixel_fraction, 1.0)
104+
self.assertEqual(image_properties.colors[0].score, 1.0)
105+
self.assertEqual(image_properties.colors[0].color.red, 1.0)
106+
self.assertEqual(image_properties.colors[0].color.green, 2.0)
107+
self.assertEqual(image_properties.colors[0].color.blue, 3.0)
108+
self.assertEqual(image_properties.colors[0].color.alpha, 1.0)

0 commit comments

Comments
 (0)
0