Skip to content

Commit

Permalink
Add loading image from filename.
Browse files Browse the repository at this point in the history
  • Loading branch information
daspecster committed Dec 1, 2016
1 parent 5cbbcb9 commit 0bc1c4b
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 24 deletions.
68 changes: 57 additions & 11 deletions docs/vision-usage.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
####################
Using the Vision API
====================
####################


********************************
Authentication and Configuration
--------------------------------
********************************

- For an overview of authentication in ``google-cloud-python``,
see :doc:`google-cloud-auth`.
Expand Down Expand Up @@ -31,8 +34,43 @@ or pass in ``credentials`` and ``project`` explicitly.
>>> client = vision.Client(project='my-project', credentials=creds)
*****************************************************
Creating an :class:`~google.cloud.vision.image.Image`
*****************************************************

The :class:`~google.cloud.vision.image.Image` class is used to load image
data from sources such as a Google Cloud Storage URI, raw bytes, or a file.


From a Google Cloud Storage URI
===============================

.. code-block:: python
>>> from google.cloud import vision
>>> client = vision.Client()
>>> image = client.image(source_uri='gs://my-test-bucket/image.jpg')
From a filename
===============

.. code-block:: python
>>> image = client.image(filename='image.jpg')
From raw bytes
==============

.. code-block:: python
>>> with open('./image.jpg', 'rb') as image_file:
... bytes_image = client.image(content=image_file.read())
****************
Manual Detection
~~~~~~~~~~~~~~~~
****************

You can call the detection method manually.

Expand Down Expand Up @@ -60,8 +98,9 @@ You can call the detection method manually.
'github'
**************
Face Detection
~~~~~~~~~~~~~~
**************

:meth:`~google.cloud.vision.image.Image.detect_faces` will search for faces in
an image and return the coordinates in the image of each `landmark type`_ that
Expand All @@ -87,8 +126,9 @@ was detected.
0.02545464
***************
Label Detection
~~~~~~~~~~~~~~~
***************

:meth:`~google.cloud.vision.image.Image.detect_labels` will attempt to label
objects in an image. If there is a car, person and a dog in the image, label
Expand All @@ -107,8 +147,9 @@ certainty from ``0.0 to 1.0``.
0.9863683
******************
Landmark Detection
~~~~~~~~~~~~~~~~~~
******************

:meth:`~google.cloud.vision.image.Image.detect_landmarks` will attempt to
detect landmarks such as "Mount Rushmore" and the "Sydney Opera House". The API
Expand All @@ -133,8 +174,9 @@ will also provide their known geographical locations if available.
162
**************
Logo Detection
~~~~~~~~~~~~~~
**************

With :meth:`~google.cloud.vision.image.Image.detect_logos`, you can identify
brand logos in an image. Their shape and location in the image can be found by
Expand Down Expand Up @@ -162,8 +204,9 @@ iterating through the detected logo's ``vertices``.
62
*********************
Safe Search Detection
~~~~~~~~~~~~~~~~~~~~~
*********************

:meth:`~google.cloud.vision.image.Image.detect_safe_search` will try to
categorize the entire contents of the image under four categories.
Expand Down Expand Up @@ -192,8 +235,9 @@ categorize the entire contents of the image under four categories.
'LIKELY'
**************
Text Detection
~~~~~~~~~~~~~~
**************

:meth:`~google.cloud.vision.image.Image.detect_text` performs OCR to find text
in an image.
Expand All @@ -213,8 +257,9 @@ in an image.
'some other text in the image'
****************
Image Properties
~~~~~~~~~~~~~~~~
****************

:meth:`~google.cloud.vision.image.Image.detect_properties` will process the
image and determine the dominant colors in the image.
Expand All @@ -238,8 +283,9 @@ image and determine the dominant colors in the image.
0.758658
****************
No results found
~~~~~~~~~~~~~~~~
****************

If no results for the detection performed can be extracted from the image, then
an empty list is returned. This behavior is similiar with all detection types.
Expand Down
27 changes: 20 additions & 7 deletions vision/google/cloud/vision/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,35 @@ class Image(object):
:type content: bytes
:param content: Byte stream of an image.
:type filename: str
:param filename: Filename to image.
:type source_uri: str
:param source_uri: Google Cloud Storage URI of image.
:type client: :class:`~google.cloud.vision.client.Client`
:param client: Instance of Vision client.
"""

def __init__(self, client, content=None, source_uri=None):
def __init__(self, client, content=None, filename=None, source_uri=None):
sources = [source for source in (content, filename, source_uri)
if source is not None]
if len(sources) != 1:
raise ValueError(
'Specify exactly one of "content", "filename", or '
'"source_uri".')

self.client = client
self._content = None
self._source = None

if source_uri:
self._source = source_uri
else:
self._content = _bytes_to_unicode(b64encode(_to_bytes(content)))
if filename is not None:
with open(filename, 'rb') as file_obj:
content = file_obj.read()

if content is not None:
content = _bytes_to_unicode(b64encode(_to_bytes(content)))

self._content = content
self._source = source_uri

def as_dict(self):
"""Generate dictionary structure for request.
Expand Down
1 change: 1 addition & 0 deletions vision/tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ localdeps =
pip install --quiet --upgrade {toxinidir}/../core
deps =
{toxinidir}/../core
mock
pytest
covercmd =
py.test --quiet \
Expand Down
42 changes: 36 additions & 6 deletions vision/unit_tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,44 @@ def _get_target_class():
def _make_one(self, *args, **kw):
return self._get_target_class()(*args, **kw)

def test_must_set_one_source(self):
with self.assertRaises(ValueError):
self._make_one(CLIENT_MOCK)

with self.assertRaises(ValueError):
self._make_one(CLIENT_MOCK, content=IMAGE_CONTENT,
source_uri=IMAGE_SOURCE)

with self.assertRaises(ValueError):
self._make_one(CLIENT_MOCK, content=IMAGE_CONTENT,
source_uri=IMAGE_SOURCE, filename='myimage.jpg')

image = self._make_one(CLIENT_MOCK, content=IMAGE_CONTENT)
self.assertEqual(image.content, B64_IMAGE_CONTENT)

def test_image_source_type_content(self):
image = self._make_one(CLIENT_MOCK, content=IMAGE_CONTENT)

_AS_DICT = {
'content': B64_IMAGE_CONTENT
as_dict = {
'content': B64_IMAGE_CONTENT,
}

self.assertEqual(B64_IMAGE_CONTENT, image.content)
self.assertEqual(None, image.source)
self.assertEqual(_AS_DICT, image.as_dict())
self.assertEqual(image.as_dict(), as_dict)

def test_image_source_type_google_cloud_storage(self):
image = self._make_one(CLIENT_MOCK, source_uri=IMAGE_SOURCE)

_AS_DICT = {
as_dict = {
'source': {
'gcs_image_uri': IMAGE_SOURCE
'gcs_image_uri': IMAGE_SOURCE,
}
}

self.assertEqual(IMAGE_SOURCE, image.source)
self.assertEqual(None, image.content)
self.assertEqual(_AS_DICT, image.as_dict())
self.assertEqual(image.as_dict(), as_dict)

def test_cannot_set_both_source_and_content(self):
image = self._make_one(CLIENT_MOCK, content=IMAGE_CONTENT)
Expand All @@ -68,3 +83,18 @@ def test_cannot_set_both_source_and_content(self):
self.assertEqual(IMAGE_SOURCE, image.source)
with self.assertRaises(AttributeError):
image.content = IMAGE_CONTENT

def test_image_from_filename(self):
from mock import mock_open
from mock import patch

as_dict = {
'content': B64_IMAGE_CONTENT,
}

with patch('google.cloud.vision.image.open',
mock_open(read_data=IMAGE_CONTENT)) as m:
image = self._make_one(CLIENT_MOCK, filename='my-image-file.jpg')
m.assert_called_once_with('my-image-file.jpg', 'rb')
self.assertEqual(image.content, B64_IMAGE_CONTENT)
self.assertEqual(image.as_dict(), as_dict)

0 comments on commit 0bc1c4b

Please sign in to comment.