首先了解什么是模拟退火,模拟退火相比较于爬上算法优点就是从局部最优解突破到全局最优解
可以看一下这篇文章最优化算法之模拟退火算法(SA)。
那么使用模拟退火实现跟踪的代码如下:
get_entropy方法用来计算能量,这里是使用的互信息熵值作为能量。
sa就是模拟退火算法。
使用模拟退火进行跟踪只是一次学习的过程,重在学习。跟踪过程一整个胡蹦乱跳的/(ㄒoㄒ)/~~
应该是因为sa中随机扰动值的问题吧。模拟退火用来跟踪是不合理的。
import cv2
import numpy as np
import random
import math
import time
start_time=time.time()
cap=cv2.VideoCapture('m.mp4')
ok,frame=cap.read()
roi=cv2.selectROI(frame,True,False)
width,hight,w,h = roi
img_roi = frame[hight:hight+h , width:width+w]
cv2.imwrite('img_roi.jpg',img_roi)
out=cv2.VideoWriter('draw_mouse.mp4',fourcc=cv2.VideoWriter_fourcc('M', 'P', '4', 'V'),fps=30,frameSize=[720,720])
#选取图片的高宽
img_h,img_w=img_roi.shape[:2]
def get_entropy(h,w,target,template):
Hd = 0.0
Pa = np.zeros(256, np.float)
SumPa = template.shape[0] * template.shape[1]
# 统计模板图片每个灰度值的数量
dis_template, _ = np.histogram(template.ravel(), 256, [0, 256])
# 计算模板图片的信息熵
for i in range(256): # 遍历每个灰度值
if dis_template[i] != 0:
# 计算每个灰度值的概率
Pa[i] = dis_template[i] / SumPa
# 计算每个灰度值的概率的自然对数
lgPa = math.log(Pa[i], 2)
# 计算信息熵
Hd += -(Pa[i] * lgPa)
# 2.计算目标图片的信息
HS = 0 # 记录每个候选框信息熵
Pb = np.zeros(256, np.float) # 记录每个候选框中每个灰度值的概率
# 统计模板图片每个灰度值的数量
target_cut = target[int(h):int(h + template.shape[0]), int(w):int(w + template.shape[1])]
dis_target, _ = np.histogram(target_cut.ravel(), 256, [0, 256])
# 计算模板图片的信息熵
for i in range(256): # 遍历每个灰度值
if dis_target[i] != 0:
# 计算每个灰度值的概率
Pb[i] = dis_target[i] / SumPa
# 计算每个灰度值的概率的自然对数
lgPb = math.log(Pb[i], 2)
# 计算信息熵
HS += -(Pb[i] * lgPb)
# 3. 计算联合概率分布
HdS = 0
for a in range(256):
if dis_template[a] != 0:
for b in range(256):
if dis_target[b] != 0:
Pab = Pa[a] * Pb[b]
lgPab = math.log(Pab, 2)
HdS += -(Pab * lgPab)
# 4.计算互信息熵值
IdS = Hd + HS - HdS
return IdS
def sa(target,template):
T = 150 # 初始值
t = T
min = 100 # 最小值
k = 20 # 内循环迭代次数
d = 0.9
# 随机框的范围
boundary_x = target.shape[0] - template.shape[0]
boundary_y = target.shape[1] - template.shape[1]
# 生成随机框的坐标
x = np.random.randint(0, boundary_x, [k])
y = np.random.randint(0, boundary_y, [k])
result = 0
h, w = 0, 0
# 外循环
z = 0
while t > min:
# 内循环
z += 1
for i in range(k):
trans = get_entropy(x[i], y[i], target, template)
x_new = x[i] + t * (random.random() - random.random())*0.01
y_new = y[i] + t * (random.random() - random.random())*0.01
if x_new >= 0 and x_new <= boundary_x and y_new >= 0 and y_new <= boundary_y:
trans_new = get_entropy(x[i], y[i], target, template)
if trans_new > trans:
x[i] = x_new
y[i] = y_new
else:
p = 1 / (1 + math.exp(-(trans_new - trans) / T))
if random.random() < p:
x[i] = x_new
y[i] = y_new
t = t * d # 每外循环一次迭代,温度降低
for i in range(k):
if result < get_entropy(x[i], y[i], target, template):
h, w = x[i], y[i]
result = get_entropy(x[i], y[i], target, template)
return h, w
f_s=1
while cap.isOpened():
ok,frame=cap.read()
if not ok:
break
print(f_s)
f_s+=1
frame_g=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
img_g=cv2.cvtColor(img_roi,cv2.COLOR_BGR2GRAY)
h,w=sa(frame_g,img_g)
print(h,w)
draw=cv2.rectangle(frame,(w,h),(w+img_w,h+img_h),color=[0,0,255],thickness=2)
cv2.imshow('demo',draw)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
out.write(draw)
cap.release()
out.release()
cv2.destroyAllWindows()
end_t=time.time()
print(end_t-start_time)