Skip to content

Commit

Permalink
Merge dev
Browse files Browse the repository at this point in the history
  • Loading branch information
MarvinKweyu committed Sep 26, 2020
2 parents 95c691d + b418809 commit ea98e77
Show file tree
Hide file tree
Showing 17 changed files with 373 additions and 30 deletions.
27 changes: 27 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,33 @@ Documentation

- Add ``write_text`` method along with other breaking changes to the documentation

.. _0.3.0:
0.3.0 (26-09-2020)
==================

Features
--------
- Video color detection and recognition

Documentation
-------------

- Include video color detection documentation
- Correction in package imports

.. _0.2.0:
0.2.0 (13-08-2020)
==================

Features
--------
- Enable input of custom text onto the image

Documentation
-------------

- Add ``write_text`` method along with other breaking changes to the documentation

.. _0.1.7:
0.1.7 (17-04-2020)
==================
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pip install ColorDetect
```

### Basic Usage

#### Images
```python
from colordetect import ColorDetect

Expand All @@ -43,6 +45,19 @@ user_image.save_image(<storage_path>,<image_name>)

Resultant image is stored in the string `storage_path` of choice with the `image_name` which will default to the current location and **out.jpg** respectively by default.

#### Videos

```python
from colordetect import VideoColor

user_video = VideoColor(<path_to_video>)
# return dictionary of color count. Do anything with this result
user_video.get_video_frames()
# to order this rather long result and get only a specific number
user_video.color_sort(color_count=6)
```


### Project Documentation

For further project documentation, visit [ColorDetect's page](https://colordetect.readthedocs.io/en/latest/)
Expand Down
3 changes: 2 additions & 1 deletion colordetect/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from .color_detect import ColorDetect
from .color_detect import ColorDetect
from .video_color_detect import VideoColor
17 changes: 13 additions & 4 deletions colordetect/color_detect.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
"""
.. _module_ColorDetect:
Module ColorDetect
==================
Defines ColorDetect class
For example:
>>> from colordetect import ColorDetect
>>> user_image = ColorDetect("<path_to_image>")
# where color_count is the target most dominant colors to be found. Default set to 5
>>> colors = user_image.get_color_count(color_count=5)
>>> colors
# alternatively, save these RGB values to the image
>>> user_image.save_color_count()
Image processed and saved successfully
>>>
# Image processed and saved successfully
"""

import logging
Expand All @@ -32,7 +34,13 @@ class ColorDetect:

def __init__(self, image):
"""Create ColorDetect object by providing an image"""
self.image = cv2.imread(image)

# check type of data being passed
if isinstance(image, np.ndarray):
self.image = image
else:
self.image = cv2.imread(image)

self.color_description = {}

def get_color_count(self, color_count: int = 5, color_format: str = 'rgb') -> dict:
Expand All @@ -53,6 +61,7 @@ def get_color_count(self, color_count: int = 5, color_format: str = 'rgb') -> di
* hsv - (60°,100%,100%)
* rgb - rgb(255, 255, 0) for yellow
* hex - #FFFF00 for yellow
:return: color description
"""

if type(color_count) != int:
Expand Down Expand Up @@ -82,7 +91,7 @@ def get_color_count(self, color_count: int = 5, color_format: str = 'rgb') -> di

return self.color_description

def _format_color(self, rgb_value, color_format):
def _format_color(self, rgb_value, color_format: str):
"""
Get the correct color format as specified
:return:
Expand Down
135 changes: 135 additions & 0 deletions colordetect/video_color_detect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
"""
.. _module_VideoColor:
Module VideoColor
==================
Defines VideoColor class
For example:
>>> from colordetect import VideoColor
>>> user_video = VideoColor("<path_to_video>")
# where color_count is the target most dominant colors to be found. Default set to 5
>>> colors = user_video.get_video_frames()
>>> colors
# alternatively shorten the dictionary to get a specific number of sorted colors from the whole lot
>>> user_video.color_sort(color_count=6)
"""

import sys
import cv2
from .color_detect import ColorDetect


class VideoColor(ColorDetect):
"""
Detect and recognize the number of colors in a video
"""

def __init__(self, video):
super().__init__(video)
self.video_file = cv2.VideoCapture(video)
self.color_description = {}

def get_video_frames(self, frame_color_count: int = 5, color_format: str = "rgb", progress: bool = False) -> dict:
"""
.. _get_video_frames:
get_video_frames
----------------
Get image frames and their colors from the video
Parameters
----------
frame_color_count: int
The number of most dominant colors to be obtained from a single frame
color_format:str
The format to return the color in.
Options
* hsv - (60°,100%,100%)
* rgb - rgb(255, 255, 0) for yellow
* hex - #FFFF00 for yellow
:return: color_description dictionary
"""
if type(frame_color_count) != int:
raise TypeError(
f"frame_color_count has to be an integer. Provided {type(frame_color_count)} "
)

color_format_options = ["rgb", "hex", "hsv"]

if color_format not in color_format_options:
raise ValueError(f"Invalid color format: {color_format}")

if type(progress) != bool:
raise ValueError(f"Progress should be a boolean. Provided {type(progress)}")

count = 0
fps = self.video_file.get(cv2.CAP_PROP_FPS)
total_frame_count = self.video_file.get(cv2.CAP_PROP_FRAME_COUNT)
video_duration = float(total_frame_count) / float(fps)
while self.video_file.isOpened():
# frame is the image
success, frame = self.video_file.read()
if success:
# read file every second
self.video_file.set(cv2.CAP_PROP_POS_MSEC, (count * 1000))
success, image = self.video_file.read()
image_object = ColorDetect(image)
colors = image_object.get_color_count(color_count=frame_color_count, color_format=color_format)
# merge dictionaries as they are created
self.color_description = {**self.color_description, **colors}
count += 1
if count >= video_duration:
break
if progress:
self._progress_bar(i=count, total_length=round(video_duration))

self.video_file.release()
cv2.destroyAllWindows()
print("\n")
return self.color_description

def color_sort(self, color_count: int = 5, ascending: bool = True):
"""
.. _color_sort
color_sort
----------------
Get number of colors wanted from video
Parameters
----------
color_count: int
The number of most dominant colors to be obtained from the image
:return: A sorted dictionary with specific number of color dominance
"""
if type(color_count) != int:
raise TypeError(f"color_count has to be an integer. Provided {type(color_count)} ")

if type(ascending) != bool:
raise TypeError(f"The value of the 'ascending' parameter is a boolean. Provided {type(ascending)} ")

sorted_colors = {
k: v
for k, v in sorted(self.color_description.items(), key=lambda item: item[1], reverse=ascending)
}
return dict(list(sorted_colors.items())[0:color_count])

def _progress_bar(self, i, total_length: int, post_text: str = "Color Detection"):
"""
_progress_bar
----------------
Display a progress bar of video processing
Parameters
----------
total_length: int
Total length of process
post_text: str
Text to display along with progress bar
"""
n_bar = 100
# # size of progress bar
j = i / total_length
sys.stdout.write("\r")
sys.stdout.write(f"[{'#' * int(n_bar * j):{n_bar}s}] {int(100 *j)}% {post_text}")
sys.stdout.flush()
Binary file added docs/_static/earth.mp4
Binary file not shown.
21 changes: 15 additions & 6 deletions docs/colordetect.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Welcome to ColorDetect's documentation
======================================

This site covers ColorDetect's usage and method documentation.
This site covers ColorDetect's usage and module documentation.


Getting started
Expand All @@ -15,11 +15,15 @@ Installation
For usage , import as::

import ColorDetect
import colordetect



Examples

Image color recognition
=======================

Example
--------

As a walk through some of the capabilities of ColorDetect we will use
Expand All @@ -30,7 +34,7 @@ this sample image.
::

# Get the most dominant color count from an image
>>> import ColorDetect
>>> from colordetect import ColorDetect
>>>
>>> my_image = ColorDetect("<image_path>")
>>> my_image.get_color_count()
Expand All @@ -50,6 +54,7 @@ For clarification::
# this key value pair would imply 6.2 % of the image, has an RGB of [2.0, 2.0, 249.0]



By default, `ColorDetect <https://colordetect.readthedocs.io/en/latest/>`_ will count
the 5 most dominant colors. This can , of course ,be overridden by parsing an argument specifying how many
colors most dominant you need from the image, with values decreasing in their percentage presence
Expand All @@ -60,9 +65,11 @@ on the different arguments it accepts including the different color format retur
Now suppose you want to take it a step further and write the result to the image itself.

.. warning:: Take note of the difference in saving the image to storage from hte previous
`save_color_count<save_color_count>` to `save_image<save_color_count>`
`save_color_count<save_color_count>` to `save_image<save_color_count>`

::


>>> my_image.write_color_count()
>>> my_image.save_image("<path_to_save_image>", "<name_of_image>")

Expand All @@ -88,7 +95,7 @@ Additionally, to enable the use of custom text on an image:

::

>>> import ColorDetect
>>> from colordetect import ColorDetect
>>> my_image = ColorDetect("<image_path>")
>>> my_image.write_text(text="a random string", line_spacing=10)

Expand All @@ -101,6 +108,8 @@ input, you want. By default, this value is an integer, zero, `0`, denoted as val

Whether using `write_text` or `write_color_count`, the image has to be saved using `save_image`.

Video color recognition can be done using :ref:`VideoColor<video_color_recognition>`

Interested to see just how far you can go? Take a look at :ref:`Contribution guidelines<Contributing>`.

`ColorDetect <https://github.com/MarvinKweyu/ColorDetect>`_ is always looking for the next step.
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
author = 'Marvin Kweyu'

# The full version, including alpha/beta/rc tags
release = '0.2.0'
release = '0.3.0'

# -- General configuration ---------------------------------------------------

Expand Down Expand Up @@ -59,7 +59,7 @@
html_logo = '../img/ColorDetect.png'

html_theme_options = {
'description': "Recognize and identify different colors in an image.",
'description': "Recognize and identify different colors in an image or video.",
'logo_text_align': 'justify',
}

Expand Down
5 changes: 5 additions & 0 deletions docs/developer_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ and feel free to submit a pull. The project source is hosted on `Github <https:/
:undoc-members:
:show-inheritance:

.. automodule:: colordetect.video_color_detect
:members:
:undoc-members:
:show-inheritance:


.. automodule:: colordetect
:members:
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Welcome to ColorDetect's documentation!
:caption: Contents:

colordetect.rst
videocolor.rst
misc


Expand Down
Loading

0 comments on commit ea98e77

Please sign in to comment.