OpenCV Python 中的运动跟踪

3
我一直在尝试制作一个运动跟踪器,以追踪录制在顶部的视频中移动的狗,并检索出显示狗的裁剪视频并忽略其余背景的内容。
我首先尝试使用opencv 3中可用的算法(BOOSTING、MIL、KCF、TLD、MEDIANFLOW、GOTURN(返回错误,尚未解决))进行对象跟踪,从此链接中获取。我甚至尝试了通过减去第一帧来进行基本的运动跟踪算法,但是它们都没有给出良好的结果。链接 我希望代码有一个预设的矩形框,一旦检测到运动,就会围绕运动区域。就像这个视频中的那样。
我对OPENCV不是很熟悉,但我相信单一运动跟踪不应该是一个问题,因为已经有很多相关工作已经完成。我是否应该考虑其他库/API,或者是否有更好的代码/教程可以让我完成这个任务?我的目的是将其与神经网络一起使用(这就是为什么我试图使用python/opencv解决它的原因)。
感谢任何帮助/建议。
编辑:
我删除了之前的代码,以使帖子更加清洁。
此外,根据我得到的反馈和进一步的研究,我能够修改一些代码,使其接近我想要的结果。然而,我仍然有一个烦人的跟踪问题。似乎第一帧影响了后面的跟踪,因为即使狗移动了,它仍然保持检测到的第一个位置。我尝试使用标志来限制只跟踪1个动作,但检测会出现问题。这是代码和显示结果的图片:
jimport imutils
import time
import cv2

previousFrame = None

def searchForMovement(cnts, frame, min_area):

    text = "Undetected"

    flag = 0

    for c in cnts:
        # if the contour is too small, ignore it
        if cv2.contourArea(c) < min_area:
            continue

        #Use the flag to prevent the detection of other motions in the video
        if flag == 0:
            (x, y, w, h) = cv2.boundingRect(c)

            #print("x y w h")
            #print(x,y,w,h) 
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
            text = "Detected"
            flag = 1

    return frame, text

def trackMotion(ret,frame, gaussian_kernel, sensitivity_value, min_area):


    if ret:

        # Convert to grayscale and blur it for better frame difference
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        gray = cv2.GaussianBlur(gray, (gaussian_kernel, gaussian_kernel), 0)



        global previousFrame

        if previousFrame is None:
            previousFrame = gray
            return frame, "Uninitialized", frame, frame



        frameDiff = cv2.absdiff(previousFrame, gray)
        thresh = cv2.threshold(frameDiff, sensitivity_value, 255, cv2.THRESH_BINARY)[1]

        thresh = cv2.dilate(thresh, None, iterations=2)
        _, cnts, _ = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        frame, text = searchForMovement(cnts, frame, min_area)
        #previousFrame = gray

    return frame, text, thresh, frameDiff




if __name__ == '__main__':

    video = "Track.avi"
    video0 = "Track.mp4"
    video1= "Ntest1.avi"
    video2= "Ntest2.avi"

    camera = cv2.VideoCapture(video1)
    time.sleep(0.25)
    min_area = 5000 #int(sys.argv[1])

    cv2.namedWindow("Security Camera Feed")


    while camera.isOpened():

        gaussian_kernel = 27
        sensitivity_value = 5
        min_area = 2500

        ret, frame = camera.read()

        #Check if the next camera read is not null
        if ret:
            frame, text, thresh, frameDiff = trackMotion(ret,frame, gaussian_kernel, sensitivity_value, min_area)

        else:
            print("Video Finished")
            break


        cv2.namedWindow('Thresh',cv2.WINDOW_NORMAL)
        cv2.namedWindow('Frame Difference',cv2.WINDOW_NORMAL)
        cv2.namedWindow('Security Camera Feed',cv2.WINDOW_NORMAL)

        cv2.resizeWindow('Thresh', 800,600)
        cv2.resizeWindow('Frame Difference', 800,600)
        cv2.resizeWindow('Security Camera Feed', 800,600)
      # uncomment to see the tresh and framedifference displays                  
        cv2.imshow("Thresh", thresh)
        cv2.imshow("Frame Difference", frameDiff)



        cv2.putText(frame, text, (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        cv2.imshow("Security Camera Feed", frame)

        key = cv2.waitKey(3) & 0xFF
        if key == 27 or key == ord('q'):
            print("Bye")
            break

    camera.release()
cv2.destroyAllWindows()

这张图片展示了第一帧仍然影响着帧差结果,这迫使包围框覆盖了没有运动的区域。

Result showing the frame difference and video display

这个案例展示了当忽略运动并错误地检测到不存在的运动(视频第二帧和第一帧之间的帧差)时的情况。当我允许多重跟踪时,它会同时跟踪两者,但仍然是错误的,因为它检测到了一个空的区域。

enter image description here

有人知道代码哪里出错或者缺少了什么吗?我一直在尝试但是无法使其正常工作。

提前感谢!!


你的代码呢?不要只放链接。 - Kinght 金
@Silencer 我已经在编辑中添加了。感谢您的评论。 - Wazaki
我认为你应该先正确地识别问题,然后再尝试解决方案。你想要首先检测运动...也许跟踪这个物体?或者只是在每一步上检测运动?你提到的第一个算法仅用于跟踪,而不是检测,这就是为什么你需要ROI(这是你要跟踪的“物体”)。另外,如果有多个物体在移动会发生什么?我建议你先正确地检测运动,可以尝试类似这样的方法 - api55
那么你有两个任务,尝试正确完成第一个任务,第二个任务可以尝试使用已知区域跟踪算法。 - api55
1
@Lewis,我用这种方法没有得到令人满意的结果,如果你的背景不是静态的话,情况会更加复杂。最终我使用了YOLO进行物体检测以进行跟踪。 - Wazaki
显示剩余5条评论
1个回答

1
为了包含动态检测,我已在NPM注册表和Docker Hub上创建了通用组件。这些组件可以检测客户端Web摄像头上的动态,并使用基于OpenCV的Python服务器进行处理。因此,客户端只需捕获Web摄像头图像,服务器就会使用OpenCV分析这些图像以确定是否有动态。客户端可以指定回调函数,每次发现动态时服务器都会调用该函数。服务器只是一个Docker镜像,您可以拉取并运行,并将其URL指定给客户端。 NPM注册表(客户端) 注册表链接:
https://www.npmjs.com/settings/kunalpimparkhede/packages

命令

npm install motion-detector-client

Docker镜像(服务器)

链接

https://hub.docker.com/r/kunalpimparkhede/motiondetectorwebcam

命令

docker pull kunalpimparkhede/motiondetectorwebcam

你只需要编写以下代码即可实现运动检测:

用法:

import MotionDetectingClient from './MotionDetectingClient';

<MotionDetectingClient server="http://0.0.0.0:8080" callback={handleMovement}/>

function handleMovement(pixels) 
{
console.log("Movement By Pixel="+pixels)
}

在服务器端:只需在8080端口启动Docker服务器即可:
docker run --name motion-detector-server-app -P 8080:5000 motion-detector-server-app

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接