├── 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 | Picture Not supported by your browser!! 9 | 10 | ### distance and angle from origin of frame (0,0) 11 | 12 | Picture Not supported by your browser!! 13 | Picture Not supported by your browser!! 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 --------------------------------------------------------------------------------