-
-
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() |
benmarwick
commented
Jan 2, 2019
HI
Can you give me the step by step procedure to run the code. how to fix the threshold etc...
Can you give me the step by step procedure to run the code. how to fix the threshold etc...
at line 69 remove ' _,' from _,contours,hierarchy = cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
Can you help me I get this error ValueError: max() arg is an empty sequence
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'
A related method is here: https://www.digitalarchns.com/measureartifacts/