From 0189e02bbc46c7aeecad29f9289d3b08a47a5d1e Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 1 Jul 2024 12:28:47 +0200 Subject: [PATCH] - defined COLORs added legend - ocv_template_mnatching uses video --- ocv_template_matching.py | 83 +++++++++++++++++++++++++++++----------- ocv_track.py | 50 ++++++++++++++---------- template_matcher.py | 6 ++- 3 files changed, 93 insertions(+), 46 deletions(-) diff --git a/ocv_template_matching.py b/ocv_template_matching.py index c5b22cb..73c0eb9 100644 --- a/ocv_template_matching.py +++ b/ocv_template_matching.py @@ -1,8 +1,15 @@ import cv2 import sys +import imutils as im from util import bbox_extend, bbox_round, image_crop, to_rect, bbox_add_position +COLOR_TRACKER = (0, 255, 0) +COLOR_TRACKER_EXT = (0, 255, 255) +COLOR_MATCHER = (0, 0, 255) +COLOR_TEMPLATE = (255, 0, 0) +IMG_SCALE_UP = 1 +TEMPLATE_MATCH_OVERLAP = 1 video = cv2.VideoCapture("./data/IMG_1730.MP4") @@ -18,35 +25,65 @@ if not ok: print('Cannot read video file') sys.exit() -bb_crop = bbox_extend(cv2.selectROI("Image", image, False), 1) +bb_crop = bbox_extend(cv2.selectROI("Image", image, False), TEMPLATE_MATCH_OVERLAP) crop = image_crop(image.copy(), bb_crop) bb_template = cv2.selectROI("Image", crop, False) template = image_crop(crop, bb_template) -# Perform template match operations -res = cv2.matchTemplate(crop, template, cv2.TM_CCOEFF_NORMED) -(min_val, max_val, min_loc, max_loc) = cv2.minMaxLoc(res) - -matcher_bbox_local = (max_loc[0], max_loc[1], template.shape[1], template.shape[0]) -matcher_top_left_local, matcher_bottom_right_local = to_rect(matcher_bbox_local) - -matcher_bbox_global = bbox_round(bbox_add_position(matcher_bbox_local, bb_crop)) -matcher_top_left_global, matcher_bottom_right_global = to_rect(matcher_bbox_global) - -template_top_left, template_bottom_right = to_rect(bb_template) - -cv2.rectangle(crop, template_top_left, template_bottom_right, (255, 0, 0), 3) -cv2.rectangle(crop, matcher_top_left_local, matcher_bottom_right_local, (0, 255, 0), 1) - -cv2.rectangle(image, matcher_top_left_global, matcher_bottom_right_global, (0, 0, 255), 1) - -cv2.imshow("Crop", crop) -cv2.imshow("Image", image) -cv2.imshow("Matcher", res) +# Initialize tracker with first frame and bounding box +tracker = cv2.TrackerKCF().create() +tracker.init(image, bb_crop) while True: - # Exit if ESC pressed - k = cv2.waitKey(1) & 0xff + # Read a new frame + ok, image = video.read() + if not ok: + break + + # Start timer + timer = cv2.getTickCount() + + # Update tracker + ok, bb_crop = tracker.update(image) + crop = image_crop(image.copy(), bb_crop) + image_anno = image.copy() + + if ok: + # Perform template match operations + crop_scaled = im.resize(crop, IMG_SCALE_UP * crop.shape[0], IMG_SCALE_UP * crop.shape[1]) + template_scaled = im.resize(template, IMG_SCALE_UP * template.shape[0], IMG_SCALE_UP * template.shape[1]) + res = cv2.matchTemplate(crop_scaled, template_scaled, cv2.TM_CCOEFF_NORMED) + (min_val, max_val, min_loc, max_loc) = cv2.minMaxLoc(res) + + matcher_bbox_local = (max_loc[0]/IMG_SCALE_UP, max_loc[1]/IMG_SCALE_UP, template.shape[1], template.shape[0]) + matcher_top_left_local, matcher_bottom_right_local = to_rect(bbox_round(matcher_bbox_local)) + + matcher_bbox = bbox_round(bbox_add_position(matcher_bbox_local, bb_crop)) + matcher_rect = to_rect(matcher_bbox) + + tracker_rect = to_rect(bb_crop) + template_top_left, template_bottom_right = to_rect(bb_template) + + cv2.rectangle(crop, template_top_left, template_bottom_right, COLOR_TEMPLATE, 3) + cv2.rectangle(crop, matcher_top_left_local, matcher_bottom_right_local, COLOR_MATCHER, 1) + + cv2.rectangle(image_anno, matcher_rect[0], matcher_rect[1], COLOR_MATCHER, 1) + cv2.rectangle(image_anno, tracker_rect[0], tracker_rect[1], COLOR_TRACKER, 1) + matcher_crop = image_crop(image, matcher_bbox) + + cv2.imshow("Crop", crop) + cv2.imshow("Image", image_anno) + cv2.imshow("Matcher res", res) + cv2.imshow("Matcher view", matcher_crop) + + while True: + # Exit if ESC pressed + k = cv2.waitKey(1) & 0xff + if k == 27: + break + if k == 32: + break + if k == 27: break diff --git a/ocv_track.py b/ocv_track.py index d0e8f57..7528cb9 100644 --- a/ocv_track.py +++ b/ocv_track.py @@ -6,16 +6,16 @@ from template_matcher import template_match_rotation from util import bbox_extend, bbox_round, process_image_bbox, image_crop, bbox_add_position, to_rect IMG_SCALE_UP = 1 -TEMPLATE_MATCH_OVERLAP = 0.5 +TEMPLATE_MATCH_OVERLAP = 1 def match(source, template, angle, center): # coarse - angle_c, loc = template_match_rotation(source, template, angle, center) + angle_c, loc, res = template_match_rotation(source, template, angle, center) # fine - angle, loc = template_match_rotation(source, template, angle_c, center, rot_min=-0.25, rot_max=+0.25, n_steps=20, scale=IMG_SCALE_UP) + angle, loc, res = template_match_rotation(source, template, angle_c, center, rot_min=-0.25, rot_max=+0.25, n_steps=20, scale=IMG_SCALE_UP) - return angle, loc + return angle, loc, res class Reference: @@ -85,6 +85,9 @@ print(f"ref_center = {ref_center}") tracker.create() tracker.init(frame_init, bbox_template) +COLOR_TRACKER = (0, 255, 0) +COLOR_TRACKER_EXT = (0, 255, 255) +COLOR_MATCHER = (0, 0, 255) current_angle = 0 path = [] line_from = None @@ -100,39 +103,40 @@ while True: # Update tracker ok, bbox_tracker = tracker.update(frame) - + print(f"Bbox Tracker: {bbox_tracker}") image_template_rotated = image_template bbox_tracker_ext = bbox_extend(bbox_tracker, TEMPLATE_MATCH_OVERLAP) if ok: - image_bbox = process_image_bbox(image_crop(frame, bbox_tracker_ext)) - current_angle, max_loc = match(image_bbox, image_template, current_angle, ref_center) + crop = image_crop(frame.copy(), bbox_tracker_ext) + current_angle, max_loc, matcher_res = match(process_image_bbox(crop), image_template, current_angle, ref_center) # determine the starting and ending (x, y)-coordinates of the # bounding box - (startX, startY) = max_loc - print(f"current_angle: {current_angle:.2f}, startX: {startX}, startY: {startY}") image_template_rotated = im.rotate(image_template, current_angle, center=ref_center) # Matcher - matcher_bbox = (max_loc[0], max_loc[1], image_template.shape[1], image_template.shape[0]) - matcher_bbox_global = bbox_round(bbox_add_position(matcher_bbox, bbox_tracker_ext)) - matcher_top_left, matcher_bottom_right = to_rect(matcher_bbox_global) - cv2.rectangle(frame, matcher_top_left, matcher_bottom_right, (255, 0, 0), 2) + matcher_bbox_local = (max_loc[0], max_loc[1], image_template.shape[1], image_template.shape[0]) + matcher_rect_local = to_rect(bbox_round(matcher_bbox_local)) + + matcher_bbox = bbox_round(bbox_add_position(matcher_bbox_local, bbox_tracker)) + matcher_rect = to_rect(matcher_bbox) # Tracker - tracker_top_left, tracker_bottom_right = to_rect(bbox_round(bbox_tracker)) - cv2.rectangle(frame, tracker_top_left, tracker_bottom_right, (0, 0, 255), 2) + tracker_rect = to_rect(bbox_round(bbox_tracker)) # Tracker ext - tracker_top_left, tracker_bottom_right = to_rect(bbox_round(bbox_tracker_ext)) - cv2.rectangle(frame, tracker_top_left, tracker_bottom_right, (255, 0, 255), 2) + tracker_ext_rect = to_rect(bbox_round(bbox_tracker_ext)) + + cv2.rectangle(frame, tracker_ext_rect[0], tracker_ext_rect[1], COLOR_TRACKER_EXT, 2) + cv2.rectangle(frame, tracker_rect[0], tracker_rect[1], COLOR_TRACKER, 2) + cv2.rectangle(frame, matcher_rect[0], matcher_rect[1], COLOR_MATCHER, 1) # Calculate Frames per second (FPS) fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer) # Draw path - line_to = (round(startX + bbox_tracker[0]), round(startY + bbox_tracker[1])) + line_to = matcher_rect[0] if line_from is not None: path.append({'from': line_from, 'to': line_to}) line_from = line_to @@ -145,16 +149,20 @@ while True: cv2.putText(frame, "Tracking failure detected", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) # Display tracker type on frame - cv2.putText(frame, tracker_type + " Tracker", (100, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2) + cv2.putText(frame, tracker_type + " Tracker", (100, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, COLOR_TRACKER, 2) + cv2.putText(frame, tracker_type + " Tracker Ext", (100, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.75, COLOR_TRACKER_EXT, 2) + cv2.putText(frame, tracker_type + " Matcher", (100, 100), cv2.FONT_HERSHEY_SIMPLEX, 0.75, COLOR_MATCHER, 2) # Display FPS on frame - cv2.putText(frame, "FPS : " + str(int(fps)), (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2) + cv2.putText(frame, "FPS : " + str(int(fps)), (100, 140), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2) # Display result cv2.imshow("Frame", frame) + cv2.imshow("Matcher", matcher_res) + cv2.imshow("Crop", image_crop(frame.copy(), matcher_bbox)) # Exit if ESC pressed - k = cv2.waitKey(1) & 0xff + k = cv2.waitKey(100) & 0xff if k == 27: break diff --git a/template_matcher.py b/template_matcher.py index 512e88d..824343e 100644 --- a/template_matcher.py +++ b/template_matcher.py @@ -8,7 +8,8 @@ def template_match_rotation(source, template, angle, center, rot_min=-1.0, rot_m best_angle = 0 best_r = 0 best_max_loc = 0 - r = 0 + best_res = None + im_source = im.resize(source, scale * source.shape[0], scale * source.shape[1]) for dangle in np.linspace(rot_min, rot_max, n_steps): # rotated and scale up to IMG_SCALE_UP-size @@ -23,6 +24,7 @@ def template_match_rotation(source, template, angle, center, rot_min=-1.0, rot_m best_r = r best_angle = dangle best_max_loc = (maxLoc[0]/scale, maxLoc[1]/scale) + best_res = res else: break @@ -30,4 +32,4 @@ def template_match_rotation(source, template, angle, center, rot_min=-1.0, rot_m loc_x = best_max_loc[0] loc_y = best_max_loc[1] - return angle, (loc_x, loc_y) + return angle, (loc_x, loc_y), best_res