-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfrom_reference.py
236 lines (187 loc) · 7.03 KB
/
from_reference.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# import the necessary packages
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2
import math
# Class for point
class point:
x = 0
y = 0
# Points for Left Right Top and Bottom
plL = point()
plR = point()
plU = point()
plD = point()
def midpoint(ptA, ptB):
return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
# load the image, convert it to grayscale, and blur it slightly
cam = cv2.VideoCapture(1)
_ ,image = cam.read()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (1, 1), 0)
# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
edged = cv2.Canny(gray, 100, 200)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)
# find contours in the edge map
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
# sort the contours from left-to-right and, then initialize the
# distance colors and reference object
(cnts, _) = contours.sort_contours(cnts)
colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
(255, 0, 255))
refObj = None
pixelsPerMetric = None
# loop over the contours individually
for c in cnts:
# if the contour is not sufficiently large, ignore it
if cv2.contourArea(c) < 500:
continue
# compute the rotated bounding box of the contour
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# order the points in the contour such that they appear
# in top-left, top-right, bottom-right, and bottom-left
# order, then draw the outline of the rotated bounding
# box
box = perspective.order_points(box)
# compute the center of the bounding box
cX = np.average(box[:, 0])
cY = np.average(box[:, 1])
# if this is the first contour we are examining (i.e.,
# the left-most contour), we presume this is the
# reference object
if refObj is None:
# unpack the ordered bounding box, then compute the
# midpoint between the top-left and top-right points,
# followed by the midpoint between the top-right and
# bottom-right
(tl, tr, br, bl) = box
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# compute the Euclidean distance between the midpoints,
# then construct the reference object
D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
pixelsPerMetric = D / 2.65
refObj = (box, (cX, cY), pixelsPerMetric)
continue
# draw the contours on the image
orig = image.copy()
x,y,z = image.shape
#The X axis in white
cv2.line(orig, (0 , y/3), (x*20,y/3),(255, 255, 255), 2)
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
# stack the reference coordinates and the object coordinates
# to include the object center
refCoords = np.vstack([refObj[0], refObj[1]])
objCoords = np.vstack([box, (cX, cY)])
# Give them values
plL.x = box[0][0]
plL.y = box[0][1]
plR.x = box[1][0]
plR.y = box[1][1]
plU.x = box[2][0]
plU.y = box[2][1]
plD.x = box[3][0]
plD.y = box[3][1]
# Finding Height and width
for (x, y) in box:
cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
# unpack the ordered bounding box, then compute the midpoint
# between the top-left and top-right coordinates, followed by
# the midpoint between bottom-left and bottom-right coordinates
(tl, tr, br, bl) = box
(tltrX, tltrY) = midpoint(tl, tr)
(blbrX, blbrY) = midpoint(bl, br)
# compute the midpoint between the top-left and top-right points,
# followed by the midpoint between the top-righ and bottom-right
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# draw the midpoints on the image
cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
# draw lines between the midpoints
cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
(255, 0, 255), 2)
cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
(255, 0, 255), 2)
# compute the Euclidean distance between the midpoints
dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
# compute the size of the object
dimA = dA / pixelsPerMetric
dimB = dB / pixelsPerMetric
# Finding Angle
rp1 = point()
rp2 = point()
Angle = 0
if(dA>=dB):
rp1.x = tltrX
rp1.y = tltrY
rp2.x = blbrX
rp2.y = blbrY
else:
rp1.x = tlblX
rp1.y = tlblY
rp2.x = trbrX
rp2.y = trbrY
#Extending the line
delX = (rp2.x - rp1.x)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
delY = (rp2.y - rp1.y)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
cv2.line(orig, (int(rp1.x - delX*650), int(rp1.y - delY*650)),
(int(rp2.x + delX*650), int(rp2.y + delY*650)),(205, 0, 0), 2)
# print("( " + str(rp1.x) + " , " +
# str(rp1.y) + ") (" + str(rp2.x) + " , " + str(rp2.y) + " ) ")
# draw the object sizes on the image
cv2.putText(orig, "{:.3f}cm".format(dimB),
(int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
cv2.putText(orig, "{:.3f}cm".format(dimA),
(int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
0.65, (255, 255, 255), 2)
gradient = (rp2.y - rp1.y)*1.0/(rp2.x - rp1.x)*1.0
Angle = math.atan(gradient)
Angle = Angle*57.2958
if(Angle < 0):
Angle = Angle + 180
cv2.putText(orig, "Orientation = {:.4f}".format(Angle) + " Degree",
(300, 460), cv2.FONT_HERSHEY_SIMPLEX,0.6, (0, 255, 255), 1)
cv2.putText(orig, "White Line = X-Axis",
(30, 460), cv2.FONT_HERSHEY_SIMPLEX,0.6, (255, 255, 255), 1)
cv2.putText(orig, "Object Dimensions and Orientation Detection",
(85, 30), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)
# Results can be drawn on the frame as well as on the console
# print("Angle = " + str(Angle))
# print("("+ str(plL.x) + " , " + str(plL.y) + ")")
# print("("+ str(plR.x) + " , " + str(plR.y) + ")")
# print("("+ str(plU.x) + " , " + str(plU.y) + ")")
# print("("+ str(plD.x) + " , " + str(plD.y) + ")")
# loop over the original points
for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
# draw circles corresponding to the current points and
# connect them with a line
cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)),
color, 2)
# compute the Euclidean distance between the coordinates,
# and then convert the distance in pixels to distance in
# units
D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
(mX, mY) = midpoint((xA, yA), (xB, yB))
cv2.putText(orig, "{:.1f}cm".format(D), (int(mX), int(mY - 10)),
cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
# show the output image
cv2.imshow("Image", orig)
cv2.waitKey(0)