-
-
Save benmarwick/2b250d8ef3dbe36f817fbe2bf14aaa55 to your computer and use it in GitHub Desktop.
| # in a terminal | |
| # python -m pip install --user opencv-contrib-python numpy scipy matplotlib ipython jupyter pandas sympy nose | |
| import cv2 | |
| import pandas as pd | |
| import numpy as np | |
| import imutils | |
| from scipy.spatial import distance as dist | |
| from imutils import perspective | |
| from imutils import contours | |
| # using cam built-in to computer | |
| videocapture=cv2.VideoCapture(0) | |
| # using IP camera address from my mobile phone, with Android 'IP Webcam' app over WiFi | |
| # videocapture=cv2.VideoCapture("http://xxx.xxx.xxx.xxx:8080/video") | |
| def safe_div(x,y): # so we don't crash so often | |
| if y==0: return 0 | |
| return x/y | |
| def nothing(x): # for trackbar | |
| pass | |
| def rescale_frame(frame, percent=25): # make the video windows a bit smaller | |
| width = int(frame.shape[1] * percent/ 100) | |
| height = int(frame.shape[0] * percent/ 100) | |
| dim = (width, height) | |
| return cv2.resize(frame, dim, interpolation=cv2.INTER_AREA) | |
| if not videocapture.isOpened(): | |
| print("can't open camera") | |
| exit() | |
| windowName="Webcam Live video feed" | |
| cv2.namedWindow(windowName) | |
| # Sliders to adjust image | |
| # https://medium.com/@manivannan_data/set-trackbar-on-image-using-opencv-python-58c57fbee1ee | |
| cv2.createTrackbar("threshold", windowName, 75, 255, nothing) | |
| cv2.createTrackbar("kernel", windowName, 5, 30, nothing) | |
| cv2.createTrackbar("iterations", windowName, 1, 10, nothing) | |
| showLive=True | |
| while(showLive): | |
| ret, frame=videocapture.read() | |
| frame_resize = rescale_frame(frame) | |
| if not ret: | |
| print("cannot capture the frame") | |
| exit() | |
| thresh= cv2.getTrackbarPos("threshold", windowName) | |
| ret,thresh1 = cv2.threshold(frame_resize,thresh,255,cv2.THRESH_BINARY) | |
| kern=cv2.getTrackbarPos("kernel", windowName) | |
| kernel = np.ones((kern,kern),np.uint8) # square image kernel used for erosion | |
| itera=cv2.getTrackbarPos("iterations", windowName) | |
| dilation = cv2.dilate(thresh1, kernel, iterations=itera) | |
| erosion = cv2.erode(dilation,kernel,iterations = itera) # refines all edges in the binary image | |
| opening = cv2.morphologyEx(erosion, cv2.MORPH_OPEN, kernel) | |
| closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel) | |
| closing = cv2.cvtColor(closing,cv2.COLOR_BGR2GRAY) | |
| _,contours,hierarchy = cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) # find contours with simple approximation cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE | |
| closing = cv2.cvtColor(closing,cv2.COLOR_GRAY2RGB) | |
| cv2.drawContours(closing, contours, -1, (128,255,0), 1) | |
| # focus on only the largest outline by area | |
| areas = [] #list to hold all areas | |
| for contour in contours: | |
| ar = cv2.contourArea(contour) | |
| areas.append(ar) | |
| max_area = max(areas) | |
| max_area_index = areas.index(max_area) # index of the list element with largest area | |
| cnt = contours[max_area_index - 1] # largest area contour is usually the viewing window itself, why? | |
| cv2.drawContours(closing, [cnt], 0, (0,0,255), 1) | |
| def midpoint(ptA, ptB): | |
| return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5) | |
| # compute the rotated bounding box of the contour | |
| orig = frame_resize.copy() | |
| box = cv2.minAreaRect(cnt) | |
| 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) | |
| cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 1) | |
| # loop over the original points and draw them | |
| 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), 1) | |
| cv2.line(orig, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),(255, 0, 255), 1) | |
| cv2.drawContours(orig, [cnt], 0, (0,0,255), 1) | |
| # 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 | |
| pixelsPerMetric = 1 # more to do here to get actual measurements that have meaning in the real world | |
| dimA = dA / pixelsPerMetric | |
| dimB = dB / pixelsPerMetric | |
| # draw the object sizes on the image | |
| cv2.putText(orig, "{:.1f}mm".format(dimA), (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2) | |
| cv2.putText(orig, "{:.1f}mm".format(dimB), (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 255), 2) | |
| # compute the center of the contour | |
| M = cv2.moments(cnt) | |
| cX = int(safe_div(M["m10"],M["m00"])) | |
| cY = int(safe_div(M["m01"],M["m00"])) | |
| # draw the contour and center of the shape on the image | |
| cv2.circle(orig, (cX, cY), 5, (255, 255, 255), -1) | |
| cv2.putText(orig, "center", (cX - 20, cY - 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 2) | |
| cv2.imshow(windowName, orig) | |
| cv2.imshow('', closing) | |
| if cv2.waitKey(30)>=0: | |
| showLive=False | |
| videocapture.release() | |
| cv2.destroyAllWindows() |
hello can any one tell me why after doing the morphology operations the closing binary image is converted in to grayscale and then into RGB
Hello,
I keep getting the error: "ValueError: max() arg is an empty sequence". Anyone have a solution?
Nice! Pretty handy!
I got this error, anyone know how to fix it?
Traceback (most recent call last):
File "C:\Users\rapto\Desktop\live video tracking.py", line 69, in
_,contours,hierarchy = cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) # find contours with simple approximation cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE
ValueError: not enough values to unpack (expected 3, got 2)
[Finished in 5.7s]
line 69, erase the first two characters ( _, )
Regards!
Hi
I got this error.
thresh= cv2.getTrackbarPos("threshold", windowName)
cv2.error: OpenCV(4.3.0) /io/opencv/modules/highgui/src/window_QT.cpp:462: error: (-27:Null pointer) NULL window handler in function 'icvFindTrackBarByName'
Can you help me I get this error ValueError: max() arg is an empty sequence