Skip to content

Commit

Permalink
Vision 1.1 API Client (#3069)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukesneeringer authored Feb 25, 2017
1 parent a3596d6 commit f4cb0ee
Show file tree
Hide file tree
Showing 27 changed files with 1,740 additions and 32 deletions.
3 changes: 3 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,14 @@
vision-batch
vision-client
vision-color
vision-crop-hint
vision-entity
vision-feature
vision-face
vision-image
vision-safe-search
vision-text
vision-web

.. toctree::
:maxdepth: 0
Expand Down
10 changes: 10 additions & 0 deletions docs/vision-crop-hint.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Vision Crop Hint
================

Crop Hint
~~~~~~~~~

.. automodule:: google.cloud.vision.crop_hint
:members:
:undoc-members:
:show-inheritance:
10 changes: 10 additions & 0 deletions docs/vision-text.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Vision Full Text
================

Full Text Annotation
~~~~~~~~~~~~~~~~~~~~

.. automodule:: google.cloud.vision.text
:members:
:undoc-members:
:show-inheritance:
61 changes: 61 additions & 0 deletions docs/vision-usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,30 @@ You can call the detection method manually.
'github'
**********
Crop Hints
**********

:meth:`~google.cloud.vision.image.Image.detect_crop_hints` will attempt to find
boundaries that contain interesting data which can be used to crop an image.

.. code-block:: python
>>> from google.cloud import vision
>>> client = vision.Client()
>>> image = client.image(source_uri='gs://my-test-bucket/image.jpg')
>>> crop_hints = image.detect_crop_hints(aspect_ratios=[1.3333], limit=2)
>>> first_hint = crop_hints[0]
>>> first_hint.bounds.vertices[0].x_coordinate
77
>>> first_hint.bounds.vertices[0].y_coordinate
102
>>> first_hint.confidence
0.5
>>> first_hint.importance_fraction
1.22000002861
**************
Face Detection
**************
Expand Down Expand Up @@ -317,6 +341,43 @@ Multiple images can be processed with a single request by passing
<Likelihood.VERY_LIKELY: 'POSSIBLE'>
*************
Web Detection
*************

:meth:`~google.cloud.vision.image.Image.detect_web` search for images on the
web that are similar to the image you have.

.. code-block:: python
>>> from google.cloud import vision
>>> client = vision.Client()
>>> with open('./image.jpg', 'rb') as image_file:
... image = client.image(content=image_file.read())
>>> web_images = image.detect_web(limit=2)
>>> for full_matching_image in web_images.full_matching_images:
... print('=' * 20)
... print(full_matching_image.url)
====================
'https://example.com/image.jpg'
>>> for partial_matching_image in web_images.partial_matching_images:
... print('=' * 20)
... print(partial_matching_image.url)
====================
>>> for page_with_matching_images in web_images.pages_with_matching_images:
... print('=' * 20)
... print(page_with_matching_images.url)
====================
'https://example.com/portfolio/'
>>> for entity in web_images.web_entities:
... print('=' * 20)
... print(entity.description)
====================
'Mount Rushmore National Memorial'
====================
'Landmark'
****************
No results found
****************
Expand Down
10 changes: 10 additions & 0 deletions docs/vision-web.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Vision Web Annotations
======================

Web Annotations
~~~~~~~~~~~~~~~

.. automodule:: google.cloud.vision.web
:members:
:undoc-members:
:show-inheritance:
2 changes: 1 addition & 1 deletion logging/google/cloud/logging/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def log_text(self, text, client=None, labels=None, insert_id=None,
See:
https://cloud.google.com/logging/docs/api/reference/rest/v2/entries/write
:type text: text
:type text: str
:param text: the log message.
:type client: :class:`~google.cloud.logging.client.Client` or
Expand Down
2 changes: 1 addition & 1 deletion storage/google/cloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ def upload_from_string(self, data, content_type='text/plain', client=None):
`lifecycle <https://cloud.google.com/storage/docs/lifecycle>`_
API documents for details.
:type data: bytes or text
:type data: bytes or str
:param data: The data to store in this blob. If the value is
text, it will be encoded as UTF-8.
Expand Down
Binary file added system_tests/data/full-text.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
181 changes: 181 additions & 0 deletions system_tests/vision.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
LABEL_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'car.jpg')
LANDMARK_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'landmark.jpg')
TEXT_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'text.jpg')
FULL_TEXT_FILE = os.path.join(_SYS_TESTS_DIR, 'data', 'full-text.jpg')


class Config(object):
Expand Down Expand Up @@ -80,6 +81,107 @@ def _pb_not_implemented_skip(self, message):
self.skipTest(message)


class TestVisionFullText(unittest.TestCase):
def setUp(self):
self.to_delete_by_case = []

def tearDown(self):
for value in self.to_delete_by_case:
value.delete()

def _assert_full_text(self, full_text):
from google.cloud.vision.text import TextAnnotation

self.assertIsInstance(full_text, TextAnnotation)
self.assertIsInstance(full_text.text, six.text_type)
self.assertEqual(len(full_text.pages), 1)
self.assertIsInstance(full_text.pages[0].width, int)
self.assertIsInstance(full_text.pages[0].height, int)

def test_detect_full_text_content(self):
client = Config.CLIENT
with open(FULL_TEXT_FILE, 'rb') as image_file:
image = client.image(content=image_file.read())
full_text = image.detect_full_text()
self._assert_full_text(full_text)

def test_detect_full_text_filename(self):
client = Config.CLIENT
image = client.image(filename=FULL_TEXT_FILE)
full_text = image.detect_full_text()
self._assert_full_text(full_text)

def test_detect_full_text_gcs(self):
bucket_name = Config.TEST_BUCKET.name
blob_name = 'full-text.jpg'
blob = Config.TEST_BUCKET.blob(blob_name)
self.to_delete_by_case.append(blob) # Clean-up.
with open(FULL_TEXT_FILE, 'rb') as file_obj:
blob.upload_from_file(file_obj)

source_uri = 'gs://%s/%s' % (bucket_name, blob_name)

client = Config.CLIENT
image = client.image(source_uri=source_uri)
full_text = image.detect_full_text()
self._assert_full_text(full_text)


class TestVisionClientCropHint(BaseVisionTestCase):
def setUp(self):
self.to_delete_by_case = []

def tearDown(self):
for value in self.to_delete_by_case:
value.delete()

def _assert_crop_hint(self, hint):
from google.cloud.vision.crop_hint import CropHint
from google.cloud.vision.geometry import Bounds

self.assertIsInstance(hint, CropHint)
self.assertIsInstance(hint.bounds, Bounds)
self.assertGreater(hint.bounds.vertices, 1)
self.assertIsInstance(hint.confidence, (int, float))
self.assertIsInstance(hint.importance_fraction, float)

def test_detect_crop_hints_content(self):
client = Config.CLIENT
with open(FACE_FILE, 'rb') as image_file:
image = client.image(content=image_file.read())
crop_hints = image.detect_crop_hints(
aspect_ratios=[1.3333, 1.7777], limit=2)
self.assertEqual(len(crop_hints), 2)
for hint in crop_hints:
self._assert_crop_hint(hint)

def test_detect_crop_hints_filename(self):
client = Config.CLIENT
image = client.image(filename=FACE_FILE)
crop_hints = image.detect_crop_hints(
aspect_ratios=[1.3333, 1.7777], limit=2)
self.assertEqual(len(crop_hints), 2)
for hint in crop_hints:
self._assert_crop_hint(hint)

def test_detect_crop_hints_gcs(self):
bucket_name = Config.TEST_BUCKET.name
blob_name = 'faces.jpg'
blob = Config.TEST_BUCKET.blob(blob_name)
self.to_delete_by_case.append(blob) # Clean-up.
with open(FACE_FILE, 'rb') as file_obj:
blob.upload_from_file(file_obj)

source_uri = 'gs://%s/%s' % (bucket_name, blob_name)
client = Config.CLIENT
image = client.image(source_uri=source_uri)
crop_hints = image.detect_crop_hints(
aspect_ratios=[1.3333, 1.7777], limit=2)
self.assertEqual(len(crop_hints), 2)
for hint in crop_hints:
self._assert_crop_hint(hint)


class TestVisionClientLogo(unittest.TestCase):
def setUp(self):
self.to_delete_by_case = []
Expand Down Expand Up @@ -559,3 +661,82 @@ def test_batch_detect_gcs(self):

self.assertEqual(len(results[1].logos), 0)
self.assertEqual(len(results[1].faces), 2)


class TestVisionWebAnnotation(BaseVisionTestCase):
def setUp(self):
self.to_delete_by_case = []

def tearDown(self):
for value in self.to_delete_by_case:
value.delete()

def _assert_web_entity(self, web_entity):
from google.cloud.vision.web import WebEntity

self.assertIsInstance(web_entity, WebEntity)
self.assertIsInstance(web_entity.entity_id, six.text_type)
self.assertIsInstance(web_entity.score, float)
self.assertIsInstance(web_entity.description, six.text_type)

def _assert_web_image(self, web_image):
from google.cloud.vision.web import WebImage

self.assertIsInstance(web_image, WebImage)
self.assertIsInstance(web_image.url, six.text_type)
self.assertIsInstance(web_image.score, float)

def _assert_web_page(self, web_page):
from google.cloud.vision.web import WebPage

self.assertIsInstance(web_page, WebPage)
self.assertIsInstance(web_page.url, six.text_type)
self.assertIsInstance(web_page.score, float)

def _assert_web_images(self, web_images, limit):
self.assertEqual(len(web_images.web_entities), limit)
for web_entity in web_images.web_entities:
self._assert_web_entity(web_entity)

self.assertEqual(len(web_images.full_matching_images), limit)
for web_image in web_images.full_matching_images:
self._assert_web_image(web_image)

self.assertEqual(len(web_images.partial_matching_images), limit)
for web_image in web_images.partial_matching_images:
self._assert_web_image(web_image)

self.assertEqual(len(web_images.pages_with_matching_images), limit)
for web_page in web_images.pages_with_matching_images:
self._assert_web_page(web_page)

def test_detect_web_images_from_content(self):
client = Config.CLIENT
with open(LANDMARK_FILE, 'rb') as image_file:
image = client.image(content=image_file.read())
limit = 5
web_images = image.detect_web(limit=limit)
self._assert_web_images(web_images, limit)

def test_detect_web_images_from_gcs(self):
client = Config.CLIENT
bucket_name = Config.TEST_BUCKET.name
blob_name = 'landmark.jpg'
blob = Config.TEST_BUCKET.blob(blob_name)
self.to_delete_by_case.append(blob) # Clean-up.
with open(LANDMARK_FILE, 'rb') as file_obj:
blob.upload_from_file(file_obj)

source_uri = 'gs://%s/%s' % (bucket_name, blob_name)

image = client.image(source_uri=source_uri)
limit = 5
web_images = image.detect_web(limit=limit)
self._assert_web_images(web_images, limit)

def test_detect_web_images_from_filename(self):
client = Config.CLIENT
image = client.image(filename=LANDMARK_FILE)
limit = 5
web_images = image.detect_web(limit=limit)
self._assert_web_images(web_images, limit)
Loading

0 comments on commit f4cb0ee

Please sign in to comment.