当前位置: 首页 > news >正文

目标跟踪——KCF源码用python实现

from numpy.fft import fft2, ifft2, fftshift
import cv2
import numpy as npclass HOG:def __init__(self, winSize):""":param winSize: 检测窗口的大小"""self.winSize = winSizeself.blockSize = (8, 8)self.blockStride = (4, 4)self.cellSize = (4, 4)self.nBins = 9self.hog = cv2.HOGDescriptor(winSize, self.blockSize, self.blockStride,self.cellSize, self.nBins)def get_feature(self, image):winStride = self.winSizew, h = self.winSizew_block, h_block = self.blockStridew = w//w_block - 1h = h//h_block - 1# 计算给定图像的HOG特征描述子,一个n*1的特征向量hist = self.hog.compute(img=image, winStride=winStride, padding=(0, 0))return hist.reshape(w, h, 36).transpose(2, 1, 0)    # 交换轴的顺序def show_hog(self, hog_feature):c, h, w = hog_feature.shapefeature = hog_feature.reshape(2, 2, 9, h, w).sum(axis=(0, 1))grid = 16hgrid = grid // 2img = np.zeros((h*grid, w*grid))for i in range(h):for j in range(w):for k in range(9):x = int(10 * feature[k, i, j] * np.cos(x=np.pi / 9 * k))y = int(10 * feature[k, i, j] * np.sin(x=np.pi / 9 * k))cv2.rectangle(img=img, pt1=(j*grid, i*grid), pt2=((j + 1) * grid, (i + 1) * grid),color=(255, 255, 255))x1 = j * grid + hgrid - xy1 = i * grid + hgrid - yx2 = j * grid + hgrid + xy2 = i * grid + hgrid + ycv2.line(img=img, pt1=(x1, y1), pt2=(x2, y2), color=(255, 255, 255), thickness=1)cv2.imshow("img", img)cv2.waitKey(0)class Tracker:def __init__(self):# 超参数设置self.max_patch_size = 256self.padding = 2.5self.sigma = 0.6self.lambdar = 0.0001self.update_rate = 0.012self.gray_feature = Falseself.debug = False# 算法变量定义self.scale_h = 0.self.scale_w = 0.self.ph = 0self.pw = 0self.hog = HOG((self.pw, self.pw))self.alphaf = Noneself.x = Noneself.roi = Nonedef first_frame(self, image, roi):"""对视频的第一帧进行标记,更新tracer的参数:param image: 第一帧图像:param roi: 第一帧图像的初始ROI元组:return: None"""x1, y1, w, h = roicx = x1 + w // 2cy = y1 + h // 2roi = (cx, cy, w, h)# 确定Patch的大小,并在此Patch中提取HOG特征描述子scale = self.max_patch_size / float(max(w, h))self.ph = int(h * scale) // 4 * 4 + 4self.pw = int(w * scale) // 4 * 4 + 4self.hog = HOG((self.pw, self.ph))# 在矩形框的中心采样、提取特征x = self.get_feature(image, roi)y = self.gaussian_peak(x.shape[2], x.shape[1])self.alphaf = self.train(x, y, self.sigma, self.lambdar)self.x = xself.roi = roidef update(self, image):"""对给定的图像,重新计算其目标的位置:param image::return:"""# 包含矩形框信息的四元组(min_x, min_y, w, h)cx, cy, w, h = self.roimax_response = -1   # 最大响应值for scale in [0.95, 1.0, 1.05]:# 将ROI值处理为整数roi = map(int, (cx, cy, w * scale, h * scale))z = self.get_feature(image, roi)    # tuple(36, h, w)# 计算响应responses = self.detect(self.x, z, self.sigma)height, width = responses.shapeif self.debug:cv2.imshow("res", responses)cv2.waitKey(0)idx = np.argmax(responses)res = np.max(responses)if res > max_response:max_response = resdx = int((idx % width - width / 2) / self.scale_w)dy = int((idx / width - height / 2) / self.scale_h)best_w = int(w * scale)best_h = int(h * scale)best_z = z# 更新矩形框的相关参数self.roi = (cx + dx, cy + dy, best_w, best_h)# 更新模板self.x = self.x * (1 - self.update_rate) + best_z * self.update_ratey = self.gaussian_peak(best_z.shape[2], best_z.shape[1])new_alphaf = self.train(best_z, y, self.sigma, self.lambdar)self.alphaf = self.alphaf * (1 - self.update_rate) + new_alphaf * self.update_ratecx, cy, w, h = self.roireturn cx - w // 2, cy - h // 2, w, hdef get_feature(self, image, roi):"""对特征进行采样:param image::param roi: 包含矩形框信息的四元组(min_x, min_y, w, h):return:"""# 对矩形框做2.5倍的Padding处理cx, cy, w, h = roiw = int(w*self.padding)//2*2h = int(h*self.padding)//2*2x = int(cx - w//2)y = int(cy - h//2)# 矩形框所覆盖的距离sub_img = image[y:y+h, x:x+w, :]resized_img = cv2.resize(src=sub_img, dsize=(self.pw, self.ph))if self.gray_feature:feature = cv2.cvtColor(resized_img, cv2.COLOR_BGR2GRAY)feature = feature.reshape(1, self.ph, self.pw)/255.0 - 0.5else:feature = self.hog.get_feature(resized_img)if self.debug:self.hog.show_hog(feature)# Hog特征的通道数、高估、宽度fc, fh, fw = feature.shapeself.scale_h = float(fh)/hself.scale_w = float(fw)/w# 两个二维数组,前者(fh,1),后者(1,fw)hann2t, hann1t = np.ogrid[0:fh, 0:fw]hann1t = 0.5 * (1 - np.cos(2 * np.pi * hann1t / (fw - 1)))hann2t = 0.5 * (1 - np.cos(2 * np.pi * hann2t / (fh - 1)))# 一个fh x fw的矩阵hann2d = hann2t * hann1tfeature = feature * hann2dreturn featuredef gaussian_peak(self, w, h):""":param w::param h::return:      一个w*h的高斯矩阵"""output_sigma = 0.125sigma = np.sqrt(w * h) / self.padding * output_sigmasyh, sxh = h//2, w//2y, x = np.mgrid[-syh:-syh + h, -sxh:-sxh + w]x = x + (1 - w % 2) / 2.y = y + (1 - h % 2) / 2.g = 1. / (2. * np.pi * sigma ** 2) * np.exp(-((x ** 2 + y ** 2) / (2. * sigma ** 2)))return gdef kernel_correlation(self, x1, x2, sigma):"""核化的相关滤波操作:param x1::param x2::param sigma:   高斯参数sigma:return:"""# 转换到傅里叶空间fx1 = fft2(x1)fx2 = fft2(x2)# \hat{x^*} \otimes \hat{x}',x*的共轭转置与x'的乘积tmp = np.conj(fx1) * fx2# 离散傅里叶逆变换转换回真实空间idft_rbf = ifft2(np.sum(tmp, axis=0))# 将零频率分量移到频谱中心。idft_rbf = fftshift(idft_rbf)# 高斯核的径向基函数d = np.sum(x1 ** 2) + np.sum(x2 ** 2) - 2.0 * idft_rbfk = np.exp(-1 / sigma ** 2 * np.abs(d) / d.size)return kdef train(self, x, y, sigma, lambdar):"""原文所给参考train函数:param x::param y::param sigma::param lambdar::return:"""k = self.kernel_correlation(x, x, sigma)return fft2(y) / (fft2(k) + lambdar)def detect(self, x, z, sigma):"""原文所给参考detect函数:param x::param z::param sigma::return:"""k = self.kernel_correlation(x, z, sigma)# 傅里叶逆变换的实部return np.real(ifft2(self.alphaf * fft2(k)))def track(video_path):cap = cv2.VideoCapture(video_path)tracker = Tracker()ok, frame = cap.read()if not ok:print("error reading video")exit(-1)roi = cv2.selectROI("tracking", frame, False, False)# roi = (218, 302, 148, 108)tracker.first_frame(frame, roi)while cap.isOpened():ok, frame = cap.read()if not ok:breakx, y, w, h = tracker.update(frame)cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 255), 1)cv2.imshow('tracking', frame)c = cv2.waitKey(1) & 0xFFif c == 27 or c == ord('q'):breakcap.release()cv2.destroyAllWindows()if __name__ == '__main__':video_path = r'D:\desk\Work\API\fpga\siamfc-pytorch\video\444.mp4'track(video_path=video_path)

参考链接

https://blog.csdn.net/qq_59109986/article/details/127892628

相关文章:

  • 本地无法连接linux上的MariaDB数据库
  • 好用的便签是什么 电脑桌面上好用的便签
  • 【51单片机基础教程】点亮led
  • go编程中接口(interface)用法
  • springboot基于Web的社区医院管理服务系统 LW+ PPT+源码+讲解
  • 深入理解和实现Windows进程间通信(共享内存)
  • 防火墙规则来阻止攻击者的 IP 地址
  • Vim入门教程
  • 9、PHP 实现调整数组顺序使奇数位于偶数前面
  • 【CT】LeetCode手撕—300. 最长递增子序列
  • 手机在网状态-手机在网状态查询-手机在网站状态接口
  • wsl2平台鸿蒙全仓docker编译环境快速创建方法
  • Spring自定义标签体系和应用
  • 嵌入式软件stm32面试
  • 如何减少sql出现问题
  • 77. Combinations
  • Cookie 在前端中的实践
  • docker python 配置
  • IDEA常用插件整理
  • iOS小技巧之UIImagePickerController实现头像选择
  • JavaScript标准库系列——Math对象和Date对象(二)
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 聊聊redis的数据结构的应用
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 异步
  • 译有关态射的一切
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 正则表达式小结
  • - 转 Ext2.0 form使用实例
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • # Maven错误Error executing Maven
  • #QT(QCharts绘制曲线)
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (黑马C++)L06 重载与继承
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (转载)OpenStack Hacker养成指南
  • *上位机的定义
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .NET关于 跳过SSL中遇到的问题
  • .NET框架设计—常被忽视的C#设计技巧
  • @Conditional注解详解
  • @EnableConfigurationProperties注解使用
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [100天算法】-不同路径 III(day 73)
  • [AIGC] Kong:一个强大的 API 网关和服务平台
  • [Android实例] 保持屏幕长亮的两种方法 [转]
  • [C++]18:set和map的使用
  • [CentOs7]iptables防火墙安装与设置
  • [cocos2d-x]关于CC_CALLBACK
  • [go-zero] 简单微服务调用
  • [GXYCTF2019]禁止套娃
  • [HackMyVM]靶场 VivifyTech
  • [IE编程] IE中对网页进行截图的编程接口
  • [Java并发编程实战] 共享对象之可见性
  • [js] 正则表达式