Object tracking program does not show tracked points in the output image - python

I need to track an object in a video frame but to do so I have to initialize good features to track my object.
So, I have a .mp4 file, I retained the blue channel of the first frame and I obtained the first frame. I then went on to create my binary mask by extracting my region of interest from the first frame and it was specified that my ROI lies within [300,400] on the y-axis and [460,550] x-axis (which is the front side of the bus).
I then initialized 10 corner points by using cv2.goodFeaturesToTrack having a quality level of 0.01 and a minimum allowable distance of 10 pixels between corner points. I then tried to display these points on the RGB image however I am not getting any points. The reason as to why I do not know.
This is shown here:
import numpy as np
import cv2
import matplotlib.pyplot as plt
vid = cv2.VideoCapture('Bus.mp4')
ret, frame = vid.read()
frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
blue_ch = frame[:,:,2]
mask = blue_ch[300:400,460:550]
prev_pts = cv2.goodFeaturesToTrack(image = mask,maxCorners=10,qualityLevel=0.01,minDistance=10,blockSize=10)
blue_ch = np.array(blue_ch)
for i in prev_pts:
x,y = i.ravel()
cv2.circle(blue_ch,(x,y),3,255,-1)
plt.imshow(blue_ch)

It creates small yellow dots in top left corner. They are similar to background color so you may not see them.
When I draw on RGB frame then I get red dots which you can see on image
If I convert blue_ch to RBG before drawing
blue_ch = cv2.cvtColor(blue_ch, cv2.COLOR_GRAY2RGB)
then I see
You get mask = blue_ch[300:400, 460:550] so when I add
y += 300
x += 460
then I get dots in correct place
My code:
import numpy as np
import cv2
import matplotlib.pyplot as plt
vid = cv2.VideoCapture('Bus.mp4')
ret, frame = vid.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
blue_ch = frame[:, :, 2]
mask = blue_ch[300:400, 460:550]
prev_pts = cv2.goodFeaturesToTrack(image=mask, maxCorners=10, qualityLevel=0.01, minDistance=10, blockSize=10)
blue_ch = cv2.cvtColor(blue_ch, cv2.COLOR_GRAY2RGB)
#blue_ch = np.array(blue_ch)
for i in prev_pts:
x, y = i.ravel()
y += 300
x += 460
#print(x, y)
cv2.circle(frame, (int(x), int(y)), 3, 255, -1)
cv2.circle(blue_ch, (int(x), int(y)), 3, 255, -1)
# --- display with matplot ---
plt.imshow(frame)
plt.show()
plt.imshow(blue_ch)
plt.show()
# -- OR display with `cv2` ---
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
blue_ch = cv2.cvtColor(blue_ch, cv2.COLOR_BGR2RGB)
cv2.imshow('frame', frame)
cv2.imshow('blue_ch', blue_ch)
print("Press ESC to exit")
try:
while cv2.waitKey(1) != 27: # ESC
pass
except:
cv2.destroyAllWindows()

Related

detect moving object with opencv and python

i found very interesting article about detection of moving objects, here is correspondng link :Detection of moving object
and also corresponding article : Article about object detection
i followed code and try to implement my self, here is corresponding code :
import cv2
import numpy as np
import matplotlib.pyplot as plt
from Background_Image_Creation import get_background
cap =cv2.VideoCapture("video_1.mp4")
#print(cap.get(cv2.CAP_PROP_FRAME_COUNT))
#print(cap.get(cv2.CAP_PROP_FPS))
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
save_name = "Result.mp4"
# define codec and create VideoWriter object
out = cv2.VideoWriter(save_name,cv2.VideoWriter_fourcc(*'mp4v'), 10, (frame_width, frame_height))
background_frame =get_background("video_1.mp4")
background = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)
print(background.shape)
frame_count =0
consecutive_frame=8
#frame_diff_list =[]
while cap.isOpened():
ret,frame =cap.read()
print(ret)
print(frame.shape)
if ret==True:
frame_count+=1
orig_frame =frame.copy()
gray =cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
if frame_count % consecutive_frame == 0 or frame_count == 1:
frame_diff_list =[]
frame_diff = cv2.absdiff(gray, background)
ret, thresh = cv2.threshold(frame_diff, 50, 255, cv2.THRESH_BINARY)
dilate_frame = cv2.dilate(thresh, None, iterations=2)
frame_diff_list.append(dilate_frame)
print(frame_diff_list)
if len(frame_diff_list) == consecutive_frame:
# add all the frames in the `frame_diff_list`
sum_frames = sum(frame_diff_list)
print(sum_frames)
# find the contours around the white segmented areas
contours, hierarchy = cv2.findContours(sum_frames, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# draw the contours, not strictly necessary
for i, cnt in enumerate(contours):
cv2.drawContours(frame, contours, i, (0, 0, 255), 3)
for contour in contours:
# continue through the loop if contour area is less than 500...
# ... helps in removing noise detection
if cv2.contourArea(contour) < 500:
continue
# get the xmin, ymin, width, and height coordinates from the contours
(x, y, w, h) = cv2.boundingRect(contour)
# draw the bounding boxes
cv2.rectangle(orig_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow('Detected Objects', orig_frame)
out.write(orig_frame)
if cv2.waitKey(100) & 0xFF == ord('q'):
break
else:
break
cap.release()
cv2.destroyAllWindows()
code for background frame creation is also presented :
import numpy as np
import cv2
import matplotlib.pyplot as plt
def get_background(path):
cap =cv2.VideoCapture(path)
frame_indices =cap.get(cv2.CAP_PROP_FRAME_COUNT)*np.random.uniform(size=50)
frames =[]
for idx in frame_indices:
cap.set(cv2.CAP_PROP_POS_FRAMES,idx)
ret,frame =cap.read()
frames.append(frame)
median_frame = np.median(frames, axis=0).astype(np.uint8)
return median_frame
#median_frame =get_background("video_1.mp4")
#cv2.imshow("Median_Background",median_frame)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
#plt.show()
code runs fine, but output video does not contain anything, it just 1 KGB size, one thing what i am thinking is that this fragment
frame_diff_list.append(dilate_frame)
is colored with yellow color, here is screenshot :
and also when i try to print print(frame_diff_list)
it just printed one output :
i was more surprised when i have tested
print(ret)
print(frame.shape)
from the begining of the loop and it just printed one output :
True
(360, 640, 3)
it seems that loop does not cover all frames right? could you help me please to figure out what is wrong with my code?

Capture what is in a rectangle of a numpy array

This might sound obvious to some of you but I was trying to figure out how to capture only what is in a rectangle.
The below code, uses dlib face detection and draws a bounding box around a detected face.
cv2.rectangle(img,(det.left(), det.top()), (det.right(), det.bottom()), color_green, line_width)
What I am struggling with is how to capture/ view only what is within the rectangle.
So in this example I only want to see what is in (det.left(), det.top()), (det.right(), det.bottom())
import sys
import dlib
import cv2
detector = dlib.get_frontal_face_detector()
cam = cv2.VideoCapture(1)
color_green = (0,255,0)
line_width = 3
while True:
ret_val, img = cam.read()
rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dets = detector(rgb_image)
for det in dets:
cv2.rectangle(img,(det.left(), det.top()), (det.right(), det.bottom()), color_green, line_width)
cv2.imshow('my webcam', img)
if cv2.waitKey(1) == 27:
break # esc to quit
cv2.destroyAllWindows()
You can try to implement cropping with numpy slicing.
For a rectangle drawn by:
cv2.rectangle(img,(left,top), (right,bottom), color_green, line_width)
You can try cropping as:
new_img = img[top:bottom,left:right,:]
to show only the parts that are within the detected boxes you'd want to either black out what's outside the dets (which I find almost impossible) or you could simply draw the desired parts on a black canvas instead
this is why I start here with a black canvas
import sys
import dlib
import cv2
import numpy as np
detector = dlib.get_frontal_face_detector()
cam = cv2.VideoCapture(1)
color_green = (0, 255, 0)
line_width = 3
while True:
ret_val, img = cam.read()
# get image dims to creat a black canvas of the same size
# img shape is (rows, cols, c) or (h, w, c)
img_h, img_w , _ = img.shape # c = 3 assuming it's a color iamge
# this will act as our black background / canvas
black_tmp = np.zeros((img_h, img_w, 3), dtype=int)
rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dets = detector(rgb_image)
for det in dets:
# det cy -> left , top | x2y2 -> right bottom
x , y, x2,y2 = det.left(), det.top(), det.right(), det.bottom()
# copy the pixels in the desired area to your black background
black_tmp [y:y2, x:x2, ::] = img[y:y2, x:x2, ::]
# maybe draw the rectangle on the new image too
cv2.rectangle(black_tmp,(det.left(), det.top()), (det.right(), det.bottom()), color_green, line_width)
cv2.imshow('my webcam', black_tmp)
if cv2.waitKey(1) == 27:
break # esc to quit
cv2.destroyAllWindows()
I've tried to only minimally edit your code
here's the np.zeros docs in case you need it
I hope this helps, if I missed any detail you need please feel free to point it out

Unsupported format or combination of formats) ,FindContours

I want to count the cars by using haar cascade.
#import libraries of python opencv
import numpy as np
import cv2
import gc
import uuid
import datetime
import time
import csv
cap = cv2.VideoCapture('v3.mp4')
car_cascade = cv2.CascadeClassifier('cars.xml')
W = cap.get(3)
H = cap.get(4)
areaTH = 700
H1 = (H/2)+10
W1 = W/2
mx = 0
my = 30
while (cap.isOpened()):
#capture frame by frame
ret, frame = cap.read()
#convert video into gray scale of each frames
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#detect cars in the video
cars = car_cascade.detectMultiScale(gray, 1.1, 3)
#to draw arectangle in each cars
for (x,y,w,h) in cars:
cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
#display the resulting frame
cv2.imshow('video', frame)
#press Q on keyboard to exit
if cv2.waitKey(25) & 0xFF == ord('q'):
break
Line1 = np.array([[20,H1],[310,H1]], np.int32).reshape((-1,1,2))
frame = cv2.polylines(frame,[Line1],False,(0,0,255),thickness=5)
fram, contours0, hierarchy =
cv2.findContours(frame,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours0:
# cv2.drawContours(frame, cnt, -1, (0,255,0), 2, 8)
area = cv2.contourArea(cnt)
#print ('Area : '+str(area))
if area > areaTH:
#################
# TRACKING #
#################
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
x,y,w,h = cv2.boundingRect(cnt)
cv2.circle(frame,(cx,cy), 3, (255,0,0), -1)
img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
#print ('H1 : '+str(H1))
print('cy : '+str(cy))
if (cy >= 147) and (cy<= 155):
Vehicles = Vehicles + 1
Line1 = np.array([[200,H1],[880,H1]],
np.int32).reshape((-1,1,2))
frame = cv2.polylines(frame,[Line1],False,(255,0,0),thickness=5)
cv2.imshow('Frame',frame)
#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows()
I convert the image properly to gray-scale and successfully drawn a line on the frame the problem is that I am getting this error
error: OpenCV(3.4.2) C:\build\3_4_winpack-bindings-win32-vc14-static\opencv\modules\imgproc\src\contours.cpp:199: error: (-210:Unsupported format or combination of formats) [Start]FindContours supports only CV_8UC1 images when mode != CV_RETR_FLOODFILL otherwise supports CV_32SC1 images only in function 'cvStartFindContours_Impl'
when ever i pass a variable 'frame' in this code line can somebody help me to solve this error thanx
fram, contours0, hierarchy =
cv2.findContours(frame,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
If you look at OpenCV documentation you see that function cv2.findContour() requires monochrome images. You pass frame which is still in 3 channels. You should use the gray variable instead (cv2.findContours(gray,...).
From the documentation for cv2.findContour()
image – Source, an 8-bit single-channel image. Non-zero pixels are treated as 1’s. Zero pixels remain 0’s, so the image is treated as binary . You can use compare() , inRange() , threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a grayscale or color one. The function modifies the image while extracting the contours. If mode equals to CV_RETR_CCOMP or CV_RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
Try this line to scale the pixels
image = cv2.convertScaleAbs(image)

OpenCV (Python) Drawing on Videos, Tracking

# libraries that will be needed
import numpy as np # numpy
import cv2 # opencv
import imutils # allows video editing
import random
from imutils.object_detection import non_max_suppression
from imutils import paths
import imutils
import cv2
#default HOG
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
# function to trak people
def tracker(cap):
while True:
ret, img = cap.read()
# if video stopped playing, quit
if ret == False:
break
# resize window
img = imutils.resize(img, width = 400)
# convert to graysclae and equalize
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
# detect people
rects, weights = hog.detectMultiScale(gray, winStride = (8, 8), padding = (8, 8), scale = 1.25)
# store detected people in array
rects = np.array([[x, y, x+w, y+h] for(x, y, w, h) in rects] )
# find largest possible rectangel to avoid detection
# of same person several times
biggest = non_max_suppression(rects, probs = None, overlapThresh = 0.65)
# draw largest rectangle
for (xA, yA, xB, yB) in biggest:
# create random color
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.rectangle(img, (xA, yA), (xB, yB), color, 2)
# show image
cv2.imshow('Image', img)
k = cv2.waitKey(30) & 0xFF
if k == 27:
break
# run video
cap = cv2.VideoCapture('NYC.mp4')
tracker(cap)
# release frame and destroy windows
cap.release()
cv2.destroyAllWindows
I am attempting to track multiple people at once using OpenCV. Once a person is detected, I draw a rectangle around them. I am having trouble having a random/different color box for each person while maintaining the same color box for a person after they have been detected.
Currently, a person is detected and a box is drawn. In the next frame, if they are still detected a new colored box is drawn, but I would like to maintain the original color.
Also open to tips/tricks that will improve my code and tracking since I am very new to this.
You need a way to say with good confidence this is the person in the next frame if you want to draw same color box for the same person. There are many ways to do it.
One way is you can use tracking. Try using Camshift/meanshift tracking(ofcourse there are many tracking algo, I wont be sure which one suits you best since i dont know your dataset).
Once a person is detected, initialise a tracker and assign a color box to that person. If person is out of the image, then have a system to remove the person from the list.
Hope this helps :)
Your if ret == False: is not indented correctly to match the while True: loop. Current Code:
def tracker(cap):
while True:
ret, img = cap.read()
# if video stopped playing, quit
if ret == False:
break
# resize window
img = imutils.resize(img, width = 400)
# convert to graysclae and equalize
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)
Fixed indentation:
def tracker(cap):
while True:
ret, img = cap.read()
# if video stopped playing, quit
if ret == False:
break
# resize window
img = imutils.resize(img, width = 400)
# convert to graysclae and equalize
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.equalizeHist(gray)

Draw an arrow instead of the rectangle at camshift algorithm with python

I want to measure the distance of the tracked object from the centre of the image, I'm not really good with python and I don't know how to get the x,y,w,h out from the roiBox object.
As you can see in the following code the algorithm prints the roiBox output - x,y of the top left corner and the w,h of the rectangle.
I need to:
Get those numbers as int's
Calculate the centre of the rectangle
Then draw an arrow from the centre of the rectangle to the centre of the frame.
The code:
# USAGE
# python track.py --video video/sample.mov
# import the necessary packages
import numpy as np
import argparse
import cv2
# initialize the current frame of the video, along with the list of ROI points along with whether or not this is input mode
frame = None
roiPts = []
inputMode = False
def select_ROI(event, x, y, flags, param):
# grab the reference to the current frame, list of ROI points and whether or not it is ROI selection mode
global frame, roiPts, inputMode
# if we are in ROI selection mode, the mouse was clicked, and we do not already have four points, then update the list of ROI points with the (x, y) location of the click and draw the circle
if inputMode and event == cv2.EVENT_LBUTTONDOWN and len(roiPts) < 4:
roiPts.append((x, y))
cv2.circle(frame, (x, y), 4, (0, 255, 0), 2)
cv2.imshow("frame", frame)
def determine_ROI_for_first_time():
global inputMode, roiBox, roiPts, roiHist
# indicate that we are in input mode and clone the frame
inputMode = True
orig = frame.copy()
# keep looping until 4 reference ROI points have been selected; press any key to exit ROI selction mode once 4 points have been selected
while len(roiPts) < 4:
cv2.imshow("frame", frame)
cv2.waitKey(0)
# determine the top-left and bottom-right points
roiPts = np.array(roiPts)
s = roiPts.sum(axis = 1)
tl = roiPts[np.argmin(s)]
br = roiPts[np.argmax(s)]
# grab the ROI for the bounding box and convert it to the HSV color space
roi = orig[tl[1]:br[1], tl[0]:br[0]]
roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
#roi = cv2.cvtColor(roi, cv2.COLOR_BGR2LAB)
# compute a HSV histogram for the ROI and store the bounding box
roiHist = cv2.calcHist([roi], [0], None, [16], [0, 180])
roiHist = cv2.normalize(roiHist, roiHist, 0, 255, cv2.NORM_MINMAX)
return (tl[0], tl[1], br[0], br[1])
def do_camshift():
global frame, roiBox
# convert the current frame to the HSV color space and perform mean shift
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
backProj = cv2.calcBackProject([hsv], [0], roiHist, [0, 180], 1)
# apply cam shift to the back projection, convert the points to a bounding box, and then draw them
(r, roiBox) = cv2.CamShift(backProj, roiBox, termination)
pts = np.int0(cv2.boxPoints(r))
cv2.polylines(frame, [pts], True, (0, 255, 0), 2)
def main():
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
help = "path to the (optional) video file")
args = vars(ap.parse_args())
# grab the reference to the current frame, list of ROI points and whether or not it is ROI selection mode
global frame, roiPts, inputMode, roiBox, termination
# if the video path was not supplied, grab the reference to the camera
if not args.get("video", False):
camera = cv2.VideoCapture(0)
# camera = cv2.VideoCapture("/home/idan/Desktop/b.mp4")
# otherwise, load the video
else:
camera = cv2.VideoCapture(args["video"])
# setup the mouse callback
cv2.namedWindow("frame")
cv2.setMouseCallback("frame", select_ROI)
# initialize the termination criteria for cam shift, indicating a maximum of ten iterations or movement by a least one pixel along with the bounding box of the ROI
termination = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
roiBox = None
# keep looping over the frames
while True:
# grab the current frame
(grabbed, frame) = camera.read()
# check to see if we have reached the end of the video
if not grabbed:
break
# handle if the 'i' key is pressed, then go into ROI selection mode
key = cv2.waitKey(1) & 0xFF
if key == ord("i") and len(roiPts) < 4:
roiBox = determine_ROI_for_first_time()
# if the see if the ROI has been computed
print roiBox
if roiBox is not None:
do_camshift()
# show the frame and record if the user presses a key
cv2.imshow("frame", frame)
# wait, if the 'q' key is pressed, stop the loop
if key == ord("q"):
break
# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()

Categories

Resources