How can I use object tracking with python? - python

I have been making a program to detect vehicles and now I have to do the tracking, how can I do it if I already have separate frames and each object of the detected frame?
center_points_cur_frame = []
center_points_prev_frame = []
tracking_objects = {}
track_id = 0
count = 0;
def pintarInformacion(rutaImg, rutaInfo, rutaPintada):
global center_points_prev_frame
global track_id
global count
count += 1
image = cv2.imread(rutaImg)
with open(rutaInfo, "r") as tf:
line = list(csv.reader(tf, delimiter=' '))
with open(rutaInfo, "r") as fp:
numlin = len(fp.readlines())
#print(numlin)
i = 1
while i<numlin:
# find bounding box coordinates
while("" in line[i]) :
line[i].remove("")
x = int(float(line[i][1]))
y = int(float(line[i][2]))
w = int(float(line[i][3]))
h = int(float(line[i][4]))
cx = int((x+w)/2)
cy = int((y+h)/2)
center_points_cur_frame.append((cx,cy))
i = i + 1;
cv2.rectangle(image, (x,y), (w,h), (0,255,0), 2)
if count <= 2:
for pt in center_points_cur_frame:
for pt2 in center_points_prev_frame:
distance = math.hypot(pt2[0] - pt[0], pt2[1] - pt2[0])
if distance < 20:
tracking_objects[track_id] = pt
track_id += 1
else:
tracking_objects_copy = tracking_objects.copy()
center_points_cur_frame_copy = center_points_cur_frame.copy()
for object_id, pt2 in tracking_objects_copy.items():
object_exists = False
for pt in center_points_cur_frame_copy:
distance = math.hypot(pt2[0] - pt[0], pt2[1] - pt[1])
# Update IDs position
if distance < 20:
tracking_objects[object_id] = pt
object_exists = True
if pt in center_points_cur_frame:
center_points_cur_frame.remove(pt)
continue
# Remove IDs lost
if not object_exists:
tracking_objects.pop(object_id)
# Add new IDs found
for pt in center_points_cur_frame:
tracking_objects[track_id] = pt
track_id += 1
for object_id, pt in tracking_objets.items():
cv2.circle(image,pt, 5, (0,0,255),-1)
cv2.putText(image,str(object_id), (pt[0], pt[1] -7),0,1,(0,0,255), 2)
# cv2.imshow("contours", img)
cv2.imwrite(rutaPintada, image)
center_points_prev_frame = center_points_cur_frame.copy();
key = cv2.waitKey(1)
if key == 27:
return 0
cv2.waitKey()
cv2.destroyAllWindows()
I am programming in google colab.
But the results are so bad
Image
As you can see, the points are drawn incorrectly as it does not find the algorithm of the trajectory but it is always the same. How can I solve my problem? This is the first time I try to track objects and this is all I need.
Thanks in advance

Related

how coping video depend on bounding box after face detection?

I faced an issue when I try to crop video depending on the bounding box after detecting the face so this is the sub of my code, pleases look for it and I hope you can help me if there is any code similar to my issues please tell me
Hi, I faced an issue when I try to crop video depending on the bounding box after detecting the face so this is the sub of my code, pleases look for it and I hope you can help me if there is any code similar to my issues please tell me
for entry in words_data:
# Extract speech to text data
print('entry:', type(entry), entry)
s_sec, s_millisec = divmod(float(entry['start']), 1)
e_sec, e_millisec = divmod(float(entry['end']), 1)
s_min = 0
e_min = 0
s_millisec = s_millisec * 1000
e_millisec = e_millisec * 1000
print('s_sec, s_millisec:', s_sec, s_millisec)
if s_sec >= 60:
s_min = math.floor(s_sec / 60.0)
s_sec = s_sec % 60
if e_sec >= 60:
e_min = math.floor(e_sec / 60.0)
e_sec = e_sec % 60
# Determine video frames involved in stt entry
min_frame = s_min*fps*60 + (s_sec*fps)
max_frame = e_min*fps*60 + (e_sec*fps)
# go to min_frame
cap.set(cv2.CAP_PROP_POS_FRAMES, min_frame)
frame_count = min_frame
# read frames from min_frame to max_frame
num_people = 0
valid_video = True
bbx = []
bby = []
bbh = []
bbw = []
bbx1 = []
bby1 = []
bbx2 = []
bby2 = []
landmarks = []
angles = []
x = []
y = []
w = []
h = []
consecutive_frames_no_people = 0
while frame_count < max_frame:
if count == 0:
t = cv2.getTickCount()
# capture next frame
ret, frame = cap.read()
if not ret:
continue
#frame = cv2.resize(frame,(0, 0), fx=scale, fy=scale,interpolation=cv2.INTER_LINEAR)
#frame = cv2.resize(frame, (480, 640),interpolation=cv2.INTER_LINEAR)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
num_people = hog_face_detector(gray,1)
# if it detects less than or more than 1 person
# go to next subtitle
if len(num_people) != 1:
consecutive_frames_no_people += 1
if consecutive_frames_no_people >= max_bad_frames:
print(consecutive_frames_no_people,
' frames without 1 person. Skiping to next subtitle')
valid_video = False
break
## if only one person in the scene
if len(num_people) == 1:
consecutive_frames_no_people = 0
rects = hog_face_detector(gray,1)
for (i, rect) in enumerate(rects):
# determine the facial landmarks for the face region, then
# convert the facial landmark (x, y)-coordinates to a NumPy
# array
shape = dlib_facelandmark(gray, rect)
shape = face_utils.shape_to_np(shape)
#bb = bounding_boxes[0]
#x1, y1 = int(rect.left()), int(rect.top())
#x2, y2 = int(rect.right()), int(rect.bottom())
#area = (x2 - x1) * (y2 - y1)
#if area < min_area:
# valid_video = False
# break
#save bounding box coordinates for final crop
#bbx1.append(bb[0])
#bby1.append(bb[1])
#bbx2.append(bb[2])
#bby2.append(bb[3])
# convert dlib's rectangle to a OpenCV-style bounding box
# [i.e., (x, y, w, h)], then draw the face bounding box
bb = face_utils.rect_to_bb(rect)
#(x, y, w, h) = face_utils.rect_to_bb(rect)
cv2.rectangle(frame, (bb[0], bb[1]), (bb[0] + bb[2], bb[1] + bb[3]), (0, 255, 0), 2)
#save bounding box coordinates for final crop
bbx1.append(bb[0])
bby1.append(bb[1])
bbx2.append(bb[2])
bby2.append(bb[3])
# Put fps at which we are processing camera feed on frame
cv2.putText(frame, "{0:.2f}-fps".format(fps_processing),
(50, height-50), cv2.FONT_HERSHEY_COMPLEX,
1, (0, 0, 255), 2)
# Display the image
cv2.imshow('Vid',frame)
# Read keyboard and exit if ESC was pressed
k = cv2.waitKey(1) & 0xFF
if k ==27:
exit()
elif k == ord('q'):
stop_videos = True
# increment frame counter
count = count + 1
# calculate fps at an interval of 100 frames
if (count == 30):
t = (cv2.getTickCount() - t)/cv2.getTickFrequency()
fps_processing = 30.0/t
count = 0
# if this was a valid video
#if valid_video and len(landmarks) > 0:
# num_output_video += 1
#entry['mouth3d'] = landmarks
#entry['angle'] = angles
if valid_video and len(bb) > 0:
num_output_video += 1
bbx1 = np.amin(bbx1)
bbx2 = np.amax(bbx2)
bby1 = np.amin(bby1)
bby2 = np.amax(bby2)
bbw = bbx2 - bbx1
bbh = bby2 - bby1
entry['bounding_box'] = [bb[0], bb[1], bb[2], bb[3]]
entry['landmark'] = bb
print('entry:', type(entry), entry)
if save_videos:
s_hr = 0
e_hr = 0
if s_min >= 60:
s_hr = math.floor(s_min / 60)
s_min = s_min % 60
if e_min >= 60:
e_hr = math.floor(e_min / 60)
e_min = e_min % 60
# cut and crop video
# ffmpeg -i input.mp4 -ss hh:mm:ss -filter:v crop=w:h:x:y -c:a copy -to hh:mm:ss output.mp4
ss = "{0:02d}:{1:02d}:{2:02d}.{3:03d}".format(
s_hr, s_min, int(s_sec), math.ceil(s_millisec))
es = "{0:02d}:{1:02d}:{2:02d}.{3:03d}".format(
e_hr, e_min, int(e_sec), math.ceil(e_millisec))
crop = "crop={0:1d}:{1:1d}:{2:1d}:{3:1d}".format(
bbw, bbh, bbx1, bby1)
out_name = os.path.join(output_dir, str(num_output_video))
subprocess.call(['ffmpeg', #'-hide_banner', '-loglevel', 'panic',
'-i', os.path.join(
videos_directory, vids_name, video_name),
'-ss', ss,
'-filter:v', crop, '-c:a', 'copy',
'-to', es, out_name +'.mp4'])
# save recognized speech
text_file = open(out_name +'.txt', "w")
text_file.write(entry['text'] + '\n')
text_file.write(str(entry['conf']))
text_file.close()
and this is output, so, how i can write the final BB for the video?
found 4 files
Processing video: health_news_1.mp4
video resolution: 608 x 1080
video framerate: 25.0
entry: <class 'dict'> {'link': 'build_Dataset', 'text': 'شانغهاي', 'conf': 0.58, 'start': 1.6, 'end': 2.24, 'bounding_box': []}
s_sec, s_millisec: 1.0 600.0000000000001
10 frames without 1 person. Skiping to next subtitle
entry: <class 'dict'> {'link': 'build_Dataset', 'text': 'تواجه', 'conf': 0.65, 'start': 2.24, 'end': 2.72, 'bounding_box': []}
s_sec, s_millisec: 2.0 240.00000000000023
Traceback (most recent call last):
File "extract_subvideos.py", line 467, in <module>
main(args)
File "extract_subvideos.py", line 315, in main
bbx1 = np.amin(bbx1)
File "<__array_function__ internals>", line 5, in amin
File "/Users/shaimaa/.local/lib/python3.8/site-packages/numpy/core/fromnumeric.py", line 2879, in amin
return _wrapreduction(a, np.minimum, 'min', axis, None, out,
File "/Users/shaimaa/.local/lib/python3.8/site-packages/numpy/core/fromnumeric.py", line 86, in _wrapreduction
return ufunc.reduce(obj, axis, dtype, out, **passkwargs)
ValueError: zero-size array to reduction operation minimum which has no identity
Error shows that you try to get amin() from empty list bbx1.
I can't test it but I think problem is that you clear bbx1 = [] but you don't clear bb = [] and later it may have not-empty bb from previous loop and empty bbx1 from current loop (because when it finds more that 1 person then it doesn't add values from bb to bbx1) and it may run code in if ... len(bb) > 1: and try to use empty bbx1
You should check len(bbx1)
if valid_video and len(bb) > 0 and len(bbx1) > 0:
OR you would have to use some boolean variable found_one_person which you would reset to False before while-loop, and set True when you find one person (if len(num_people) == 1:), and use it to write data
if valid_video and found_one_person:

Python code to print percentage RGB in an ROI not working

I am trying to find percentage RGB value of an ROI in camera feed. The end goal is to take a snapshot as soon as an object which has an RGB value of certain threshold arrives in the ROI.
But the code is calculating RGB of entire video feed. Im not able to find out what could be the reason for this, can anyone please help.
import cv2
from matplotlib import pyplot as plt
cam_capture = cv2.VideoCapture(0)
cv2.destroyAllWindows()
upper_left = (132, 278)
bottom_right = (586, 400)
while True:
_, image_frame = cam_capture.read()
#Rectangle marker
r = cv2.rectangle(image_frame, upper_left, bottom_right, (100, 50, 200), 5)
rect_img = image_frame[upper_left[1] : bottom_right[1], upper_left[0] : bottom_right[0]]
sketcher_rect = rect_img
#sketcher_rect = sketch_transform(sketcher_rect)
#Conversion for 3 channels to put back on original image (streaming)
color_B = 0
color_G = 0
color_R = 0
color_N = 0 # neutral/gray color
rows=454
cols=268
for i in range(132,278):
for j in range(400,586):
k = image_frame[i,j]
#print ("org",k[0],k[1],k[2])
if k[0] > k[1] and k[0] > k[2]:
color_B = color_B + 1
continue
if k[1] > k[0] and k[1] > k[2]:
color_G = color_G + 1
continue
if k[2] > k[0] and k[2] > k[1]:
color_R = color_R + 1
continue
color_N = color_N + 1
pix_total = rows * cols
print('Blue:', color_B/pix_total, 'Green:', color_G/pix_total, 'Red:', color_R/pix_total, 'Gray:', color_N/pix_total)
#Replacing the sketched image on Region of Interest
image_frame[upper_left[1] : bottom_right[1], upper_left[0] : bottom_right[0]] =sketcher_rect
cv2.imshow("Sketcher ROI", image_frame)
if cv2.waitKey(1) == 13:
break
cam_capture.release()
cv2.destroyAllWindows()
Solved it..Actually I was entering wrong coordinates in the for loop
rows=400-278
cols=586-132
#print (k[0],k[1],k[2])
for i in range(278,400):
for j in range(132,586):

How to detect fingers using OpenCV?

I'm trying to detect the hand and fingers in an image using OpenCV in python.
This is the code I'm using:
import cv2, random, math
import numpy as np
import matplotlib.pyplot as plt
import time
def calculateAngle(far, start, end):
a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)
angle = math.acos((b**2 + c**2 - a**2) / (2*b*c))
return angle
image = cv2.imread("5_P_hgr1_id09_2.png")
imageHSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
Min = np.array([5,55,60],np.uint8)
Max = np.array([13,139,198],np.uint8)
mask = cv2 . inRange ( imageHSV , Min, Max)
kernel_square = np.ones(None,np.uint8)
kernel_ellipse= cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(11,11))
dilation = cv2.dilate(mask,kernel_ellipse,iterations = 1)
closing = cv2.morphologyEx(dilation, cv2.MORPH_CLOSE, kernel_square)
erosion = cv2.erode(closing,kernel_square,iterations = 1)
contours, hierarchy = cv2.findContours(erosion,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
if len(contours)>0:
maxArea = 0
hull = []
fingerList = []
for i in range (len(contours)):
cnt = contours[i]
area = cv2.contourArea(cnt)
if area>maxArea :
maxArea = area
ci = i
cnts = contours[ci]
hull2 = cv2.convexHull(cnts)
hull = cv2.convexHull(cnts, returnPoints=False)
defects = cv2.convexityDefects(cnts, hull)
moments = cv2.moments(contours[ci])
#Central mass
if moments['m00']!=0: #m00 moments spatiaux
cx = int(moments['m10']/moments['m00']) # cx = M10/M00
cy = int(moments['m01']/moments['m00']) # cy = M01/M00
centerMass=(cx,cy)
cv2.circle(image,centerMass,7,[100,0,255],2)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image,'Center',tuple(centerMass),font,0.5,(255,255,255),1)
D = []
for i in range (len(cnts)):
x = np.array(cnts[i][0][0])
y = np.array(cnts[i][0][1])
xp = np.power(x-cx, 2)
yp = np.power(y-cy, 2)
dist = np.sqrt(xp+yp)
D.append(dist)
dist_min = np.min(D)
closest_d = np.where ( D== dist_min)[0]
closest_p = tuple(cnts[closest_d[0]][0])
cnt = 0
farDefect=[]
Far =[]
if type(defects) != type(None):
for i in range (defects.shape[0]):
s,e,f,d = defects[i, 0]
start = tuple(cnts [s,0])
end = tuple(cnts[e,0])
far = tuple(cnts[f,0])
Far.append(far)
x = far[0]
y = far[0]
angle = calculateAngle (far, start, end)
if angle<= math.pi/1.6 and far != closest_p and d>8000 :
cnt+=1
farDefect.append(far)
for i in range (len(farDefect)):
xd = (farDefect[i][0])
yd = (farDefect[i][1])
listDistance = []
dist = 0
for j in range (defects.shape[0]):
s,e,f,d = defects[j,0]
point = cnts[f][0]
distance = np.sqrt(np.power(point[0]-centerMass[0],2)+np.power(point[1]-centerMass[1],2))
distance2 = np.sqrt(np.power(point[0]-xd,2)+np.power(point[1]-yd,2))
distance3 = np.sqrt(np.power(xd-centerMass[0],2)+np.power(yd-centerMass[1],2))
if dist<distance and distance2<distance and distance3<distance and
distance3+distance2<=distance+50 :
if i==0 :
dist = distance
pn= point
listDistance.append((point[0],point[1]))
if i==1 :
distance3 = np.sqrt(np.power(pn[0]-point[0],2)+np.power(pn[1]-point[1],2))
if distance3>100:
dist = distance
pn2= point
listDistance.append((point[0],point[1]))
if i==2 :
distance3 = np.sqrt(np.power(pn[0]-point[0],2)+np.power(pn[1]-point[1],2))
distance4 = np.sqrt(np.power(pn2[0]-point[0],2)+np.power(pn2[1]-point[1],2))
if distance4>100 and distance3>100:
dist = distance
pn3= point
listDistance.append((point[0],point[1]))
if i==3 :
distance3 = np.sqrt(np.power(pn[0]-point[0],2)+np.power(pn[1]-point[1],2))
distance4 = np.sqrt(np.power(pn2[0]-point[0],2)+np.power(pn2[1]-point[1],2))
distance5 = np.sqrt(np.power(pn3[0]-point[0],2)+np.power(pn3[1]-point[1],2))
if distance4>100 and distance3>100 and distance5>100:
dist = distance
listDistance.append((point[0],point[1]))
dist = 1000
for j in range (len(listDistance)):
point = listDistance[j]
distance = np.sqrt(np.power(point[0]-xd,2)+np.power(point[1]-yd,2))
if distance<dist and distance!=0:
finger = point
cv2.circle(image,(finger),7,[100,0,255],2)
fingerList.append(finger)
dist = 50000
for j in range (len(fingerList)):
point = fingerList[j]
distance = np.sqrt(np.power(point[0]-cx,2)+np.power(point[1]-cy,2))
if distance<dist:
dist = distance
finger = point
x,y,w,h = cv2.boundingRect(cnts)
image = cv2.rectangle(image,(x,y),(x+w,y+h),(0,0,255),2)
for i in range (len(farDefect)):
defaut= farDefect[i]
cv2.circle(image,defaut,7,[100,0,255],2)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(image,'D',tuple(defaut),font,0.5,(255,255,255),1)
for i in range (len(contours)):
color_con = (0,255,0) #green color for contours
color = (255,0,0) #blue color for convex hull
cv2.drawContours(image, contours, i, color_con, 1,8, hierarchy)
#cv2.drawContours(image,[hull2], i, color, 1,8)
cv2.imshow("image", image)
cv2.waitKey(0)
I'm getting the following results:
However, I can not detect all the fingers (I have 5 fingers and I get 4 that are represented with small red circles). I don't know where is the problem or how should I detect all fingers.
I'm looking for results close to this:
Any help is appreciated.

Creating trail from YOLO v2 + deep_sort object tracking with tensorflow

I'm trying to create trails and map of trails of all ID like this video: https://www.youtube.com/watch?v=tq0BgncuMhs
So far I haven't been able to, I'm currently using this repo from bendidi https://github.com/bendidi/Tracking-with-darkflow which I modifies to also show the trails.
I did try using cv2.line and extract it from track.to_tlbr() but right now the result look like this:
Here's the code that I modified to get the current result:
darkflow/darkflow/net/yolov2/predict.py
from collections import deque
import numpy as np
import math
import cv2
import os
import json
#from scipy.special import expit
#from utils.box import BoundBox, box_iou, prob_compare
#from utils.box import prob_compare2, box_intersection
from ...utils.box import BoundBox
from ...cython_utils.cy_yolo2_findboxes import box_constructor
ds = True
try :
from deep_sort.application_util import preprocessing as prep
from deep_sort.application_util import visualization
from deep_sort.deep_sort.detection import Detection
except :
ds = False
def expit(x):
return 1. / (1. + np.exp(-x))
def _softmax(x):
e_x = np.exp(x - np.max(x))
out = e_x / e_x.sum()
return out
def findboxes(self, net_out):
# meta
meta = self.meta
boxes = list()
boxes=box_constructor(meta,net_out)
return boxes
def extract_boxes(self,new_im):
cont = []
new_im=new_im.astype(np.uint8)
ret, thresh=cv2.threshold(new_im, 127, 255, 0)
p, contours, hierarchy=cv2.findContours(
thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for i in range(0, len(contours)):
cnt=contours[i]
x, y, w, h=cv2.boundingRect(cnt)
if w*h > 30**2 and ((w < new_im.shape[0] and h <= new_im.shape[1]) or (w <= new_im.shape[0] and h < new_im.shape[1])):
if self.FLAGS.tracker == "sort":
cont.append([x, y, x+w, y+h])
else : cont.append([x, y, w, h])
return cont
def postprocess(self,net_out, im,frame_id = 0,csv_file=None,csv=None,mask = None,encoder=None,tracker=None):
"""
Takes net output, draw net_out, save to disk
"""
boxes = self.findboxes(net_out)
# meta
meta = self.meta
nms_max_overlap = 0.1
threshold = meta['thresh']
colors = meta['colors']
labels = meta['labels']
if type(im) is not np.ndarray:
imgcv = cv2.imread(im)
else: imgcv = im
h, w, _ = imgcv.shape
thick = int((h + w) // 300)
resultsForJSON = []
if not self.FLAGS.track :
for b in boxes:
boxResults = self.process_box(b, h, w, threshold)
if boxResults is None:
continue
left, right, top, bot, mess, max_indx, confidence = boxResults
if self.FLAGS.json:
resultsForJSON.append({"label": mess, "confidence": float('%.2f' % confidence), "topleft": {"x": left, "y": top}, "bottomright": {"x": right, "y": bot}})
continue
if self.FLAGS.display or self.FLAGS.saveVideo:
cv2.rectangle(imgcv,
(left, top), (right, bot),
colors[max_indx], thick)
cv2.putText(imgcv, mess, (left, top - 12),
0, 1e-3 * h, colors[max_indx],thick//3)
else :
if not ds :
print("ERROR : deep sort or sort submodules not found for tracking please run :")
print("\tgit submodule update --init --recursive")
print("ENDING")
exit(1)
detections = []
scores = []
lines = deque(maxlen=64)
for b in boxes:
boxResults = self.process_box(b, h, w, threshold)
if boxResults is None:
continue
left, right, top, bot, mess, max_indx, confidence = boxResults
if mess not in self.FLAGS.trackObj :
continue
if self.FLAGS.tracker == "deep_sort":
detections.append(np.array([left,top,right-left,bot-top]).astype(np.float64))
scores.append(confidence)
elif self.FLAGS.tracker == "sort":
detections.append(np.array([left,top,right,bot]).astype(np.float64))
if len(detections) < 3 and self.FLAGS.BK_MOG:
detections = detections + extract_boxes(self,mask)
detections = np.array(detections)
if detections.shape[0] == 0 :
return imgcv
if self.FLAGS.tracker == "deep_sort":
scores = np.array(scores)
features = encoder(imgcv, detections.copy())
detections = [
Detection(bbox, score, feature) for bbox,score, feature in
zip(detections,scores, features)]
# Run non-maxima suppression.
boxes = np.array([d.tlwh for d in detections])
scores = np.array([d.confidence for d in detections])
indices = prep.non_max_suppression(boxes, nms_max_overlap, scores)
detections = [detections[i] for i in indices]
tracker.predict()
tracker.update(detections)
trackers = tracker.tracks
elif self.FLAGS.tracker == "sort":
trackers = tracker.update(detections)
for track in trackers:
if self.FLAGS.tracker == "deep_sort":
if not track.is_confirmed() or track.time_since_update > 1:
continue
bbox = track.to_tlbr()
center = (int(bbox[0]) + ((int(bbox[2]) - int(bbox[0])) // 2)), (int(bbox[1]) + ((int(bbox[3]) - int(bbox[1])) // 2)) # X + Width / 2, Y + Height / 2
lines.appendleft(center)
id_num = str(track.track_id)
elif self.FLAGS.tracker == "sort":
bbox = [int(track[0]),int(track[1]),int(track[2]),int(track[3])]
id_num = str(int(track[4]))
if self.FLAGS.csv:
csv.writerow([frame_id,id_num,int(bbox[0]),int(bbox[1]),int(bbox[2])-int(bbox[0]),int(bbox[3])-int(bbox[1])])
csv_file.flush()
if self.FLAGS.display or self.FLAGS.saveVideo:
cv2.rectangle(imgcv, (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])),
(255,255,255), thick//3)
cv2.putText(imgcv, id_num,(int(bbox[0]), int(bbox[1]) - 12),0, 1e-3 * h, (255,255,255),thick//6)
for i in range(1, len(lines)):
cv2.line(imgcv, lines[i - 1], lines[i], (255,255,255), thick//3)
return imgcv
Or just the code that I added:
...
lines = deque(maxlen=64)
...
center = (int(bbox[0]) + ((int(bbox[2]) - int(bbox[0])) // 2)), (int(bbox[1]) + ((int(bbox[3]) - int(bbox[1])) // 2)) # X + Width / 2, Y + Height / 2
lines.appendleft(center)
...
for i in range(1, len(lines)):
cv2.line(imgcv, lines[i - 1], lines[i], (255,255,255), thick//3)
Could someone help me out on this? Or should I do something with the data first instead of plug in straight into cv2.line? If you also have any suggestion for using external software rather than using Python, that's also welcome (I have frame_id, track_id, x, y, w, h data)

Triangulation with holes in python

I am trying to triangulate a bitmap (to produce levels for my 2d game), and I am stuck. I am using the Triangle library by Jonathan Shewchuk using this wrapper.
I start with an image,
then I detect edges and determine which vertices are holes. I picked every fourth for triangulation,
then I passed those points to triangulation, but I end up with something like this
where my hole has disappeared. What am I doing wrong?
Also, why am i getting somewhat convex hull instead of triangulated polygon?
Here is my code so far:
#here i am loading all data, that i will use later on but i had to insert that, just in case
mapfg = glob(path.join(pathtomapfolder, "Foreground.png"))[0] #Getting map foreground image
mapob = glob(path.join(pathtomapfolder, "Obstacles.png"))[0] #Getting map file
mappr = glob(path.join(pathtomapfolder, "Properties.txt"))[0] #Getting map info file
self.mapprops = [mapob, mapfg, mappr]
#getting ground and obstacles
obsbitmap = Image.open(self.mapprops[0])
lockBitmap = obsbitmap.load()
compareClr = (0, 0, 0)
for y in xrange(obsbitmap.size[1]):
tmp = []
for x in xrange(obsbitmap.size[0]):
if lockBitmap[x, y][0] == compareClr[0] and lockBitmap[x, y][6] == compareClr[1] and lockBitmap[x, y][7] == compareClr[2]:
tmp.append(1)
else:
tmp.append(0)
self.obs.append(tmp)
#detecting edges
for y in xrange(len(self.obs)):
tmphit = []
for x in xrange(len(self.obs[0])):
if (self.obs[y][x] == 0 and (self.obs[MinMax.NoOver(y - 1, len(self.obs) - 1, 0)][x] == 1 or self.obs[y][MinMax.NoOver(x - 1, len(self.obs[0]) - 1, 0)] == 1 or self.obs[y][MinMax.NoOver(x + 1, len(self.obs[0]) - 1, 0)] == 1 or self.obs[MinMax.NoOver(y + 1, len(self.obs) - 1, 0)][x] == 1)) or (self.obs[y][x] == 1 and (MinMax.WillOver(y - 1, len(self.obs) - 1, 0) or MinMax.WillOver(x - 1, len(self.obs[0]) - 1, 0) or MinMax.WillOver(x + 1, len(self.obs[0]) - 1, 0) or MinMax.WillOver(y + 1, len(self.obs) - 1, 0))):
tmphit.append(True)
else:
tmphit.append(False)
self.hit.append(tmphit)
#here it starts, first of all i search for vertice, then go CW or CCW and get all vertices from edge of one polygon, i also detect, whether it is hole or not and to which polygon is related to.
xcirc = ycirc = 0
coords = []
coordvalues = []
parentid = []
self.allverts = [coords, coordvalues, parentid]
polyID = 0
for y in xrange(len(self.obs)):
for x in xrange(len(self.obs[0])):
if self.hit[y][x] and not (x, y) in self.allverts[0]:
left = []
right = []
up = []
down = []
numobjects = numholes = 0
type = ""
parentid = -1
for v in xrange(len(self.allverts[0])):
if self.allverts[0][v][8] == y and self.allverts[0][v][0] < x: left.append(self.allverts[1][v])
if self.allverts[0][v][9] == y and self.allverts[0][v][0] > x: right.append(self.allverts[1][v])
if self.allverts[0][v][0] == x and self.allverts[0][v][10] < y: up.append(self.allverts[1][v])
if self.allverts[0][v][0] == x and self.allverts[0][v][11] > y: down.append(self.allverts[1][v])
for id in xrange(polyID):
if ("not hole", id) in left and ("not hole", id) in right and ("not hole", id) in up and ("not hole", id) in down:
numobjects += 1
parentid = id
elif ("hole", id) in left and ("hole", id) in right and ("hole", id) in up and ("hole", id) in down:
numholes += 1
if numobjects == 0 or numobjects == numholes: type = "not hole"
elif numobjects > numholes: type = "hole"
found = False
lastangle = -90
self.allverts[0].append((x, y))
self.allverts[1].append((type, polyID))
self.allverts[2].append(parentid)
v = 1
while not found:
angle = MinMax.Overflow(lastangle - 45, 180, -179)
lastangle = angle
xcirc = int(round(math.cos((math.pi / 180) * angle)))
ycirc = int(round(math.sin((math.pi / 180) * angle)))
if self.hit[MinMax.NoOver(self.allverts[0][-1][12] + ycirc, len(self.hit) - 1, 0)][MinMax.NoOver(self.allverts[0][-1][0] + xcirc, len(self.hit[0]) - 1, 0)] and (MinMax.WontOver(self.allverts[0][-1][13] + ycirc, len(self.hit) - 1, 0) and MinMax.WontOver(self.allverts[0][-1][0] + xcirc, len(self.hit[0]) - 1, 0)):
if not (self.allverts[0][-1][0] + xcirc, self.allverts[0][-1][14] + ycirc) in self.allverts[0]:
self.allverts[0].append((self.allverts[0][-1][0] + xcirc, self.allverts[0][-1][15] + ycirc))
self.allverts[1].append((type, polyID))
self.allverts[2].append(parentid)
v += 1
else:
#self.allverts.append((self.allverts[-1][0] + xcirc, self.allverts[-1][16] + ycirc))
found = True
if v < 4:
polyID -= 1
for d in xrange(v):
del self.allverts[0][-1]
del self.allverts[1][-1]
del self.allverts[2][-1]
lastangle = MinMax.Overflow(lastangle + 135, 180, -179)
polyID += 1
# now i have to convert that data structure to something i can pass to triangulate function
objects = []
objectpoints = []
idtoindexobj = []
holes = []
holepoints = []
holecoords = []
holeleft = len(self.hit[0])
holetop = len(self.hit)
holeright = holebottom = 0
idtoindexhole = []
prevvert = (self.allverts[0][0], self.allverts[1][0], self.allverts[2][0])
d = 0
for u in xrange(len(self.allverts[0])):
vert = (self.allverts[0][u], self.allverts[1][u], self.allverts[2][u])
if vert[1][17] != prevvert[1][18]:
d = 0
if prevvert[1][0] == "not hole":
objects.append(objectpoints)
objectpoints = []
idtoindexobj.append(prevvert[1][19])
else:
holes.append(holepoints)
holepoints = []
holecoords.append((holeleft + (MinMax.AminB(holeleft, holeright)/2), holetop + (MinMax.AminB(holetop, holebottom)/2)))
idtoindexhole.append(prevvert[2])
holeleft = len(self.hit[0])
holetop = len(self.hit)
holeright = holebottom = 0
if vert[1][0] == "not hole":
if d % 4 == 0:
objectpoints.append((vert[0][0], vert[0][20]))
else:
if d % 4 == 0:
holepoints.append((vert[0][0], vert[0][21]))
if vert[0][0] < holeleft: holeleft = vert[0][0]
if vert[0][0] > holeright: holeright = vert[0][0]
if vert[0][22] < holetop: holetop = vert[0][23]
if vert[0][24] > holebottom: holebottom = vert[0][25]
d+=1
prevvert = vert
if prevvert[1][0] == "not hole":
objects.append(objectpoints)
objectpoints = []
idtoindexobj.append(prevvert[1][26])
else:
holes.append(holepoints)
holepoints = []
holecoords.append((holeleft + (MinMax.AminB(holeleft, holeright)/2), holetop + (MinMax.AminB(holetop, holebottom)/2)))
idtoindexhole.append(prevvert[2])
holeleft = len(self.hit[0])
holetop = len(self.hit)
holeright = holebottom = 0
objectpoints.append((vert[0][0], vert[0][27]))
self.polygons = []
for ind, id in enumerate(idtoindexobj):
holecoordlist = []
segments = []
for k, l in enumerate(idtoindexhole):
if l == id:
holecoordlist.append(holecoords[k])
prevsegpart = False
for segpart in holes[k]:
if not prevsegpart:
prevsegpart = segpart
continue
segments.append((prevsegpart[0], prevsegpart[1], segpart[0], segpart[1]))
prevsegpart = segpart
segments.append((prevsegpart[0], prevsegpart[1], holes[k][0][0], holes[k][0][1]))
if segments:
self.polygons.append({"vertices":objects[ind], "segments":segments, "holes":holecoordlist})
else:
self.polygons.append({"vertices":objects[ind]})
indtripolylist = []
for pol in self.polygons:
#here i am calling that triangulate function
indtripolylist.append(triangle.triangulate(pol, opts="q"))
#and finally convert what has been returned to coordinates of triangles (because it returns list of vertices and touples of indexes pointing to vertices)
self.tripolylist = []
for po in indtripolylist:
tmptriangles = []
for tr in po["triangles"]:
tmptriangles.append((po["vertices"][tr[0]], po["vertices"][tr[1]], po["vertices"][tr[2]]))
self.tripolylist.append(tmptriangles)
Thank you for your help.
This had me scratching my head for a while, your comments helped me get it working.
to see an example of the data you need to pass:
triangle.get_data('face')
to stop a polygon being "filled in" and keep it concave you can pass along the segments like this
segments = []
for i in range(len(verts)-1):
segments.append([int(i),int(i+1)])
segments.append([int(i+1),int(0)])
A = {'vertices':array(verts), 'segments':array(segments)}
to add a hole, you need to mark the verts and segments seperatly (warning: untested code)
vertmarks = []
for i in range(len(verts)):
vertmarks.append([2])
for i in range(len(hole)):
vertmarks.append([4])
segmarks = []
for i in range(len(segments)):
segmarks.append([2])
for i in range(len(holesegments)):
segmarks.append([4])
A = {'vertices':array(verts), 'segments':array(segments),
'segment_markers':array(segmarks), 'vertex_markers':array(vertmarks)}
'holes' should also be passed as a list of [x,y] locations - one inside each hole

Categories