diff --git a/CHANGES.txt b/CHANGES.txt index 65fe504..58f2cbc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -8,3 +8,4 @@ v0.3.3, Fri Aug 1 -- Added language detection api v0.4.0, Fri Aug 1 -- Changed api import to lowercase, added language example v0.4.1, Fri Aug 1 -- Updated __version__ variable to be accurate v0.4.2, Wed Aug 6 -- Updated README to accurately reflect political analysis results +v0.4.3, Thu Sep 11 -- Added image features api and sphinx compliant documentation diff --git a/README b/README index 1efd8d6..de1bd75 100644 --- a/README +++ b/README @@ -1,12 +1,16 @@ indicoio-python =============== -A wrapper for a series of APIs made by Indico Data Solutions. +A wrapper for a series of APIs made by indico. Check out the main site on: http://indico.io +Check out our documentation on: + +http://indicoiopython.s3-website-us-west-2.amazonaws.com/indicoio.html + Our APIs are totally free to use, and ready to be used in your application. No data or training required. Current APIs @@ -14,8 +18,9 @@ Current APIs Right now this wrapper supports the following apps: -- Political Sentiment Analysis - Positive/Negative Sentiment Analysis +- Political Sentiment Analysis +- Image Feature Extraction - Facial Emotion Recognition - Facial Feature Extraction - Language Detection diff --git a/README.md b/README.md index 1efd8d6..de1bd75 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ indicoio-python =============== -A wrapper for a series of APIs made by Indico Data Solutions. +A wrapper for a series of APIs made by indico. Check out the main site on: http://indico.io +Check out our documentation on: + +http://indicoiopython.s3-website-us-west-2.amazonaws.com/indicoio.html + Our APIs are totally free to use, and ready to be used in your application. No data or training required. Current APIs @@ -14,8 +18,9 @@ Current APIs Right now this wrapper supports the following apps: -- Political Sentiment Analysis - Positive/Negative Sentiment Analysis +- Political Sentiment Analysis +- Image Feature Extraction - Facial Emotion Recognition - Facial Feature Extraction - Language Detection diff --git a/indicoio/__init__.py b/indicoio/__init__.py index 76d4a39..d3d3739 100644 --- a/indicoio/__init__.py +++ b/indicoio/__init__.py @@ -1,9 +1,10 @@ JSON_HEADERS = {'Content-type': 'application/json', 'Accept': 'text/plain'} -Version, version, __version__, VERSION = ('0.4.2',) * 4 +Version, version, __version__, VERSION = ('0.4.3',) * 4 from text.sentiment import political, posneg from text.sentiment import posneg as sentiment from text.lang import language from images.fer import fer from images.features import facial_features +from images.features import image_features \ No newline at end of file diff --git a/indicoio/images/features.py b/indicoio/images/features.py index cac6475..d6b049b 100644 --- a/indicoio/images/features.py +++ b/indicoio/images/features.py @@ -4,6 +4,7 @@ import requests import numpy as np from indicoio import JSON_HEADERS +from indicoio.utils import image_preprocess def facial_features(image): """ @@ -30,5 +31,47 @@ def facial_features(image): data_dict = json.dumps({"face": image}) response = requests.post("http://api.indico.io/facialfeatures", data=data_dict, headers=JSON_HEADERS) - response_dict = json.loads(response.content) - return response_dict['response'] + response_dict = response.json() + if 'response' not in response_dict: + raise ValueError(response_dict.values()[0]) + else: + return response_dict['response'] + +def image_features(image): + """ + Given an input image, returns a 2048 dimensional sparse feature vector explaining that image. + Useful as a form of feature engineering for image oriented tasks. + + * Input can be either grayscale or rgb color and should either be a numpy array or nested list format. + * Input data should be either uint8 0-255 range values or floating point between 0 and 1. + * Large images (i.e. 1024x768+) are much bigger than needed, resizing will be done internally to 64x64 if needed. + * For ideal performance, images should be square aspect ratio but non-square aspect ratios are supported as well. + + Example usage: + + .. code-block:: python + + >>> from indicoio import image_features + >>> import numpy as np + >>> image = np.zeros((64,64,3)) + >>> features = image_features(image) + >>> len(features),np.min(features),np.max(features),np.sum(np.asarray(f)!=0) + (2048, 0.0, 6.97088623046875, 571) + + Since the image features returned are a semantic description of the contents of an image they can be used + to implement many other common image related tasks such as object recognition or image similarity and retrieval. + + For image similarity, simple distance metrics applied to collections of image feature vectors can work very well. + + :param image: The image to be analyzed. + :type image: numpy.ndarray + :rtype: List containing features + """ + image = image_preprocess(image) + data_dict = json.dumps({"image": image}) + response = requests.post("http://api.indico.io/imagefeatures", data=data_dict, headers=JSON_HEADERS) + response_dict = response.json() + if 'Features' not in response_dict: + raise ValueError(response_dict.values()[0]) + else: + return response_dict['Features'] \ No newline at end of file diff --git a/indicoio/images/fer.py b/indicoio/images/fer.py index d9fcf94..f66e063 100644 --- a/indicoio/images/fer.py +++ b/indicoio/images/fer.py @@ -30,4 +30,8 @@ def fer(image): data_dict = json.dumps({"face": image}) response = requests.post("http://api.indico.io/fer", data=data_dict, headers=JSON_HEADERS) - return json.loads(response.content) + response_dict = response.json() + if len(response_dict) < 2: + raise ValueError(response_dict.values()[0]) + else: + return response_dict diff --git a/indicoio/text/lang.py b/indicoio/text/lang.py index fd56ac6..d4b6767 100644 --- a/indicoio/text/lang.py +++ b/indicoio/text/lang.py @@ -28,4 +28,8 @@ def language(text): data_dict = json.dumps({'text': text}) response = requests.post("http://api.indico.io/language", data=data_dict, headers=JSON_HEADERS) - return json.loads(response.content) \ No newline at end of file + response_dict = response.json() + if len(response_dict) < 2: + raise ValueError(response_dict.values()[0]) + else: + return response_dict \ No newline at end of file diff --git a/indicoio/text/sentiment.py b/indicoio/text/sentiment.py index 8e7f004..ba5e8fe 100644 --- a/indicoio/text/sentiment.py +++ b/indicoio/text/sentiment.py @@ -32,13 +32,17 @@ def political(text): data_dict = json.dumps({'text': text}) response = requests.post("http://api.indico.io/political", data=data_dict, headers=JSON_HEADERS) - return json.loads(response.content) + response_dict = response.json() + if len(response_dict) < 2: + raise ValueError(response_dict.values()[0]) + else: + return response_dict def posneg(text): """ Given input text, returns a scalar estimate of the sentiment of that text. Values are roughly in the range 0 to 1 with 0.5 indicating neutral sentiment. - Likewise, 0 would suggest very negative sentiment and 1 would suggest very positive sentiment. + For reference, 0 suggests very negative sentiment and 1 suggests very positive sentiment. Example usage: @@ -48,13 +52,17 @@ def posneg(text): >>> text = 'Thanks everyone for the birthday wishes!! It was a crazy few days ><' >>> sentiment = sentiment(text) >>> sentiment - {u'Sentiment': 0.6946439339979863} + 0.6946439339979863 :param text: The text to be analyzed. :type text: str or unicode - :rtype: Dictionary containing Sentiment key with a float value + :rtype: Float """ data_dict = json.dumps({'text': text}) response = requests.post("http://api.indico.io/sentiment", data=data_dict, headers=JSON_HEADERS) - return json.loads(response.content) + response_dict = response.json() + if 'Sentiment' not in response_dict: + raise ValueError(response_dict.values()[0]) + else: + return response_dict['Sentiment'] diff --git a/indicoio/utils/__init__.py b/indicoio/utils/__init__.py index 7272f87..18ae6db 100644 --- a/indicoio/utils/__init__.py +++ b/indicoio/utils/__init__.py @@ -1,5 +1,6 @@ import inspect import numpy as np +from skimage.transform import resize class TypeCheck(object): """ @@ -84,3 +85,22 @@ def normalize(array, distribution=1, norm_range=(0, 1), **kwargs): if dict_array: return dict(zip(keys, norm_array)) return norm_array + +def image_preprocess(image): + """ + Takes an image and prepares it for sending to the api including + resizing and image data/structure standardizing. + """ + if isinstance(image,list): + image = np.asarray(image) + if type(image).__module__ != np.__name__: + raise ValueError('Image was not of type numpy.ndarray or list.') + if str(image.dtype) in ['int64','uint8']: + image = image/255. + if len(image.shape) == 2: + image = np.dstack((image,image,image)) + if len(image.shape) == 4: + image = image[:,:,:3] + image = resize(image,(64,64)) + image = image.tolist() + return image \ No newline at end of file diff --git a/setup.py b/setup.py index 34ad457..dfe9649 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ except ImportError: setup( name="IndicoIo", - version='0.4.2', + version='0.4.3', packages=[ "indicoio", "indicoio.text",