-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdetector_camshift.py
147 lines (127 loc) · 4.68 KB
/
detector_camshift.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import cv, cv2
import numpy as np
from hand_pos import Outline, HandPos
import rectangle
from bench import benchmark
import logging
class DetectorCamshift:
"""
Use camshift to track a hand in an image.
This detector requires a region of interest from the image
(the hand) to create a histogram.
One way of doing this automatically is to use
a HAAR detector for bootstrap.
"""
def __init__(self, config, img, roi):
self.config = config
# Output shape
self.output_shape = Outline.RECT
# If the output shall be rectangle,
# adjust the position a little bit.
self.rect_offset = (0,-40)
# Remember area in image with highest skin probabiltiy
self.max_foreground_prob = 0
# Create histogram from roi
self.set_track_window(roi)
# Run detection for inital back projection
self.detect(img, None)
def set_track_window(self, roi):
# Calculate initial track window
x0, y0, x1, y1 = roi
width = x1 - x0
height = y1 - y0
if width > 0 and height > 0:
#self.track_window = roi
# Store region of interest for later use
self.roi = roi
# Track only the bottom half of the roi.
# This empirically yields better results
#self.track_window = (x0 + int(height/2), y0 + int(width/4), height, width - int(width/4))
self.track_window = (x0, y0, width, height)
def preprocess(self, img):
"""
The preprocessing step prepares the image to improve detection probability.
"""
self.hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
def set_mask(self, hsv):
# Use default values...
self.mask = cv2.inRange(hsv, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
# ...or our calculated values
LOWER = np.array([self.config["min_hue"],
self.config["min_saturation"],
self.config["min_darkness"]],
np.uint8)
UPPER = np.array([self.config["max_hue"],
self.config["max_saturation"],
self.config["max_darkness"]],
np.uint8)
#self.mask = cv2.inRange(hsv, LOWER, UPPER)
#@benchmark
def detect(self, img, face_pos):
"""
Track blobs with camshift
Returns a needle hypothesis and the confidence that it is correct.
"""
self.preprocess(img)
x0, y0, x1, y1 = self.roi
self.set_mask(self.hsv)
# Extract region of interest from preprocessed image
hsv_roi = self.hsv[y0:y1, x0:x1]
mask_roi = self.mask[y0:y1, x0:x1]
# Adjust histogram
hist = cv2.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] )
cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX);
self.hist = hist.reshape(-1)
prob = cv2.calcBackProject([self.hsv], [0], self.hist, [0, 180], 1)
prob &= self.mask
term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
try:
track_box, track_window = cv2.CamShift(prob, self.track_window, term_crit)
self.set_track_window(track_window)
self.get_confidence(prob, track_window)
prob = 1
# Select outline (rectangle or ellipse)
if self.output_shape == Outline.RECT:
# Camshift normally outputs an ellipse, but if the output shall be a
# rectangle, we can create one by creating a rectangle arround the ellipse
# and tweaking the result.
# Although the track window would have a rectangle shape,
# we get much better results with the above strategy.
position = rectangle.get_bounding_rect(track_box)
position = rectangle.offset(position, self.rect_offset)
return HandPos(pos=position, prob=prob, outline=Outline.RECT)
else:
return HandPos(pos=track_box, prob=prob, outline=Outline.ELLIPSE)
except Exception, e:
print e
return HandPos()
def get_confidence(self, prob, track_window):
# Calculate average skin probability for background
self.background_prob = np.average(prob)
# Calculate average skin probability for selected foreground
x1, y1, w,h = track_window
x2 = x1 + w
y2 = y1 + h
p = prob[y1:y2,x1:x2]
foreground_prob = np.average(p)
if foreground_prob > self.max_foreground_prob:
self.max_foreground_prob = foreground_prob
# Debug
#i = prob
#cv2.rectangle(i, (x1, y1), (x2, y2), (255,255,255), 5)
#cv2.imshow("Prob", i)
#conf = foreground_prob - background_prob
conf = foreground_prob / self.max_foreground_prob
logging.debug("Camshift: Confidence %s", conf)
return conf
def train(self, img):
"""
Train the detector with a special test image. This improves the following
detection results.
"""
pass
def set_config(config):
"""
Load new settings at runtime
"""
self.config = config