Skip to content

Commit

Permalink
Merge pull request #37 from fernaper/development
Browse files Browse the repository at this point in the history
v2.0.2
  • Loading branch information
fernaper authored Apr 14, 2019
2 parents 6ef796f + bbeac23 commit aada297
Show file tree
Hide file tree
Showing 15 changed files with 331 additions and 198 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Images and videos
*.jpg
*.jpeg
*.png
*.mp4

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
133 changes: 58 additions & 75 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# opencv-draw-tools
# cv2_tools
Library to help the drawing process with OpenCV. Thought to add labels to the images. Classification of images, etc.

![image](https://user-images.githubusercontent.com/18369529/53686731-3dba0500-3d2b-11e9-95e5-e4517c013d14.png)
Expand All @@ -24,21 +24,70 @@ Finally you can install the library with:

When you install `opencv-draw-tools`, it will automatically download `numpy` but not opencv becouse in some cases you will need another version.

## Usage

### Test
## Test

```
import opencv_draw_tools as cv2_tools
import cv2_tools
print('Name: {}\nVersion:{}\nHelp:{}'.format(cv2_tools.name,cv2_tools.__version__,cv2_tools.help))
cv2_tools.webcam_test()
webcam_test()
```

## Ussage and Important classes

### ManagerCV2

```
from cv2_tools.Management import ManagerCV2
```

If you want to work with video or stream, this class will help you mantain your code cleaner while you get more features.

For example:
- Open a a stream (your webcam).
- Reproduce it on real time with max FPS equals to 24.
- Press `esc` to finish the program.
- At the end print average FPS.

```
from cv2_tools.Managment import ManagerCV2
import cv2
# keystroke=27 is the button `esc`
manager_cv2 = ManagerCV2(cv2.VideoCapture(0), is_stream=True, keystroke=27, wait_key=1, fps_limit=60)
# This for will manage file descriptor for you
for frame in manager_cv2:
cv2.imshow('Example easy manager', frame)
cv2.destroyAllWindows()
print(manager_cv2.get_fps())
```

If you want to use another button and you don't know the ID, you can check easily using the following code:

```
from cv2_tools.Managment import ManagerCV2
import cv2
# keystroke=27 is the button `esc`
manager_cv2 = ManagerCV2(cv2.VideoCapture(0), is_stream=True, keystroke=27, wait_key=1, fps_limit=60)
# This for will manage file descriptor for you
for frame in manager_cv2:
# Each time you press a button, you will get its id in your terminal
last_keystroke = manager_cv2.get_last_keystroke()
if last_keystroke != -1:
print(last_keystroke)
cv2.imshow('Easy button checker', frame)
cv2.destroyAllWindows()
```
### Oriented Object Programming method

### SelectorCV2

Firstly create a SelectorCV2 object. You can pass it optional parameters to configure the output.
```
selector = cv2_tools.SelectorCV2(color=(200,90,0), filled=True)
from cv2_tools.Selection import SelectorCV2
selector = SelectorCV2(color=(200,90,0), filled=True)
```

Also you can configure it later using the method (all optional parameters):
Expand Down Expand Up @@ -80,70 +129,4 @@ selector.set_range_valid_rectangles( origin, destination)
set_valid_rectangles(indexes)
```

If you want, you can see the example [detect_faces.py](opencv_draw_tools/detect_faces.py), it also use an open source library called `face_recognition`.


### Manual method

```
import opencv_draw_tools as cv2_tools
"""
Draw better rectangles to select zones.
Keyword arguments:
frame -- opencv frame object where you want to draw
position -- touple with 4 elements (x1, y1, x2, y2)
This elements must be between 0 and 1 in case it is normalized
or between 0 and frame height/width.
tags -- list of strings/tags you want to associate to the selected zone (default [])
tag_position -- position where you want to add the tags, relatively to the selected zone (default None)
If None provided it will auto select the zone where it fits better:
- First try to put the text on the Bottom Rigth corner
- If it doesn't fit, try to put the text on the Bottom Left corner
- If it doesn't fit, try to put the text Inside the rectangle
- Finally if it doesn't fit, try to put the text On top of the rectangle
alpha -- transparency of the selected zone on the image (default 0.9)
1 means totally visible and 0 totally invisible
color -- color of the selected zone, touple with 3 elements BGR (default (110,70,45) -> dark blue)
BGR = Blue - Green - Red
normalized -- boolean parameter, if True, position provided normalized (between 0 and 1) else you should provide concrete values (default False)
thickness -- thickness of the drawing in pixels (default 2)
filled -- boolean parameter, if True, will draw a filled rectangle with one-third opacity compared to the rectangle (default False)
peephole -- boolean parameter, if True, also draw additional effect, so it looks like a peephole
"""
frame = cv2_tools.select_zone(frame, position, tags=[])
```

### Example with Webcam

```
import opencv_draw_tools as cv2_tools
cv2_tools.webcam_test()
```

See `webcam_test()` code:

```
def webcam_test():
"""Reproduce Webcam in real time with a selected zone."""
print('Launching webcam test')
cap = cv2.VideoCapture(0)
f_width = cap.get(3)
f_height = cap.get(4)
window_name = 'opencv_draw_tools'
while True:
ret, frame = cap.read()
frame = cv2.flip(frame, 1)
if ret:
keystroke = cv2.waitKey(1)
position = (0.33,0.2,0.66,0.8)
tags = ['MIT License', '(C) Copyright\n Fernando\n Perez\n Gutierrez']
frame = select_zone(frame, position, tags=tags, color=(130,58,14), thickness=2, filled=True, normalized=True)
cv2.imshow(window_name, frame)
# True if escape 'esc' is pressed
if keystroke == 27:
break
cv2.destroyAllWindows()
cv2.VideoCapture(0).release()
```
If you want, you can see the example [detect_faces.py](examples/detect_faces.py), it also use an open source library called `face_recognition`.
1 change: 1 addition & 0 deletions cv2_tools/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../LICENSE
75 changes: 75 additions & 0 deletions cv2_tools/Management.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# MIT License
# Copyright (c) 2019 Fernando Perez
import time
import cv2

# TODO: Document ManagerCV2
class ManagerCV2():

_tries_reconnect_stream = 10

def __init__(self, video, is_stream=False, keystroke=-1, wait_key=-1, fps_limit=0):
self.video = video
self.is_stream = is_stream
self.stream = video
self.fps_limit = fps_limit

self.keystroke = keystroke
self.wait_key = wait_key

self.last_keystroke = -1
self.initial_time = None
self.final_time = None
self.count_frames = 0


def __iter__(self):
self.initial_time = time.time()
self.last_frame_time = self.initial_time
self.count_frames = 0
self.last_keystroke = -1
return self


def __next__(self):
ret, frame = self.video.read()
self.final_time = time.time()

if self.is_stream:
for i in range(ManagerCV2._tries_reconnect_stream):
ret, frame = self.video.read()
if ret:
break
if i+1 == ManagerCV2._tries_reconnect_stream:
self.end_iteration()
elif not ret:
self.end_iteration()

if self.wait_key != -1:
self.last_keystroke = cv2.waitKey(self.wait_key)
if self.last_keystroke == self.keystroke:
self.end_iteration()

self.count_frames += 1

# Here we limit the speed (if we want constant frames)
if self.fps_limit:
time_to_sleep = (1 / self.fps_limit) - (time.time() - self.last_frame_time)
if time_to_sleep > 0:
time.sleep(time_to_sleep)

self.last_frame_time = time.time()
return frame


def get_last_keystroke(self):
return self.last_keystroke


def end_iteration(self):
self.video.release()
raise StopIteration


def get_fps(self):
return round(self.count_frames / (self.final_time - self.initial_time),3)
1 change: 1 addition & 0 deletions cv2_tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
../README.md
123 changes: 123 additions & 0 deletions cv2_tools/Selection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# MIT License
# Copyright (c) 2019 Fernando Perez
import cv2

from cv2_tools.utils import *


# TODO: Document SelectorCV2
class SelectorCV2():


def __init__(self, alpha=0.9, color=(110,70,45), normalized=False, thickness=2,
filled=False, peephole=True, margin=5, closed_polygon=False):
self.zones = []
self.polygon_zones = []
self.all_tags = []
# Visual parameters
self.alpha = alpha
self.color = color
self.normalized = normalized
self.thickness = thickness
self.filled = filled
self.peephole = peephole
self.margin = margin
# Polygon
self.closed_polygon = closed_polygon


def set_properties(self, alpha=None, color=None, normalized=None,
thickness=None, filled=None, peephole=None,
margin=None):
if alpha is not None:
self.alpha = alpha
if color is not None:
self.color = color
if normalized is not None:
self.normalized = normalized
if thickness is not None:
self.thickness = thickness
if filled is not None:
self.filled = filled
if peephole is not None:
self.peephole = peephole
if margin is not None:
self.margin = margin


def add_zone(self, zone, tags=None):
self.zones.append(zone)
if tags and type(tags) is not list:
tags = [tags]
elif not tags:
tags = []
self.all_tags.append(tags)


def add_polygon(self, polygon, surrounding_box=False, tags=None):
if not polygon:
return

self.polygon_zones.append(polygon)

if surrounding_box:
min_x, min_y, max_x, max_y = polygon[0][0], polygon[0][1], 0, 0
for position in polygon:
if position[0] < min_x:
min_x = position[0]
if position[0] > max_x:
max_x = position[0]
if position[1] < min_y:
min_y = position[1]
if position[1] > max_y:
max_y = position[1]

self.zones.append((min_x, min_y, max_x, max_y))

if tags and type(tags) is not list:
tags = [tags]
elif not tags:
tags = []
self.all_tags.append(tags)


def set_range_valid_rectangles(self, origin, destination):
self.zones = self.zones[origin:destination]
self.all_tags = self.all_tags[origin:destination]


def set_valid_rectangles(self, indexes):
# This if is just for efficiency
if not indexes:
self.zones = []
self.all_tags = []
return

for i in range(len(self.zones)):
if i not in indexes:
self.zones.pop(i)
self.all_tags.pop(i)


def draw(self, frame, fx=1, fy=1, interpolation=cv2.INTER_LINEAR):
next_frame = select_multiple_zones(
frame.copy(),
self.zones,
all_tags=self.all_tags,
alpha=self.alpha,
color=self.color,
normalized=self.normalized,
thickness=self.thickness,
filled=self.filled,
peephole=self.peephole,
margin=self.margin)

next_frame = select_polygon(
next_frame,
all_vertexes=self.polygon_zones,
color=self.color,
thickness=self.thickness,
closed=self.closed_polygon
)

return cv2.resize(next_frame, (0,0), fx=fx, fy=fy, interpolation=interpolation)
7 changes: 3 additions & 4 deletions opencv_draw_tools/__init__.py → cv2_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from opencv_draw_tools.SelectZone import *
import opencv_draw_tools.tags_constraint
from cv2_tools.utils import webcam_test, get_complete_help

name = 'opencv_draw_tools'
name = 'cv2_tools'
help = '''
MIT License
Copyright (c) 2019 Fernando Perez
For more information visit: https://github.com/fernaper/opencv-draw-tools
Also you can write complete_help to view full information'''
__version__ = '1.2.0'
__version__ = '2.0.2'

complete_help = '''
{} - v{}
Expand Down
File renamed without changes.
Loading

0 comments on commit aada297

Please sign in to comment.