simultaneous tracking (player and pokemon) support added

This commit is contained in:
niart120 2022-01-18 03:46:21 +09:00
parent efe3375618
commit e741278d1a

View File

@ -7,6 +7,7 @@ import time
import cv2
from xorshift import Xorshift
import calc
from collections import Counter
IDLE = 0xFF
SINGLE = 0xF0
@ -20,7 +21,7 @@ def tracking_blink(img, roi_x, roi_y, roi_w, roi_h, th = 0.9, size = 40)->Tuple[
"""measuring the type and interval of player's blinks
Returns:
blinks:List[int],intervals:list[int],offset_time:float: [description]
blinks:List[int], intervals:list[int], offset_time:float
"""
eye = img
@ -40,7 +41,7 @@ def tracking_blink(img, roi_x, roi_y, roi_w, roi_h, th = 0.9, size = 40)->Tuple[
offset_time = 0
# 瞬きの観測
# observe blinks
while len(blinks)<size or state!=IDLE:
_, frame = video.read()
time_counter = time.perf_counter()
@ -58,7 +59,7 @@ def tracking_blink(img, roi_x, roi_y, roi_w, roi_h, th = 0.9, size = 40)->Tuple[
if 0.01<match<th:
if state==IDLE:
blinks.append(0)
interval = (time_counter - prev_time)/1.018
interval = (time_counter - prev_time)/1.017
interval_round = round(interval)
intervals.append(interval_round)
@ -85,8 +86,8 @@ def tracking_blink(img, roi_x, roi_y, roi_w, roi_h, th = 0.9, size = 40)->Tuple[
cv2.destroyAllWindows()
return (blinks, intervals, offset_time)
def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, size = 60)->Tuple[List[int],List[int],float]:
"""measuring the type and interval of pokemon's blinks
def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, th = 0.85, size = 60)->Tuple[List[int],List[int],float]:
"""measuring the interval of pokemon's blinks
Returns:
intervals:list[int],offset_time:float: [description]
@ -106,7 +107,7 @@ def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, size = 60)->Tuple[List[
prev_time = time.perf_counter()
# 瞬きの観測
# observe blinks
while len(intervals)<size:
_, frame = video.read()
time_counter = time.perf_counter()
@ -115,12 +116,12 @@ def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, size = 60)->Tuple[List[
if (roi==prev_roi).all():
continue
prev_roi = roi
cv2.imshow("",roi)
cv2.imshow("",cv2.resize(roi, (roi_w*2, roi_h*2)))
cv2.waitKey(1)
res = cv2.matchTemplate(roi,eye,cv2.TM_CCOEFF_NORMED)
_, match, _, _ = cv2.minMaxLoc(res)
if 0.4<match<0.85:
if 0.4<match<th:
if state==IDLE:
interval = (time_counter - prev_time)
print(interval)
@ -135,6 +136,100 @@ def tracking_poke_blink(img, roi_x, roi_y, roi_w, roi_h, size = 60)->Tuple[List[
video.release()
return intervals
def simultaneous_tracking(plimg, plroi:Tuple[int,int,int,int], pkimg, pkroi:Tuple[int,int,int,int], plth=0.88, pkth=0.999185, size=8)->Tuple[List[int],List[int],float]:
"""measuring type/intervals of player's blinks and the interval of pokemon's blinks
note: this methods is very unstable. it not recommended to use.
Returns:
intervals:list[int],offset_time:float: [description]
"""
video = cv2.VideoCapture(0,cv2.CAP_DSHOW)
video.set(cv2.CAP_PROP_FRAME_WIDTH,1920)
video.set(cv2.CAP_PROP_FRAME_HEIGHT,1080)
video.set(cv2.CAP_PROP_BUFFERSIZE,1)
pl_state = IDLE
pk_state = IDLE
blinks = []
intervals = []
pl_prev = time.perf_counter()
pk_prev = time.perf_counter()
prev_roi = None
debug_txt = ""
offset_time = 0
blinkcounter = 0
# observe blinks
while len(blinks)<size or pl_state!=IDLE:
_, frame = video.read()
time_counter = time.perf_counter()
#player eye
roi_x,roi_y,roi_w,roi_h = plroi
roi = cv2.cvtColor(frame[roi_y:roi_y+roi_h,roi_x:roi_x+roi_w],cv2.COLOR_RGB2GRAY)
if (roi==prev_roi).all():
continue
prev_roi = roi
res = cv2.matchTemplate(roi,plimg,cv2.TM_CCOEFF_NORMED)
_, match, _, _ = cv2.minMaxLoc(res)
#cv2.imshow("pl",roi)
if 0.01<match<plth:
if pl_state==IDLE:
blinks.append(0)
interval = (time_counter - pl_prev)/1.017
interval_round = round(interval)
interval_corrected = interval_round + blinkcounter
blinkcounter = 0#reset blinkcounter
intervals.append(interval_corrected)
if len(intervals)==size:
offset_time = time_counter
#check interval
check = " " if abs(interval-interval_round)<0.2 else "*"
debug_txt = f"{interval}"+check
pl_state = SINGLE
pl_prev = time_counter
elif pl_state==SINGLE:
#double
if time_counter - pl_prev>0.3:
blinks[-1] = 1
debug_txt = debug_txt+"d"
pl_state = DOUBLE
elif pl_state==DOUBLE:
pass
if pl_state!=IDLE and time_counter - pl_prev>0.7:
pl_state = IDLE
print(debug_txt, len(blinks))
if pk_state==IDLE:
#poke eye
roi_x,roi_y,roi_w,roi_h = pkroi
roi = cv2.cvtColor(frame[roi_y:roi_y+roi_h,roi_x:roi_x+roi_w],cv2.COLOR_RGB2GRAY)
res = cv2.matchTemplate(roi,pkimg,cv2.TM_CCORR_NORMED)#CCORR might be better?
_, match, _, _ = cv2.minMaxLoc(res)
cv2.imshow("pk",roi)
cv2.waitKey(1)
if 0.4<match<pkth:
#print("poke blinked!")
blinkcounter += 1
pk_prev = time_counter
pk_state = SINGLE
if pk_state!=IDLE and time_counter - pk_prev>0.7:
pk_state = IDLE
cv2.destroyAllWindows()
print(intervals)
return (blinks, intervals, offset_time)
def recov(blinks:List[int],rawintervals:List[int])->Xorshift:
"""
Recover the xorshift from the type and interval of blinks.
@ -165,7 +260,7 @@ def recov(blinks:List[int],rawintervals:List[int])->Xorshift:
return result
def reidentifyByBlinks(rng:Xorshift, observed_blinks:List[int], npc = 0, search_max=10**6, search_min=0)->Xorshift:
"""reidentify Xorshift state by type of observed blinks.
"""reidentify Xorshift state by the type of observed blinks.
Args:
rng (Xorshift): identified rng
@ -223,13 +318,13 @@ def reidentifyByBlinks(rng:Xorshift, observed_blinks:List[int], npc = 0, search_
return None
def reidentifyByIntervals(rng:Xorshift, rawintervals:List[int], npc = 0, search_max=10**6, search_min=0)->Xorshift:
def reidentifyByIntervals(rng:Xorshift, rawintervals:List[int], npc = 0, th = 0, search_max=10**6, search_min=0)->Xorshift:
"""reidentify Xorshift state by intervals of observed blinks.
This method is faster than "reidentifyByBlinks" in most cases since it can be reidentified by less blinking.
Args:
rng (Xorshift): [description]
rawintervals (List[int]): list of intervals of blinks. 6 or more is recommended.
rawintervals (List[int]): list of intervals of blinks. 7 or more are recommended.
npc (int, optional): [description]. Defaults to 0.
search_max ([type], optional): [description]. Defaults to 10**6.
search_min (int, optional): [description]. Defaults to 0.
@ -248,9 +343,6 @@ def reidentifyByIntervals(rng:Xorshift, rawintervals:List[int], npc = 0, search_
blinkrands = [(i, int((r&0b1110)==0)) for i,r in list(enumerate(identify_rng.getNextRandSequence(search_max)))[d::1+npc]]
#prepare
expected_blinks_lst = []
expected_blinks = 0
lastblink_idx = -1
@ -280,15 +372,21 @@ def reidentifyByIntervals(rng:Xorshift, rawintervals:List[int], npc = 0, search_
#search
result = Xorshift(*rng.getState())
distlst = []
for idx, blinks in expected_blinks_lst:
if search_blinks==blinks and search_min <= idx:
print(f"found at advances:{idx}, d={d}")
#check by hamming distance
distance = bin(search_blinks^blinks).count("1")
distlst.append(distance)
isSame = distance<=th
if isSame and search_min <= idx:
print(f"found at advances:{idx}, d={d}, hamming={distance}")
result.getNextRandSequence(idx)
return result
c = Counter(distlst)
print(sorted(c.items()))
return None
def recovByMunchlax(rawintervals:List[float])->Xorshift:
"""Recover the xorshift from the interval of Munchlax blinks.
@ -299,8 +397,8 @@ def recovByMunchlax(rawintervals:List[float])->Xorshift:
Xorshift: [description]
"""
advances = len(rawintervals)
intervals = [interval+0.048 for interval in rawintervals]#観測結果のずれを補正
intervals = intervals[1:]#最初の観測結果はノイズなのでそれ以降を使う
intervals = [interval+0.048 for interval in rawintervals]#Corrects for delays in observation results
intervals = intervals[1:]#The first observation is noise, so we use the one after that.
states = calc.reverseStatesByMunchlax(intervals)
prng = Xorshift(*states)