diff --git a/.gitignore b/.gitignore
index 091919c..83ed8e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,6 +63,11 @@ instance/
# Sphinx documentation
docs/_build/
+# py.test
+.cache/*
+.pytest_cache/*
+.pytest_config
+
# PyBuilder
target/
diff --git a/Dockerfile b/Dockerfile
index 3514060..5eddc8c 100755
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,55 +1,46 @@
# TensorPy Docker Image
-FROM ubuntu:15.10
+FROM ubuntu:17.10
-#=======================================
-# Install Python and Basic Python Tools
-#=======================================
-RUN apt-get update && apt-get install -y python python-pip python-setuptools \
- python-dev python-distribute python-virtualenv
+#================================
+# Update apt-get package sources
+#================================
+RUN apt-get update
-#=========================================
-# Install Bash Command Line Tools and Git
-#=========================================
+#==================================================
+# Install Bash Command Line Tools, Python, and Git
+#==================================================
RUN apt-get -qy --no-install-recommends install \
+ python \
+ python-dev \
+ python-pip \
+ python-distribute \
+ python-virtualenv \
+ python-setuptools \
sudo \
unzip \
wget \
curl \
+ libxi6 \
+ libgconf-2-4 \
vim \
git-core \
&& rm -rf /var/lib/apt/lists/*
-#========================================
-# Add normal user with passwordless sudo
-#========================================
-RUN sudo useradd seluser --shell /bin/bash --create-home \
- && sudo usermod -a -G sudo seluser \
- && echo 'ALL ALL = (ALL) NOPASSWD: ALL' >> /etc/sudoers
-
-#==============================
-# Locale and encoding settings
-#==============================
-ENV LANGUAGE en_US.UTF-8
-ENV LANG ${LANGUAGE}
-RUN locale-gen ${LANGUAGE} \
- && dpkg-reconfigure --frontend noninteractive locales
-
#==============================
# Set up TensorFlow / TensorPy
#==============================
-COPY third_party/docker/docker_install.sh /TensorPy/docker_install.sh
+COPY install.sh /TensorPy/install.sh
COPY requirements.txt /TensorPy/
COPY setup.py /TensorPy/
COPY tensorpy /TensorPy/tensorpy/
COPY examples /TensorPy/examples/
-COPY third_party/docker /TensorPy/third_party/docker/
-COPY third_party/docker/run_docker_test.sh /TensorPy/
-RUN cd /TensorPy && ls && ./third_party/docker/docker_install.sh
+COPY integrations/docker/run_docker_test.sh /TensorPy/
+RUN cd /TensorPy && ls && ./install.sh
RUN cd /TensorPy && pip install -r requirements.txt
#===================
# Create entrypoint
#===================
-COPY third_party/docker/docker-entrypoint.sh /
+COPY integrations/docker/docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/bin/bash"]
diff --git a/LICENSE b/LICENSE
index 3ed9a1a..107c651 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2017 Michael Mintz
+Copyright (c) 2018 Michael Mintz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 2eaa7de..56b21ec 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@

# TensorPy
-[](https://pypi.python.org/pypi/tensorpy) [](https://github.com/TensorPy/TensorPy/stargazers) [](https://docs.python.org/2/) [](https://github.com/TensorPy/TensorPy/blob/master/LICENSE) [](https://gitter.im/TensorPy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](https://pypi.python.org/pypi/tensorpy) [](https://docs.python.org/2/) [](https://gitter.im/TensorPy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
**Easy Image Classification with TensorFlow**
@@ -9,16 +9,19 @@
(**[Watch the 2-minute tutorial on YouTube](https://www.youtube.com/watch?v=lVtzaHcUE7Q)**)
-Now runs **much faster** since video released!
+### Requirements:
-You can use TensorPy to classify images by simply passing a URL on the command line, or by using TensorPy in your Python programs. **[TensorFlow](https://www.tensorflow.org/)** does all the image-recognition work. TensorPy also simplifies TensorFlow installation by automating several setup steps into a single script (See **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** for details).
+* A Mac or Linux machine
+* Python 3.5, 3.6, or 3.7
+
+You can use TensorPy to classify images by simply passing a URL on the command line, or by using TensorPy in your Python programs. **[TensorFlow](https://www.tensorflow.org/)** does all the real work. TensorPy also simplifies TensorFlow installation by automating several setup steps into a single script (See **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** for details).
(Read **[how_tensorpy_works](https://github.com/TensorPy/TensorPy/blob/master/help_docs/how_tensorpy_works.md)** for a detailed explanation of how TensorPy works.)
## Setup Steps for Mac & Ubuntu/Linux
-(**Windows & Docker users**: See the **[Docker ReadMe](https://github.com/TensorPy/TensorPy/blob/master/third_party/docker/ReadMe.md)** for running on a Docker machine. Windows requires Docker to run TensorFlow.)
+(**Windows & Docker users**: See the **[Docker ReadMe](https://github.com/TensorPy/TensorPy/blob/master/integrations/docker/ReadMe.md)** for running on a Docker machine. Windows requires Docker to run TensorFlow.)
#### **Step 1:** Create and activate a virtual environment named "tensorpy"
@@ -33,7 +36,7 @@ cd TensorPy
#### **Step 3:** Install TensorPy, TensorFlow, and ImageNet/Inception
-The **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** script installs everything you need:
+Use **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** to install everything you need.
```bash
./install.sh
@@ -41,6 +44,8 @@ The **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)*
#### **Step 4:** Run the examples
+(NOTE: Run times may vary depending on your Internet connection and computer's CPU speed.)
+
Classify a single image from a URL:
```bash
@@ -55,9 +60,43 @@ classify "https://github.com/TensorPy/TensorPy/tree/master/examples/images"
Classify a single image URL from a Python script: (See **[test_python_classify.py](https://github.com/TensorPy/TensorPy/blob/master/examples/test_python_classify.py)** for details.)
+```bash
+python examples/test_python_classify.py
+```
+
+Classify an image from a local file path:
+
+```bash
+classify examples/images/cat_animal.jpg
+```
+
+Classify all images from a local folder:
+
+```bash
+classify examples/images/
+```
+
+#### **Examples in Python programs:**
+
+Classify an image from a local file path using a Python script: (See **[test_python_file_classify.py](https://github.com/TensorPy/TensorPy/blob/master/examples/test_python_file_classify.py)** for details.)
+
+```bash
+cd examples
+python test_python_file_classify.py
+```
+
+Classify all images in a local folder using a Python script (Output = LIST): (See **[test_python_folder_classify.py](https://github.com/TensorPy/TensorPy/blob/master/examples/test_python_folder_classify.py)** for details.)
+
+```bash
+cd examples
+python test_python_folder_classify.py
+```
+
+Classify all images in a local folder using a Python script (Output = DICTIONARY): (See **[test_python_folder_classify_dict.py](https://github.com/TensorPy/TensorPy/blob/master/examples/test_python_folder_classify_dict.py)** for details.)
+
```bash
cd examples
-python test_python_classify.py
+python test_python_folder_classify_dict.py
```
____________
diff --git a/examples/ReadMe.md b/examples/ReadMe.md
index 541b5c0..17f2efa 100755
--- a/examples/ReadMe.md
+++ b/examples/ReadMe.md
@@ -1,6 +1,6 @@
## Running TensorPy Examples
-(NOTE: If you didn't install TensorFlow and TensorPy properly from the README instructions, these scripts won't work.)
+(NOTE: If you didn't install TensorFlow and TensorPy properly from the [README](https://github.com/TensorPy/TensorPy/blob/master/README.md) instructions, these scripts won't work.)
```bash
./test_classify_image.sh
@@ -14,4 +14,6 @@ You can also perform classifications from Python scripts:
python test_python_classify.py
```
-(NOTE: If you see any ``*.pyc`` files appear as you run tests, that is compiled bytecode, which is a natural result of running Python code.)
+(NOTE: If you see any ``*.pyc`` files appear as you run Python scripts, that is compiled bytecode, which is a natural result of running Python code.)
+
+For more examples, see Step 4 of the [README](https://github.com/TensorPy/TensorPy/blob/master/README.md).
diff --git a/examples/test_python_file_classify.py b/examples/test_python_file_classify.py
new file mode 100644
index 0000000..8523edf
--- /dev/null
+++ b/examples/test_python_file_classify.py
@@ -0,0 +1,4 @@
+from tensorpy import image_base
+
+result = image_base.classify_local_image("images/cat_animal.jpg")
+print("\nBest match classification:\n%s\n" % result)
diff --git a/examples/test_python_folder_classify.py b/examples/test_python_folder_classify.py
new file mode 100644
index 0000000..c3c6dc2
--- /dev/null
+++ b/examples/test_python_folder_classify.py
@@ -0,0 +1,6 @@
+from tensorpy import image_base
+
+classifications = image_base.classify_folder_images('./images')
+print("*** Displaying Image Classification Results as a list: ***")
+for classification in classifications:
+ print(classification)
diff --git a/examples/test_python_folder_classify_dict.py b/examples/test_python_folder_classify_dict.py
new file mode 100644
index 0000000..5119129
--- /dev/null
+++ b/examples/test_python_folder_classify_dict.py
@@ -0,0 +1,5 @@
+from tensorpy import image_base
+
+dictionary = image_base.classify_folder_images('./images', return_dict=True)
+print("*** Displaying Image Classification Results as a dictionary: ***")
+print(dictionary)
diff --git a/help_docs/how_tensorpy_works.md b/help_docs/how_tensorpy_works.md
index b01300e..0d76f96 100755
--- a/help_docs/how_tensorpy_works.md
+++ b/help_docs/how_tensorpy_works.md
@@ -1,5 +1,7 @@
### How TensorPy Works (Detailed Explanation)
+(NOTE: Run times may vary depending on your Internet connection and computer's CPU speed.)
+
Once TensorPy is installed with **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)**, a command called ``classify`` is added to your command line, which takes a URL as input. When called, TensorPy determines if that URL links to an image or a web image. If it's an image, TensorPy downloads the image to a new folder called ``downloads_folder``. From there, the image is converted to a JPEG. Then, the image is fed to the local **[tensorpy/classify_image.py](https://github.com/TensorPy/TensorPy/blob/master/tensorpy/classify_image.py)** which tells TensorFlow to use the ImageNet Inception database to classify the image and print out the result.
If the ``classify`` command is called with a web page as input, then all images on that page (up to the limit defined in **[tensorpy/settings.py](https://github.com/TensorPy/TensorPy/blob/master/tensorpy/settings.py)**) will get downloaded to ``downloads_folder``, where TensorPy does the work listed above per image, with the exception of images smaller than the minimum size defined in tensorpy/settings.py (currently 50x50 pixels). Images that are too small will be skipped because results have shown that icons and other tiny images get extremely poor classification results.
diff --git a/help_docs/pip_installation.md b/help_docs/pip_installation.md
index 158a808..6ecdaad 100755
--- a/help_docs/pip_installation.md
+++ b/help_docs/pip_installation.md
@@ -1,13 +1,19 @@
### Pip Installation Instructions
-Ubuntu/Linux
+Ubuntu/Linux:
```bash
sudo apt-get install python-pip python-dev
```
-Mac OS X
+Mac OS X:
```bash
sudo easy_install pip
```
+
+OR
+
+```bash
+python -m pip install -U pip
+```
diff --git a/help_docs/virtualenv_instructions.md b/help_docs/virtualenv_instructions.md
index 2452237..692f620 100755
--- a/help_docs/virtualenv_instructions.md
+++ b/help_docs/virtualenv_instructions.md
@@ -1,15 +1,15 @@
### Virtual Environment Setup Tutorial
-First:
+First, install virtualenv / virtualenvwrapper:
```bash
-sudo pip install virtualenv
-sudo pip install virtualenvwrapper
+python -m pip install virtualenv
+python -m pip install virtualenvwrapper
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
```
-Next, follow the command depending on the system you're using:
+If you add ``source /usr/local/bin/virtualenvwrapper.sh`` to your local bash file (``~/.bash_profile`` on Mac, ``~/.bashrc`` on Linux), virtualenvwrapper commands will be available to you whenever you open a new command prompt. You can then use the following commands to make those changes active.
Mac users: ``source ~/.bash_profile``
Linux users: ``source ~/.bashrc``
@@ -28,7 +28,6 @@ deactivate
You can always jump back in later:
-(If you're using ``virtualenvwrapper``):
```bash
workon tensorpy
```
diff --git a/install.sh b/install.sh
index 4417369..2062c23 100755
--- a/install.sh
+++ b/install.sh
@@ -1,20 +1,19 @@
# Installs TensorPy, TensorFlow, ImageNet, and required dependancies
-pip install --upgrade pip
-echo "Installing TensorPy..."
-pip install -r requirements.txt
-python setup.py install
+python -m pip install --upgrade pip
+echo "Installing TensorPy:"
+pip install -r requirements.txt --upgrade
+python setup.py develop
value="$(uname)"
-if [ $value == "Linux" ]
+if [ $value = "Linux" ]
then
echo "Initializing TensorFlow setup on a Linux machine..."
- export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.1.0-cp27-none-linux_x86_64.whl
+ export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.14.0-cp27-none-linux_x86_64.whl
pip install --ignore-installed --upgrade $TF_BINARY_URL
-elif [ $value == "Darwin" ]
+elif [ $value = "Darwin" ]
then
echo "Initializing TensorFlow setup on a MAC..."
- export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.1.0-py2-none-any.whl
- pip install --ignore-installed --upgrade $TF_BINARY_URL
+ pip install --upgrade tensorflow
else
echo "Incompatible machine for TensorFlow. Exiting script..."
fi
diff --git a/third_party/ReadMe.md b/integrations/ReadMe.md
similarity index 59%
rename from third_party/ReadMe.md
rename to integrations/ReadMe.md
index 287ae25..75f693f 100755
--- a/third_party/ReadMe.md
+++ b/integrations/ReadMe.md
@@ -1,3 +1,3 @@
-## Third-Party / Integrations
+## Integrations
This folder contains TensorPy integrations
diff --git a/third_party/docker/ReadMe.md b/integrations/docker/ReadMe.md
similarity index 100%
rename from third_party/docker/ReadMe.md
rename to integrations/docker/ReadMe.md
diff --git a/third_party/docker/docker-entrypoint.sh b/integrations/docker/docker-entrypoint.sh
similarity index 100%
rename from third_party/docker/docker-entrypoint.sh
rename to integrations/docker/docker-entrypoint.sh
diff --git a/third_party/docker/run_docker_test.sh b/integrations/docker/run_docker_test.sh
similarity index 100%
rename from third_party/docker/run_docker_test.sh
rename to integrations/docker/run_docker_test.sh
diff --git a/requirements.txt b/requirements.txt
index fb2f6bf..5f4fae2 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,6 @@
-requests>=2.13.0
-six>=1.10.0
-Pillow>=4.1.1
-BeautifulSoup>=3.2.1
--e .
+tensorflow==1.15.4
+pip>=20.2.3
+six>=1.15.0
+requests>=2.24.0
+Pillow==7.2.0
+beautifulsoup4==4.9.2
diff --git a/setup.cfg b/setup.cfg
new file mode 100755
index 0000000..cb069cd
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[bdist_wheel]
+# TensorPy works for both Python 2.7 and Python 3
+universal=1
diff --git a/setup.py b/setup.py
index 9b5ad5b..863853e 100644
--- a/setup.py
+++ b/setup.py
@@ -5,21 +5,72 @@
"""
from setuptools import setup, find_packages # noqa
+import os
+import sys
+
+
+this_directory = os.path.abspath(os.path.dirname(__file__))
+long_description = None
+try:
+ with open(os.path.join(this_directory, 'README.md'), 'rb') as f:
+ long_description = f.read().decode('utf-8')
+except IOError:
+ long_description = 'Easy Image Classification with TensorFlow!'
+
+if sys.argv[-1] == 'publish':
+ reply = None
+ input_method = input
+ if not sys.version_info[0] >= 3:
+ input_method = raw_input # noqa
+ reply = str(input_method(
+ '>>> Confirm release PUBLISH to PyPI? (yes/no): ')).lower().strip()
+ if reply == 'yes':
+ print("\n*** Checking code health with flake8:\n")
+ flake8_status = os.system("flake8 --exclude=temp")
+ if flake8_status != 0:
+ print("\nWARNING! Fix flake8 issues before publishing to PyPI!\n")
+ sys.exit()
+ else:
+ print("*** No flake8 issues detected. Continuing...")
+ print("\n*** Rebuilding distribution packages: ***\n")
+ os.system('rm -f dist/*.egg; rm -f dist/*.tar.gz; rm -f dist/*.whl')
+ os.system('python setup.py sdist bdist_wheel') # Create new tar/wheel
+ print("\n*** Installing twine: *** (Required for PyPI uploads)\n")
+ os.system("python -m pip install --upgrade 'twine>=1.15.0'")
+ print("\n*** Installing tqdm: *** (Required for PyPI uploads)\n")
+ os.system("python -m pip install --upgrade 'tqdm>=4.49.0'")
+ print("\n*** Publishing The Release to PyPI: ***\n")
+ os.system('python -m twine upload dist/*') # Requires ~/.pypirc Keys
+ print("\n*** The Release was PUBLISHED SUCCESSFULLY to PyPI! :) ***\n")
+ else:
+ print("\n>>> The Release was NOT PUBLISHED to PyPI! <<<\n")
+ sys.exit()
setup(
name='tensorpy',
- version='1.0.14',
- url='http://tensorpy.com',
+ version='1.6.1',
+ description='Easy Image Classification with TensorFlow!',
+ long_description=long_description,
+ long_description_content_type='text/markdown',
+ url='https://github.com/TensorPy/TensorPy',
+ platforms=["Linux", "Unix", "Mac OS-X"],
author='Michael Mintz',
- author_email='@mintzworld',
+ author_email='mdmintz@gmail.com',
maintainer='Michael Mintz',
- description='Easy Image Classification with TensorFlow!',
- license='The MIT License',
+ license="MIT",
+ classifiers=[
+ "Programming Language :: Python :: 3.5",
+ "Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ ],
+ python_requires='>=3.5, <3.8',
install_requires=[
- 'requests>=2.13.0',
- 'six>=1.10.0',
- 'Pillow>=4.1.1',
- 'BeautifulSoup>=3.2.1',
+ 'tensorflow==1.15.4',
+ 'pip>=20.2.3',
+ 'six>=1.15.0',
+ 'requests>=2.24.0',
+ 'Pillow==7.2.0',
+ 'beautifulsoup4==4.9.2',
],
packages=['tensorpy'],
entry_points={
diff --git a/tensorpy/classify.py b/tensorpy/classify.py
index 8da263f..518e97e 100644
--- a/tensorpy/classify.py
+++ b/tensorpy/classify.py
@@ -3,6 +3,7 @@
import threading
import uuid
from multiprocessing.dummy import Pool as ThreadPool
+from os.path import isdir, isfile
from tensorpy import classify_image
from tensorpy import settings
from tensorpy import image_base
@@ -21,7 +22,7 @@ def download_and_classify_image(image_url):
downloads_folder = settings.DOWNLOADS_FOLDER
# Prevent file conflicts by using unique identifiers
- hex_name = 'temp_image_%s' % uuid.uuid4().get_hex()
+ hex_name = 'temp_image_%s' % uuid.uuid4().hex
hex_name_png = hex_name + '.png'
hex_name_jpg = hex_name + '.jpg'
@@ -64,19 +65,30 @@ def main():
expected_arg = "[A valid PAGE_URL or IMAGE_URL]"
num_args = len(sys.argv)
if num_args < 2 or num_args > 2:
- print "\n* INVALID RUN COMMAND! * Usage:"
- print "classify %s\n" % expected_arg
+ print("\n* INVALID RUN COMMAND! * Usage:")
+ print("classify %s\n" % expected_arg)
elif num_args == 2:
url = sys.argv[1]
valid_url = web_core.is_valid_url(url)
if not valid_url:
- raise Exception("Error: %s is not a valid URL!" % url)
+ file_path = url
+ if isfile(file_path):
+ best_guess = image_base.classify_local_image(file_path)
+ elif isdir(file_path):
+ best_guess = image_base.classify_folder_images(
+ file_path, return_dict=True)
+ else:
+ raise Exception("Error: %s is not a valid image path!" % url)
+ print("\n*** Best match classification: ***")
+ print(best_guess)
+ print("")
+ return
content_type = web_core.get_content_type(url)
if content_type == 'other':
raise Exception(
"Error: %s does not evaluate to %s" % (url, expected_arg))
elif content_type == 'image':
- best_guess = image_base.get_image_classification(url)
+ best_guess = image_base.classify_image_url(url)
print("\n*** Best match classification: ***")
print(best_guess)
print("")
@@ -107,14 +119,14 @@ def main():
"Best match classifications for page images:"
" ***")
images_classified += 1
- print best_guess
+ print(best_guess)
if images_classified >= settings.MAX_IMAGES_PER_PAGE:
break
if images_classified >= settings.MAX_IMAGES_PER_PAGE:
- print("\n(NOTE: Exceeded page classification limit "
- "of %d images per URL! Stopping early.)" % (
- settings.MAX_IMAGES_PER_PAGE))
+ print("\n(NOTE: Exceeded page classification limit "
+ "of %d images per URL! Stopping early.)" % (
+ settings.MAX_IMAGES_PER_PAGE))
if images_classified == 0:
print("\nCould not find images to classify on the page! "
diff --git a/tensorpy/classify_image.py b/tensorpy/classify_image.py
index 40a05a8..2c20196 100644
--- a/tensorpy/classify_image.py
+++ b/tensorpy/classify_image.py
@@ -13,7 +13,7 @@
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
FLAGS = tf.app.flags.FLAGS
-tf.logging.set_verbosity(tf.logging.ERROR)
+tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
tf.app.flags.DEFINE_string(
'model_dir', settings.IMAGENET_FOLDER,
"""Path to classify_image_graph_def.pb, """
@@ -126,4 +126,4 @@ def external_run(image):
if __name__ == '__main__':
- tf.app.run()
+ tf.compat.v1.app.run()
diff --git a/tensorpy/download_imagenet.py b/tensorpy/download_imagenet.py
index ab425e7..1dd49b3 100644
--- a/tensorpy/download_imagenet.py
+++ b/tensorpy/download_imagenet.py
@@ -26,6 +26,7 @@ def maybe_download_and_extract():
os.makedirs(dest_directory)
filename = DATA_URL.split('/')[-1]
filepath = os.path.join(dest_directory, filename)
+ print("ImageNet Inception DB filepath: %s" % filepath)
if not os.path.exists(filepath):
def _progress(count, block_size, total_size):
sys.stdout.write('\r>> Downloading %s %.1f%%' % (
@@ -43,4 +44,4 @@ def main(_):
maybe_download_and_extract()
-tf.app.run()
+tf.compat.v1.app.run()
diff --git a/tensorpy/image_base.py b/tensorpy/image_base.py
index 2b6905b..98aa7c1 100644
--- a/tensorpy/image_base.py
+++ b/tensorpy/image_base.py
@@ -1,18 +1,22 @@
import os
import requests
+import shutil
+import sys
import uuid
-from BeautifulSoup import BeautifulSoup
+from bs4 import BeautifulSoup
+from io import StringIO
+from os import listdir
+from os.path import isdir, isfile, join
from PIL import Image
-from StringIO import StringIO
from tensorpy import classify_image
from tensorpy import settings
from tensorpy import web_core
def get_image_file_dimensions(file_name):
- image = Image.open(file_name)
- image_dimensions = image.size # (width, height) tuple
- return image_dimensions
+ with Image.open(file_name) as image:
+ image_dimensions = image.size # (width, height) tuple
+ return image_dimensions
def convert_image_file_to_jpg(file_name):
@@ -22,15 +26,17 @@ def convert_image_file_to_jpg(file_name):
outfile = f + ".jpg"
if infile != outfile:
try:
- Image.open(infile).convert('RGBA').save(outfile, "JPEG")
+ with Image.open(infile) as image:
+ image.convert('RGB').save(outfile, "JPEG")
except IOError:
raise Exception("Cannot convert %s to jpg!" % file_name)
def load_image_from_url(image_url):
response = requests.get(image_url)
- image = Image.open(StringIO(response.content)).convert('RGBA')
- return image
+ with Image.open(StringIO(response.content)) as image:
+ image.convert('RGB')
+ return image
def get_image_dimensions(image):
@@ -57,10 +63,12 @@ def get_all_images_on_page(page_url):
full_base_url = prefix + "://" + base_url + "/"
html = requests.get(page_url)
completed_source = web_core.rebuild_source(html.text, full_base_url)
- soup = BeautifulSoup(completed_source)
- imgs = soup.fetch('img', src=True, onload=None)
+ soup = BeautifulSoup(completed_source, "html.parser")
+ imgs = soup.find_all("img")
image_url_list = []
for img in imgs:
+ if not img.has_attr("src") or img.has_attr("onload"):
+ continue
link = img["src"].split("src=")[-1]
compact_link = link.split('?')[0]
if (compact_link.endswith('.png') or compact_link.endswith('.jpg') or
@@ -75,26 +83,80 @@ def get_all_images_on_page(page_url):
return image_url_list
-def get_image_classification(image_url):
+def classify_image_url(image_url):
+ """ Classify an image from a URL. """
downloads_folder = settings.DOWNLOADS_FOLDER
- hex_name = 'temp_image_%s' % uuid.uuid4().get_hex()
+ hex_name = 'temp_image_%s' % uuid.uuid4().hex
hex_name_png = hex_name + '.png'
hex_name_jpg = hex_name + '.jpg'
-
web_core.save_file_as(image_url, hex_name_png)
convert_image_file_to_jpg(
"%s/%s" % (downloads_folder, hex_name_png))
os.rename(downloads_folder + "/" + hex_name_png,
downloads_folder + "/temp_image_png.png")
-
best_guess = classify_image.external_run(
"%s/%s" % (downloads_folder, hex_name_jpg))
os.rename(downloads_folder + "/" + hex_name_jpg,
downloads_folder + "/temp_image_jpg.jpg")
-
return best_guess.strip()
-def classify(image_url):
- """ A shorter method name for get_image_classification() """
- return get_image_classification(image_url)
+def get_image_classification(image_url):
+ # Keep original method name for backwards-compatibility
+ return classify_image_url(image_url)
+
+
+def classify_local_image(file_path):
+ """ Classify an image from a local file path. """
+ if not file_path.endswith('.jpg') and not file_path.endswith('.png'):
+ raise Exception("Expecting a .jpg or .png file!")
+ downloads_folder = settings.DOWNLOADS_FOLDER
+ hex_name = 'temp_image_%s' % uuid.uuid4().hex
+ hex_name_png = hex_name + '.png'
+ hex_name_jpg = hex_name + '.jpg'
+ shutil.copy2(file_path, os.path.join(downloads_folder, hex_name_png))
+ convert_image_file_to_jpg(
+ "%s/%s" % (downloads_folder, hex_name_png))
+ os.rename(downloads_folder + "/" + hex_name_png,
+ downloads_folder + "/temp_image_png.png")
+ best_guess = classify_image.external_run(
+ "%s/%s" % (downloads_folder, hex_name_jpg))
+ os.rename(downloads_folder + "/" + hex_name_jpg,
+ downloads_folder + "/temp_image_jpg.jpg")
+ return best_guess
+
+
+def classify_folder_images(folder_path, return_dict=False):
+ """ Classify all images from a local folder. """
+ classified_images_list = []
+ classified_images_dict = {}
+ files = [f for f in listdir(folder_path) if isfile(join(folder_path, f))]
+ images = [f for f in files if (f.endswith('.jpg') or f.endswith('.png'))]
+ total = len(images)
+ counter = 0
+ for image in images:
+ counter += 1
+ sys.stdout.write("\rClassifying Image %d of %s..." % (counter, total))
+ sys.stdout.flush()
+ result = classify_local_image(os.path.join(folder_path, image))
+ classified_images_list.append(result)
+ classified_images_dict[image] = result
+ sys.stdout.write("\rAll classifications have been completed!\n")
+ if return_dict:
+ return classified_images_dict
+ return classified_images_list
+
+
+def classify(image_url_or_path):
+ """ Classify an image from a URL or local file path.
+ If a local folder is provided, all images in the folder
+ will be classified. """
+ is_valid_url = web_core.is_valid_url(image_url_or_path)
+ if is_valid_url:
+ return classify_image_url(image_url_or_path)
+ elif isfile(image_url_or_path):
+ return classify_local_image(image_url_or_path)
+ elif isdir(image_url_or_path):
+ return classify_folder_images(image_url_or_path, return_dict=True)
+ else:
+ raise Exception("Expecting an image URL, file path, or folder path!")
diff --git a/third_party/docker/docker_install.sh b/third_party/docker/docker_install.sh
deleted file mode 100755
index 8edc900..0000000
--- a/third_party/docker/docker_install.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-# Installs TensorPy, TensorFlow, ImageNet, and required dependancies
-# (Special Docker edition!)
-
-pip install --upgrade pip
-echo "Installing TensorPy..."
-python setup.py install
-echo "Initializing TensorFlow setup on an Ubuntu Docker machine..."
-export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl
-pip install $TF_BINARY_URL
-echo "Downloading ImageNet (image database for classifying images)..."
-python tensorpy/download_imagenet.py
-exit