├── README.md
├── from_origin.py
├── from_reference.py
├── git1.png
├── git2.png
├── git3.png
├── real_origin.py
└── real_time.py
/README.md:
--------------------------------------------------------------------------------
1 | # Angle-Distance
2 | Finding distance of various objects from a reference object and their angle with respect to x-axis
3 |
4 | ## What this is about
5 | [Working Video](https://www.linkedin.com/feed/update/urn:li:activity:6514920454183051264)
6 |
7 | ### distance from a reference object (coin)
8 |
9 |
10 | ### distance and angle from origin of frame (0,0)
11 |
12 |
13 |
14 |
15 | You can use this to find distance between objects as well as their ange of orientation in real time
16 | ## Dependencies
17 | First of all you will need a web cam and -
18 | 1. python
19 | 2. opencv
20 | 3. imutils
21 | 4. scipy
22 |
--------------------------------------------------------------------------------
/from_origin.py:
--------------------------------------------------------------------------------
1 | # import the necessary packages
2 | from scipy.spatial import distance as dist
3 | from imutils import perspective
4 | from imutils import contours
5 | import math
6 | import numpy as np
7 | import argparse
8 | import imutils
9 | import cv2
10 |
11 |
12 | # Class for point
13 | class point:
14 | x = 0
15 | y = 0
16 |
17 | # Points for Left Right Top and Bottom
18 | plL = point()
19 | plR = point()
20 | plU = point()
21 | plD = point()
22 |
23 | # For finding midpoint
24 | def midpoint(ptA, ptB):
25 | return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
26 |
27 | # load the image, convert it to grayscale, and blur it slightly
28 | cam = cv2.VideoCapture(0)
29 | _ ,image = cam.read()
30 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
31 | gray = cv2.GaussianBlur(gray, (7, 7), 0)
32 |
33 | # perform edge detection, then perform a dilation + erosion to
34 | # close gaps in between object edges
35 | edged = cv2.Canny(gray, 50, 100)
36 | edged = cv2.dilate(edged, None, iterations=1)
37 | edged = cv2.erode(edged, None, iterations=1)
38 |
39 | # find contours in the edge map
40 | cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
41 | cv2.CHAIN_APPROX_SIMPLE)
42 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
43 |
44 | # sort the contours from left-to-right and, then initialize the
45 | # distance colors and reference object
46 | (cnts, _) = contours.sort_contours(cnts)
47 | colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
48 | (255, 0, 255))
49 | refObj = None
50 | pixelsPerMetric = None
51 |
52 | # loop over the contours individually
53 | for c in cnts:
54 | # if the contour is not sufficiently large, ignore it
55 | if cv2.contourArea(c) < 100:
56 | continue
57 |
58 | # compute the rotated bounding box of the contour
59 | box = cv2.minAreaRect(c)
60 | box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
61 | box = np.array(box, dtype="int")
62 |
63 | # order the points in the contour such that they appear
64 | # in top-left, top-right, bottom-right, and bottom-left
65 | # order, then draw the outline of the rotated bounding
66 | # box
67 | box = perspective.order_points(box)
68 |
69 | # compute the center of the bounding box
70 | cX = np.average(box[:, 0])
71 | cY = np.average(box[:, 1])
72 |
73 | # if reference object is not set then we presume
74 | # the origin i.e. the (0,0) of the camera frame
75 | # as reference point
76 | if refObj is None:
77 | box1 = np.zeros(box.shape)
78 | rcX = 0
79 | rcY = 0
80 | refObj = (box1, (rcX, rcY), 27.6)
81 |
82 | # draw the contours on the image
83 | orig = image.copy()
84 | cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
85 | cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
86 |
87 | # stack the reference coordinates and the object coordinates
88 | # to include the object center
89 | refCoords = np.vstack([refObj[0], refObj[1]])
90 | objCoords = np.vstack([box, (cX, cY)])
91 |
92 | # Give them values
93 | plL.x = box[0][0]
94 | plL.y = box[0][1]
95 |
96 | plR.x = box[1][0]
97 | plR.y = box[1][1]
98 |
99 | plU.x = box[2][0]
100 | plU.y = box[2][1]
101 |
102 | plD.x = box[3][0]
103 | plD.y = box[3][1]
104 |
105 | # Finding Height and width
106 | for (x, y) in box:
107 | cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
108 |
109 | # unpack the ordered bounding box, then compute the midpoint
110 | # between the top-left and top-right coordinates, followed by
111 | # the midpoint between bottom-left and bottom-right coordinates
112 | (tl, tr, br, bl) = box
113 | (tltrX, tltrY) = midpoint(tl, tr)
114 | (blbrX, blbrY) = midpoint(bl, br)
115 |
116 | # compute the midpoint between the top-left and top-right points,
117 | # followed by the midpoint between the top-righ and bottom-right
118 | (tlblX, tlblY) = midpoint(tl, bl)
119 | (trbrX, trbrY) = midpoint(tr, br)
120 |
121 | # draw the midpoints on the image
122 | cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
123 | cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
124 | cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
125 | cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
126 |
127 | # draw lines between the midpoints
128 | cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
129 | (255, 0, 255), 2)
130 | cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
131 | (255, 0, 255), 2)
132 |
133 | # compute the Euclidean distance between the midpoints
134 | dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
135 | dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
136 |
137 | # if the pixels per metric has not been initialized, then
138 | # compute it as the ratio of pixels to supplied metric
139 | # (in this case, inches)
140 | if pixelsPerMetric is None:
141 | pixelsPerMetric = 27.6 # This ratio needs to be set manually
142 |
143 | # compute the size of the object
144 | dimA = dA / pixelsPerMetric
145 | dimB = dB / pixelsPerMetric
146 |
147 | # draw the object sizes on the image
148 | cv2.putText(orig, "{:.1f}in".format(dimA),
149 | (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
150 | 0.65, (255, 255, 255), 2)
151 | cv2.putText(orig, "{:.1f}in".format(dimB),
152 | (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
153 | 0.65, (255, 255, 255), 2)
154 |
155 | # Finding Angle
156 | rp1 = point()
157 | rp2 = point()
158 |
159 | Angle = 0
160 |
161 | if(dA>=dB):
162 | rp1.x = tltrX
163 | rp1.y = tltrY
164 | rp2.x = blbrX
165 | rp2.y = blbrY
166 | else:
167 | rp1.x = tlblX
168 | rp1.y = tlblY
169 | rp2.x = trbrX
170 | rp2.y = trbrY
171 |
172 | print("( " + str(rp1.x) + " , " +
173 | str(rp1.y) + ") (" + str(rp2.x) + " , " + str(rp2.y) + " ) ")
174 |
175 | gradient = (rp2.y - rp1.y)*1.0/(rp2.x - rp1.x)*1.0
176 | Angle = math.atan(gradient)
177 | Angle = Angle*57.2958
178 |
179 | if(Angle < 0):
180 | Angle = Angle + 180
181 |
182 | # Results of calculations can be printed in console or you can
183 | # write them on the frame itself
184 | print("Angle = " + str(Angle))
185 | print("("+ str(plL.x) + " , " + str(plL.y) + ")")
186 | print("("+ str(plR.x) + " , " + str(plR.y) + ")")
187 | print("("+ str(plU.x) + " , " + str(plU.y) + ")")
188 | print("("+ str(plD.x) + " , " + str(plD.y) + ")")
189 | print("Height = " + str(height/27.6))
190 | print("width = " + str(width/27.6))
191 | print("Loss = " + str(abs(diag1 - diag2)))
192 |
193 | # loop over the original points
194 | for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
195 | # draw circles corresponding to the current points and
196 | cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
197 | # connect them with a line
198 | cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
199 | cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)), color, 2)
200 |
201 | # compute the Euclidean distance between the coordinates,
202 | # and then convert the distance in pixels to distance in
203 | # units
204 | D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
205 | (mX, mY) = midpoint((xA, yA), (xB, yB))
206 | cv2.putText(orig, "{:.1f}cm".format(D), (int(mX), int(mY - 10)),
207 | cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
208 |
209 | # show the output image
210 | cv2.imshow("Image", orig)
211 |
212 | cv2.waitKey(0)
213 |
--------------------------------------------------------------------------------
/from_reference.py:
--------------------------------------------------------------------------------
1 | # import the necessary packages
2 | from scipy.spatial import distance as dist
3 | from imutils import perspective
4 | from imutils import contours
5 | import numpy as np
6 | import argparse
7 | import imutils
8 | import cv2
9 | import math
10 |
11 | # Class for point
12 | class point:
13 | x = 0
14 | y = 0
15 |
16 | # Points for Left Right Top and Bottom
17 | plL = point()
18 | plR = point()
19 | plU = point()
20 | plD = point()
21 |
22 | def midpoint(ptA, ptB):
23 | return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
24 |
25 | # load the image, convert it to grayscale, and blur it slightly
26 | cam = cv2.VideoCapture(1)
27 | _ ,image = cam.read()
28 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
29 | gray = cv2.GaussianBlur(gray, (1, 1), 0)
30 |
31 | # perform edge detection, then perform a dilation + erosion to
32 | # close gaps in between object edges
33 | edged = cv2.Canny(gray, 100, 200)
34 | edged = cv2.dilate(edged, None, iterations=1)
35 | edged = cv2.erode(edged, None, iterations=1)
36 |
37 | # find contours in the edge map
38 | cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
39 | cv2.CHAIN_APPROX_SIMPLE)
40 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
41 |
42 | # sort the contours from left-to-right and, then initialize the
43 | # distance colors and reference object
44 | (cnts, _) = contours.sort_contours(cnts)
45 | colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
46 | (255, 0, 255))
47 |
48 | refObj = None
49 | pixelsPerMetric = None
50 |
51 | # loop over the contours individually
52 | for c in cnts:
53 | # if the contour is not sufficiently large, ignore it
54 | if cv2.contourArea(c) < 500:
55 | continue
56 |
57 | # compute the rotated bounding box of the contour
58 | box = cv2.minAreaRect(c)
59 | box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
60 | box = np.array(box, dtype="int")
61 |
62 | # order the points in the contour such that they appear
63 | # in top-left, top-right, bottom-right, and bottom-left
64 | # order, then draw the outline of the rotated bounding
65 | # box
66 | box = perspective.order_points(box)
67 |
68 | # compute the center of the bounding box
69 | cX = np.average(box[:, 0])
70 | cY = np.average(box[:, 1])
71 |
72 | # if this is the first contour we are examining (i.e.,
73 | # the left-most contour), we presume this is the
74 | # reference object
75 | if refObj is None:
76 | # unpack the ordered bounding box, then compute the
77 | # midpoint between the top-left and top-right points,
78 | # followed by the midpoint between the top-right and
79 | # bottom-right
80 | (tl, tr, br, bl) = box
81 | (tlblX, tlblY) = midpoint(tl, bl)
82 | (trbrX, trbrY) = midpoint(tr, br)
83 |
84 | # compute the Euclidean distance between the midpoints,
85 | # then construct the reference object
86 | D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
87 |
88 | pixelsPerMetric = D / 2.65
89 | refObj = (box, (cX, cY), pixelsPerMetric)
90 | continue
91 |
92 | # draw the contours on the image
93 | orig = image.copy()
94 |
95 | x,y,z = image.shape
96 |
97 | #The X axis in white
98 | cv2.line(orig, (0 , y/3), (x*20,y/3),(255, 255, 255), 2)
99 |
100 | cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
101 | cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
102 |
103 | # stack the reference coordinates and the object coordinates
104 | # to include the object center
105 | refCoords = np.vstack([refObj[0], refObj[1]])
106 | objCoords = np.vstack([box, (cX, cY)])
107 |
108 | # Give them values
109 | plL.x = box[0][0]
110 | plL.y = box[0][1]
111 |
112 | plR.x = box[1][0]
113 | plR.y = box[1][1]
114 |
115 | plU.x = box[2][0]
116 | plU.y = box[2][1]
117 |
118 | plD.x = box[3][0]
119 | plD.y = box[3][1]
120 |
121 | # Finding Height and width
122 | for (x, y) in box:
123 | cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
124 |
125 | # unpack the ordered bounding box, then compute the midpoint
126 | # between the top-left and top-right coordinates, followed by
127 | # the midpoint between bottom-left and bottom-right coordinates
128 | (tl, tr, br, bl) = box
129 | (tltrX, tltrY) = midpoint(tl, tr)
130 | (blbrX, blbrY) = midpoint(bl, br)
131 |
132 | # compute the midpoint between the top-left and top-right points,
133 | # followed by the midpoint between the top-righ and bottom-right
134 | (tlblX, tlblY) = midpoint(tl, bl)
135 | (trbrX, trbrY) = midpoint(tr, br)
136 |
137 | # draw the midpoints on the image
138 | cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
139 | cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
140 | cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
141 | cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
142 |
143 | # draw lines between the midpoints
144 | cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
145 | (255, 0, 255), 2)
146 | cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
147 | (255, 0, 255), 2)
148 |
149 | # compute the Euclidean distance between the midpoints
150 | dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
151 | dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
152 |
153 | # compute the size of the object
154 | dimA = dA / pixelsPerMetric
155 | dimB = dB / pixelsPerMetric
156 |
157 | # Finding Angle
158 | rp1 = point()
159 | rp2 = point()
160 |
161 | Angle = 0
162 |
163 | if(dA>=dB):
164 | rp1.x = tltrX
165 | rp1.y = tltrY
166 | rp2.x = blbrX
167 | rp2.y = blbrY
168 | else:
169 | rp1.x = tlblX
170 | rp1.y = tlblY
171 | rp2.x = trbrX
172 | rp2.y = trbrY
173 |
174 | #Extending the line
175 | delX = (rp2.x - rp1.x)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
176 | delY = (rp2.y - rp1.y)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
177 |
178 | cv2.line(orig, (int(rp1.x - delX*650), int(rp1.y - delY*650)),
179 | (int(rp2.x + delX*650), int(rp2.y + delY*650)),(205, 0, 0), 2)
180 |
181 | # print("( " + str(rp1.x) + " , " +
182 | # str(rp1.y) + ") (" + str(rp2.x) + " , " + str(rp2.y) + " ) ")
183 |
184 | # draw the object sizes on the image
185 | cv2.putText(orig, "{:.3f}cm".format(dimB),
186 | (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
187 | 0.65, (255, 255, 255), 2)
188 | cv2.putText(orig, "{:.3f}cm".format(dimA),
189 | (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
190 | 0.65, (255, 255, 255), 2)
191 |
192 | gradient = (rp2.y - rp1.y)*1.0/(rp2.x - rp1.x)*1.0
193 | Angle = math.atan(gradient)
194 | Angle = Angle*57.2958
195 |
196 | if(Angle < 0):
197 | Angle = Angle + 180
198 |
199 | cv2.putText(orig, "Orientation = {:.4f}".format(Angle) + " Degree",
200 | (300, 460), cv2.FONT_HERSHEY_SIMPLEX,0.6, (0, 255, 255), 1)
201 |
202 |
203 | cv2.putText(orig, "White Line = X-Axis",
204 | (30, 460), cv2.FONT_HERSHEY_SIMPLEX,0.6, (255, 255, 255), 1)
205 |
206 |
207 | cv2.putText(orig, "Object Dimensions and Orientation Detection",
208 | (85, 30), cv2.FONT_HERSHEY_SIMPLEX,0.65, (255, 255, 255), 2)
209 |
210 | # Results can be drawn on the frame as well as on the console
211 | # print("Angle = " + str(Angle))
212 | # print("("+ str(plL.x) + " , " + str(plL.y) + ")")
213 | # print("("+ str(plR.x) + " , " + str(plR.y) + ")")
214 | # print("("+ str(plU.x) + " , " + str(plU.y) + ")")
215 | # print("("+ str(plD.x) + " , " + str(plD.y) + ")")
216 |
217 | # loop over the original points
218 | for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
219 | # draw circles corresponding to the current points and
220 | # connect them with a line
221 | cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
222 | cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
223 | cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)),
224 | color, 2)
225 |
226 | # compute the Euclidean distance between the coordinates,
227 | # and then convert the distance in pixels to distance in
228 | # units
229 | D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
230 | (mX, mY) = midpoint((xA, yA), (xB, yB))
231 | cv2.putText(orig, "{:.1f}cm".format(D), (int(mX), int(mY - 10)),
232 | cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
233 |
234 | # show the output image
235 | cv2.imshow("Image", orig)
236 | cv2.waitKey(0)
237 |
--------------------------------------------------------------------------------
/git1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Angle-Distance/af7b839790afcc5c6b36136ae423b77f25039621/git1.png
--------------------------------------------------------------------------------
/git2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Angle-Distance/af7b839790afcc5c6b36136ae423b77f25039621/git2.png
--------------------------------------------------------------------------------
/git3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevashishPrasad/Angle-Distance/af7b839790afcc5c6b36136ae423b77f25039621/git3.png
--------------------------------------------------------------------------------
/real_origin.py:
--------------------------------------------------------------------------------
1 | # import the necessary packages
2 | from scipy.spatial import distance as dist
3 | from imutils import perspective
4 | from imutils import contours
5 | import numpy as np
6 | import argparse
7 | import imutils
8 | import cv2
9 | import math
10 |
11 | # Class for point
12 | class point:
13 | x = 0
14 | y = 0
15 |
16 | # Points for Left Right Top and Bottom
17 | plL = point()
18 | plR = point()
19 | plU = point()
20 | plD = point()
21 |
22 | def midpoint(ptA, ptB):
23 | return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
24 |
25 | # Starting to capture video feed from the webcam
26 | cam = cv2.VideoCapture(1)
27 |
28 | while True:
29 |
30 | # load the image, convert it to grayscale, and blur it slightly
31 | _ ,image = cam.read()
32 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
33 | gray = cv2.GaussianBlur(gray, (7, 7), 0)
34 |
35 | # perform edge detection, then perform a dilation + erosion to
36 | # close gaps in between object edges
37 | edged = cv2.Canny(gray, 50, 100)
38 | edged = cv2.dilate(edged, None, iterations=1)
39 | edged = cv2.erode(edged, None, iterations=1)
40 |
41 | # find contours in the edge map
42 | cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
43 | cv2.CHAIN_APPROX_SIMPLE)
44 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
45 |
46 | # sort the contours from left-to-right and, then initialize the
47 | # distance colors and reference object
48 | (cnts, _) = contours.sort_contours(cnts)
49 | colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
50 | (255, 0, 255))
51 | refObj = None
52 | pixelsPerMetric = None
53 |
54 | # loop over the contours individually
55 | for c in cnts:
56 | # if the contour is not sufficiently large, ignore it
57 | if cv2.contourArea(c) < 100:
58 | continue
59 |
60 | # compute the rotated bounding box of the contour
61 | box = cv2.minAreaRect(c)
62 | box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
63 | box = np.array(box, dtype="int")
64 |
65 | # order the points in the contour such that they appear
66 | # in top-left, top-right, bottom-right, and bottom-left
67 | # order, then draw the outline of the rotated bounding
68 | # box
69 | box = perspective.order_points(box)
70 |
71 | # compute the center of the bounding box
72 | cX = np.average(box[:, 0])
73 | cY = np.average(box[:, 1])
74 |
75 | # if this is the first contour we are examining (i.e.,
76 | # the left-most contour), we presume this is the
77 | # reference object
78 |
79 | if refObj is None:
80 |
81 | box1 = np.zeros(box.shape)
82 |
83 | # compute the Euclidean distance between the midpoints,
84 | # then construct the reference object
85 |
86 | rcX = 0
87 | rcY = 0
88 | refObj = (box1, (rcX, rcY), 27.6)
89 |
90 | # pixels per metric ratio was calculated manually as
91 | # = total no. of pixels on x axis of frame/ width of frame in cm
92 | # i get total no of pixels on X axis using
93 | # x,y,c = image.shape
94 |
95 | # draw the contours on the image
96 | orig = image.copy()
97 | cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
98 | cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
99 |
100 | # stack the reference coordinates and the object coordinates
101 | # to include the object center
102 | refCoords = np.vstack([refObj[0], refObj[1]])
103 | objCoords = np.vstack([box, (cX, cY)])
104 |
105 | # Give the points values
106 | plL.x = box[0][0]
107 | plL.y = box[0][1]
108 |
109 | plR.x = box[1][0]
110 | plR.y = box[1][1]
111 |
112 | plU.x = box[2][0]
113 | plU.y = box[2][1]
114 |
115 | plD.x = box[3][0]
116 | plD.y = box[3][1]
117 |
118 | # Finding Height and width
119 | for (x, y) in box:
120 | cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
121 |
122 | # unpack the ordered bounding box, then compute the midpoint
123 | # between the top-left and top-right coordinates, followed by
124 | # the midpoint between bottom-left and bottom-right coordinates
125 | (tl, tr, br, bl) = box
126 | (tltrX, tltrY) = midpoint(tl, tr)
127 | (blbrX, blbrY) = midpoint(bl, br)
128 |
129 | # compute the midpoint between the top-left and top-right points,
130 | # followed by the midpoint between the top-righ and bottom-right
131 | (tlblX, tlblY) = midpoint(tl, bl)
132 | (trbrX, trbrY) = midpoint(tr, br)
133 |
134 | # draw the midpoints on the image
135 | cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
136 | cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
137 | cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
138 | cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
139 |
140 | # draw lines between the midpoints
141 | cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
142 | (255, 0, 255), 2)
143 | cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
144 | (255, 0, 255), 2)
145 |
146 | # compute the Euclidean distance between the midpoints
147 | dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
148 | dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
149 |
150 | # if the pixels per metric has not been initialized, then
151 | # compute it as the ratio of pixels to supplied metric
152 | # (in this case, inches)
153 | if pixelsPerMetric is None:
154 | pixelsPerMetric = 27.6
155 |
156 | # compute the size of the object
157 | dimA = dA / pixelsPerMetric
158 | dimB = dB / pixelsPerMetric
159 |
160 | # draw the object sizes on the image
161 | cv2.putText(orig, "{:.1f}cm".format(dimA),
162 | (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
163 | 0.65, (255, 255, 255), 2)
164 | cv2.putText(orig, "{:.1f}cm".format(dimB),
165 | (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
166 | 0.65, (255, 255, 255), 2)
167 |
168 | # Finding Angle of the length (the larger side) and not of the width
169 |
170 | rp1 = point()
171 | rp2 = point()
172 |
173 | Angle = 0
174 |
175 | if(dA>=dB):
176 | rp1.x = tltrX
177 | rp1.y = tltrY
178 | rp2.x = blbrX
179 | rp2.y = blbrY
180 | else:
181 | rp1.x = tlblX
182 | rp1.y = tlblY
183 | rp2.x = trbrX
184 | rp2.y = trbrY
185 |
186 | # Extending the line of which angle is to be calculated
187 |
188 | delX = (rp2.x - rp1.x)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
189 | delY = (rp2.y - rp1.y)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
190 |
191 | cv2.line(orig, (int(rp1.x - delX*250), int(rp1.y - delY*250)),
192 | (int(rp2.x + delX*250), int(rp2.y + delY*250)),(205, 0, 0), 2)
193 |
194 | x,y,z = image.shape
195 |
196 | # The x axis, makes it easy to see the angle
197 | cv2.line(orig, (0 , y/3), (x*20,y/3),
198 | (0, 0, 0), 2)
199 |
200 | gradient = (rp2.y - rp1.y)*1.0/(rp2.x - rp1.x)*1.0
201 | Angle = math.atan(gradient)
202 | Angle = Angle*57.2958
203 |
204 | if(Angle < 0):
205 | Angle = Angle + 180
206 |
207 | cv2.putText(orig, "{:.4f}".format(Angle) + " Degrees",
208 | (330, 460), cv2.FONT_HERSHEY_SIMPLEX,
209 | 0.75, (0, 255, 255), 2)
210 |
211 | # loop over the original points
212 | for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
213 | # draw circles corresponding to the current points and
214 | cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
215 | # connect them with a line
216 | cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
217 | cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)), color, 2)
218 |
219 | # compute the Euclidean distance between the coordinates,
220 | # and then convert the distance in pixels to distance in
221 | # units
222 | D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
223 | (mX, mY) = midpoint((xA, yA), (xB, yB))
224 | cv2.putText(orig, "{:.1f}cm".format(D), (int(mX), int(mY - 10)),
225 | cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
226 |
227 | # show the output image
228 | cv2.imshow("Image", orig)
229 |
230 | if cv2.waitKey(1) & 0xFF == ord('q'):
231 | break
--------------------------------------------------------------------------------
/real_time.py:
--------------------------------------------------------------------------------
1 | # import the necessary packages
2 |
3 | from scipy.spatial import distance as dist
4 | from imutils import perspective
5 | from imutils import contours
6 | import numpy as np
7 | import argparse
8 | import imutils
9 | import cv2
10 | import math
11 |
12 | #***************** Class for point *************************
13 | class point:
14 | x = 0
15 | y = 0
16 | #**********************************************************************
17 |
18 | #------------ Points for Left Right Top and Bottom --------------
19 | plL = point()
20 | plR = point()
21 | plU = point()
22 | plD = point()
23 | #---------- Ends Points for Left Right Top and Bottom ----------------
24 |
25 | def midpoint(ptA, ptB):
26 | return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)
27 |
28 | #^^^^ You can use following code to take values from command line ^^^^^
29 | """# construct the argument parse and parse the arguments
30 | ap = argparse.ArgumentParser()
31 | ap.add_argument("-i", "--image", required=True,
32 | help="path to the input image")
33 | ap.add_argument("-w", "--width", type=float, required=True,
34 | help="width of the left-most object in the image (in inches)")
35 | args = vars(ap.parse_args())"""
36 |
37 | # load the image, convert it to grayscale, and blur it slightly
38 | cam = cv2.VideoCapture(1)
39 |
40 | while True:
41 |
42 | _ ,image = cam.read()
43 |
44 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
45 | gray = cv2.GaussianBlur(gray, (7, 7), 0)
46 |
47 | # perform edge detection, then perform a dilation + erosion to
48 | # close gaps in between object edges
49 | edged = cv2.Canny(gray, 50, 100)
50 | edged = cv2.dilate(edged, None, iterations=1)
51 | edged = cv2.erode(edged, None, iterations=1)
52 |
53 | # find contours in the edge map
54 | cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
55 | cv2.CHAIN_APPROX_SIMPLE)
56 | cnts = cnts[0] if imutils.is_cv2() else cnts[1]
57 |
58 | # sort the contours from left-to-right and, then initialize the
59 | # distance colors and reference object
60 | (cnts, _) = contours.sort_contours(cnts)
61 | colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
62 | (255, 0, 255))
63 | refObj = None
64 | pixelsPerMetric = None
65 |
66 | # loop over the contours individually
67 | for c in cnts:
68 | # if the contour is not sufficiently large, ignore it
69 | if cv2.contourArea(c) < 100:
70 | continue
71 |
72 | # compute the rotated bounding box of the contour
73 | box = cv2.minAreaRect(c)
74 | box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
75 | box = np.array(box, dtype="int")
76 |
77 | # order the points in the contour such that they appear
78 | # in top-left, top-right, bottom-right, and bottom-left
79 | # order, then draw the outline of the rotated bounding
80 | # box
81 | box = perspective.order_points(box)
82 |
83 | # compute the center of the bounding box
84 | cX = np.average(box[:, 0])
85 | cY = np.average(box[:, 1])
86 |
87 | # if this is the first contour we are examining (i.e.,
88 | # the left-most contour), we presume this is the
89 | # reference object
90 | if refObj is None:
91 | # unpack the ordered bounding box, then compute the
92 | # midpoint between the top-left and top-right points,
93 | # followed by the midpoint between the top-right and
94 | # bottom-right
95 | (tl, tr, br, bl) = box
96 | (tlblX, tlblY) = midpoint(tl, bl)
97 | (trbrX, trbrY) = midpoint(tr, br)
98 |
99 | # compute the Euclidean distance between the midpoints,
100 | # then construct the reference object
101 | D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
102 | refObj = (box, (cX, cY), D / 2.8)
103 | continue
104 |
105 | # draw the contours on the image
106 | orig = image.copy()
107 | cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
108 | cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
109 |
110 | # stack the reference coordinates and the object coordinates
111 | # to include the object center
112 | refCoords = np.vstack([refObj[0], refObj[1]])
113 | objCoords = np.vstack([box, (cX, cY)])
114 |
115 | ################# Give them values ########################
116 |
117 | plL.x = box[0][0]
118 | plL.y = box[0][1]
119 |
120 | plR.x = box[1][0]
121 | plR.y = box[1][1]
122 |
123 | plU.x = box[2][0]
124 | plU.y = box[2][1]
125 |
126 | plD.x = box[3][0]
127 | plD.y = box[3][1]
128 |
129 | ################# end ########################
130 |
131 |
132 |
133 | #++++++++++++++++ Finding Height and width +++++++++++++++++++
134 |
135 | for (x, y) in box:
136 | cv2.circle(orig, (int(x), int(y)), 5, (0, 0, 255), -1)
137 |
138 | # unpack the ordered bounding box, then compute the midpoint
139 | # between the top-left and top-right coordinates, followed by
140 | # the midpoint between bottom-left and bottom-right coordinates
141 | (tl, tr, br, bl) = box
142 | (tltrX, tltrY) = midpoint(tl, tr)
143 | (blbrX, blbrY) = midpoint(bl, br)
144 |
145 | # compute the midpoint between the top-left and top-right points,
146 | # followed by the midpoint between the top-righ and bottom-right
147 | (tlblX, tlblY) = midpoint(tl, bl)
148 | (trbrX, trbrY) = midpoint(tr, br)
149 |
150 | # draw the midpoints on the image
151 | cv2.circle(orig, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
152 | cv2.circle(orig, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
153 | cv2.circle(orig, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
154 | cv2.circle(orig, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)
155 |
156 | # draw lines between the midpoints
157 | cv2.line(orig, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
158 | (255, 0, 255), 2)
159 | cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
160 | (255, 0, 255), 2)
161 |
162 | # compute the Euclidean distance between the midpoints
163 | dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
164 | dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
165 |
166 | # if the pixels per metric has not been initialized, then
167 | # compute it as the ratio of pixels to supplied metric
168 | # (in this case, inches)
169 | if pixelsPerMetric is None:
170 | pixelsPerMetric = 27.6
171 |
172 | # compute the size of the object
173 | dimA = dA / pixelsPerMetric
174 | dimB = dB / pixelsPerMetric
175 |
176 | # draw the object sizes on the image
177 | cv2.putText(orig, "{:.1f}cm".format(dimA),
178 | (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
179 | 0.65, (255, 255, 255), 2)
180 | cv2.putText(orig, "{:.1f}cm".format(dimB),
181 | (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
182 | 0.65, (255, 255, 255), 2)
183 |
184 | #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
185 |
186 |
187 | #%%%%%%%%%%%%%%%%%%%%%%%%% Finding Angle %%%%%%%%%%%%%%%%%%%%%%%%%%
188 |
189 | rp1 = point()
190 | rp2 = point()
191 |
192 | Angle = 0
193 |
194 | if(dA>=dB):
195 | rp1.x = tltrX
196 | rp1.y = tltrY
197 | rp2.x = blbrX
198 | rp2.y = blbrY
199 | else:
200 | rp1.x = tlblX
201 | rp1.y = tlblY
202 | rp2.x = trbrX
203 | rp2.y = trbrY
204 |
205 | #Extending the line
206 |
207 | delX = (rp2.x - rp1.x)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
208 | delY = (rp2.y - rp1.y)/(math.sqrt(((rp2.x-rp1.x) ** 2)+((rp2.y-rp1.y) ** 2)))
209 |
210 | cv2.line(orig, (int(rp1.x - delX*350), int(rp1.y - delY*350)),
211 | (int(rp2.x + delX*250), int(rp2.y + delY*250)),(205, 0, 0), 2)
212 |
213 | x,y,z = image.shape
214 |
215 | #The X axis in black
216 | cv2.line(orig, (0 , y/3), (x*20,y/3),(0, 0, 0), 2)
217 |
218 | gradient = (rp2.y - rp1.y)*1.0/(rp2.x - rp1.x)*1.0
219 | Angle = math.atan(gradient)
220 | Angle = Angle*57.2958
221 |
222 | if(Angle < 0):
223 | Angle = Angle + 180
224 |
225 | cv2.putText(orig, "{:.4f}".format(Angle) + " Degrees",
226 | (330, 460), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 255, 255), 2)
227 |
228 | #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229 |
230 | # loop over the original points
231 | for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
232 | # draw circles corresponding to the current points and
233 | # connect them with a line
234 | cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
235 | cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
236 | cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)),
237 | color, 2)
238 |
239 | # compute the Euclidean distance between the coordinates,
240 | # and then convert the distance in pixels to distance in
241 | # units
242 | D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
243 | (mX, mY) = midpoint((xA, yA), (xB, yB))
244 | cv2.putText(orig, "{:.1f}cm".format(D), (int(mX), int(mY - 10)),
245 | cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
246 |
247 | # show the output image
248 | cv2.imshow("Image", orig)
249 |
250 | if cv2.waitKey(1) & 0xFF == ord('q'):
251 | break
--------------------------------------------------------------------------------