美文网首页Python_图像处理
【图像工程入门】OpenCV检测器和跟踪器(运动物体检测跟踪)

【图像工程入门】OpenCV检测器和跟踪器(运动物体检测跟踪)

作者: 不给自己画饼 | 来源:发表于2021-07-19 20:36 被阅读0次

    一、原理

    OpenCV内置目标检测

    OpenCV内置的目标检测主要是对于特定物体(人脸)或者运动物体进行检测,本例使用OpenCV中的MOG2算法对运动的目标进行检测,检测后使用腐蚀、膨胀进行处理,得到较合理的初步目标检测区域。

    OpenCV内置目标跟踪

    使用OpenCV内置的MIL跟踪器或者DaSiamRPN跟踪器,使用其对于已经检测到的目标进行跟踪,以达到增强软件检测结果稳定性的目的。

    软件设计目标

    通过结合OpenCV内置的两种算法,达到较为稳定的目标检测目的。

    二、软件设计

    软件主要设计如图所示,表征了软件的循环结构


    循环中每次调用类方法(process_one_frame)

    需要强调的是,本例完成匆忙仅采用了简单的平均值滤波器,但是本例非常适合采用卡尔曼滤波器对于检测和跟踪的结果进行预测。

    三、代码

    将上述软件设计封装在类中

    import copy
    
    import cv2
    import numpy as np
    
    class ImageProcessorCloseLoop:
        def __init__(self, subtractor_type="MOG2", tracker_type="DaSiamRPN"):
            self.sub = self.create_subtractor(subtractor_type)
            self.tracker_type = tracker_type
            self.trackers = list()
    
        def create_subtractor(self, subtractor_type):
            if subtractor_type == "MOG2":
                return cv2.createBackgroundSubtractorMOG2()
            elif subtractor_type == "KNN":
                return cv2.createBackgroundSubtractorKNN()
    
        def create_tracker(self, tracker_type):
            if tracker_type == "MIL":
                return cv2.TrackerMIL_create()
            elif tracker_type == "GOTURN":
                return cv2.TrackerGOTURN_create()
            elif tracker_type == "DaSiamRPN":
                return cv2.TrackerDaSiamRPN_create()
    
        def process_one_frame(self, frame):
            '''
            :param frame: original video frame image (np.ndarray)
            :return: bboxes (tuple of bbox)
            '''
            detect_result = self.simple_detect(frame)
            track_result = list()
            for tracker in self.trackers:
                ok, bbox = tracker.update(frame)
                if ok:
                    track_result.append(bbox)
                else:
                    self.trackers.remove(tracker)
            matched_detect, matched_track, only_detect, only_track = self.compare_result(detect_result, track_result)
    
            res_matched = list()
            for i in range(len(matched_track)):
                bb1 = matched_detect[I]
                bb2 = matched_track[I]
                bb_res = self.bb_filter2(bb1, bb2)
                res_matched.append(bb_res)
    
            res_track = only_track
            res_detect = only_detect
    
            for res in res_detect:
                tracker = self.create_tracker(tracker_type=self.tracker_type)
                # tracker.init(frame, res)
    
            res = res_matched + res_track + res_detect
            return res
    
        def simple_detect(self, img: np.ndarray):
            mask = self.sub.apply(img)
            thresh, bw = cv2.threshold(mask, 120, 255, cv2.THRESH_OTSU)
            kernel = np.ones((3, 3), dtype=int)
            dilated = cv2.erode(bw, kernel, iterations=1)
            inflated = cv2.dilate(dilated, kernel, iterations=1)
            # find contour:
            cnts, hier = cv2.findContours(inflated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            bboxes = list()
            for i in range(len(cnts), 0, -1):
                c = cnts[i - 1]
                area = cv2.contourArea(c)
                if area < 10:
                    continue
                bbox = cv2.boundingRect(c)
                x, y, w, h = bbox
                diameter = w if w > h else h
                if diameter <= 15:
                    continue
                bboxes.append(bbox)
            return bboxes
    
        def compare_two(self, bb1, bb2):
            '''
            compare two bbox
            :param bb1: bbox tuple (x, y, w, h)
            :param bb2: bbox tuple
            :return: True or False
            '''
            x1, y1, w1, h1 = bb1
            x2, y2, w2, h2 = bb2
            IOU1 = (min(x1 + w1, x2 + w2) - max(x1, x2)) / (max(x1 + w1, x2 + w2) - min(x1, x2))
            IOU2 = (min(y1 + h1, y2 + h2) - max(y1, y2)) / (max(y1 + h1, y2 + h2) - min(x1, x2))
            IOU = IOU2 * IOU1
            if IOU > 0.9:
                return True
            else:
                return False
    
        def compare_result(self, detect_res, track_res):
            '''
            compare the detect results by comparing IOU of the bboxes
            :param last_res: list of bboxes
            :param this_res: list of bboxes
            :return: tuple (matched, new, only_last)
            '''
            matched_detect = list()
            matched_track = list()
            track = list()
            detect = list()
    
            for track_box in track_res:
                for detect_box in detect_res:
                    is_matched = self.compare_two(track_box, detect_box)
                    if is_matched:
                        matched_track.append(track_box)
                        matched_detect.append(detect_box)
                        detect_res.remove(detect_box)
                    else:
                        track.append(track_box)
    
            for detect_box in detect_res:
                detect.append(detect_box)
            return matched_detect, matched_track, detect, track
    
        def bb_filter2(self, bbox1, bbox2, method="mean"):
            '''
            :param bbox1:bbox (x, y, w, h)
            :param bbox2:bbox
            :return: bbox
            '''
            if method == "mean":
                return (bbox1[0] + bbox2[0])/2, (bbox1[1] + bbox2[1])/2, (bbox1[2] + bbox2[2])/2, (bbox1[3] + bbox2[3])/2
    
    

    实例化类和视频读取循环写在main.py

    main.py
    import cv2
    import processor
    
    if __name__=="__main__":
        cap = cv2.VideoCapture("/Users/wanglingyu/sources/video1.mp4")
    
        proc = processor.ImageProcessorCloseLoop(tracker_type="MIL")
    
        ret, frame = cap.read()
        if not ret:
            exit(1)
    
        while True:
            ret, frame = cap.read()
            if not ret:
                break
    
            bboxes = proc.process_one_frame(frame)
            for bbox in bboxes:
                x, y, w, h = bbox
                cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 0xff), 1)
    
            cv2.imshow("Video", frame)
            key = cv2.waitKey(10)
            if key == ord(" "):
                k1 = cv2.waitKey()
    
    
        cap.release()
        cv2.destroyAllWindows()
    
    

    四、效果

    能够稳定地对于目标进行检测,且检测框不易丢失。


    目标检测效果

    五、环境配置

    本例代码运行于macOS 11.4 Big Sur上,该系统运行于arm平台的M1芯片上,其中OpenCV若需要编译则需要在配置cmake时配置好python2或python3的各个选项。如果使用PyCharm软件则在其内置的软件仓库中直接安装即可使用,兼容性没有问题。

    相关文章

      网友评论

        本文标题:【图像工程入门】OpenCV检测器和跟踪器(运动物体检测跟踪)

        本文链接:https://www.haomeiwen.com/subject/wbghmltx.html