-
Notifications
You must be signed in to change notification settings - Fork 2
/
opencvutility.py
162 lines (124 loc) · 4.39 KB
/
opencvutility.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
"""
.. versionadded:: 0.2
.. codeauthor:: Aman Gajendra Jain <[email protected]>
**External Dependencies**
.. hlist::
:columns: 3
- cv2
- piexif
- PIL
**Internal Dependencies**
.. hlist::
:columns: 1
- :class:`~quark.helpers.spatial`
"""
# Copyright (C) 2018 Skylark Drones
import cv2
import piexif
from PIL import Image
from spatial import is_point_inside_polygon
def rotate_jpeg(filename):
"""
Rotates and overwrites the image
:param str filename: Absolute path to the image-file
"""
image = Image.open(filename)
if 'exif' not in image.info:
return
exif_dict = piexif.load(image.info["exif"])
if piexif.ImageIFD.Orientation not in exif_dict["0th"]:
return
orientation = exif_dict["0th"].pop(piexif.ImageIFD.Orientation)
exif_bytes = piexif.dump(exif_dict)
if orientation == 2:
image = image.transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 3:
image = image.rotate(180)
elif orientation == 4:
image = image.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 5:
image = image.rotate(-90, expand=True).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 6:
image = image.rotate(-90, expand=True)
elif orientation == 7:
image = image.rotate(90, expand=True).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 8:
image = image.rotate(90, expand=True)
# TODO: Write the new orientation of the image into the EXIF metadata
image.save(filename, exif=exif_bytes)
def rect_contains(rect, pt):
"""
Checks whether a given point is inside the rectangle
:param list rect: The bounding-box to be checked for a point in it
:param tuple pt: The point to be checked
:return: if the point is inside the bounding-box or not
:rtype: bool
"""
polygon = [
(rect[0], rect[1]),
(rect[0], rect[1] + rect[3]),
(rect[0] + rect[2], rect[1] + rect[3]),
(rect[0] + rect[2], rect[1]),
]
return is_point_inside_polygon(pt, polygon)
def morphology(black_white, kernel):
"""
Performs the preliminary morphological operations to fill the holes and
remove noise i.e, it performs morphological opening and closing operations
:param numpy.ndarray black_white: The binary image on which the operation
is to be performed
:param numpy.ndarray kernel: The type of structuring-element to be used for
performing this operations
:return: Binary image, on which morphological operations were performed
"""
closing = cv2.morphologyEx(black_white, cv2.MORPH_CLOSE, kernel)
opening = cv2.morphologyEx(closing, cv2.MORPH_OPEN, kernel)
return opening
def extract_contours(black_white):
"""
Extract only "External" contours from the binary image
:param numpy.ndarray black_white: The binary image from which the contours
were to be extracted
:return: External contours
:rtype: list
"""
black_white, contours, h = cv2.findContours(
black_white, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
return contours
def check_concavity(contours):
"""
Checks for concavity for a list of contours, and appends it to the new list
if they are concave.
.. note::
The argument that specifies approximation, i.e.
"0.01 * cv2.arcLength(contour, True)" could be changed based on the
requirement.
:param list contours: Contours to be checked for concavity
:return: Contours that are concave
:rtype: list
"""
concave = []
for contour in contours:
approx = cv2.approxPolyDP(
contour, 0.01 * cv2.arcLength(contour, True), True
)
if ~cv2.isContourConvex(approx):
concave.append(contour)
return concave
def extract_roi(image, bbox):
"""
Extracts a list of region-of-interest(ROI) from the list of bounding-boxes
from a given image
:param numpy.ndarray image: The image from which ROI's were to be extracted
:param list bbox: The list of bounding-boxes, where each bounding box is
given by [x,y,w,h] i.e [x-coordinate of top-left corner, y-coordinate
of top-left corner, width of rectangle, height of rectangle]
:return: ROIs extracted from the image
:rtype: list
"""
rois = []
for x, y, w, h in bbox:
roi = image[y : y + h - 1, x : x + h - 1]
rois.append(roi)
return rois