Skip to content

Commit

Permalink
create classes to ease code readability
Browse files Browse the repository at this point in the history
  • Loading branch information
piif committed Mar 29, 2016
1 parent fdc992b commit d1a3a30
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 92 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
152 changes: 152 additions & 0 deletions Gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from numpy import array, int16
import cv2

class Line:
x0 = 0
y0 = 0
x1 = 0
y1 = 0
name = "??"
background = None

maxLen = 0
segments = []
bgPixels = None

# abstraction of a line into an image, where movement
# have to be detected
def __init__(self, _name, _coords):
self.name = _name
(self.x0, self.y0, self.x1, self.y1) = tuple(_coords)
self.compute()


def setBackground(self, frame):
self.background = frame


def setStart(self, x, y):
(self.x0, self.y0) = (x, y)
self.compute()


def setEnd(self, x, y):
(self.x1, self.y1) = (x, y)
self.compute()


def compute(self):
self.maxLen = max ( abs(self.x0 - self.x1), abs(self.y0 - self.y1) )
# let to be computed when asked for
bgPixels = None


def computeBgPixels(self):
self.bgPixels = [ array(self.background[y][x], dtype=int16) \
for x, y in self.getPixels() ]


def __len__(self):
return self.maxLen


def redraw(self, image, color):
cv2.line(image, (self.x0, self.y0), (self.x1, self.y1), color, 2)
for (s0, s1) in self.segments:
cv2.line(image, s0, s1, (255, 255, 255), 2)

def getPixels(self, nbIteration = -1):
if (nbIteration == -1):
nbIteration = self.maxLen
if nbIteration == 0:
raise StopIteration()

dx = (self.x1 - self.x0)
dy = (self.y1 - self.y0)
for t in range(0, nbIteration):
x = dx * t / nbIteration + self.x0
y = dy * t / nbIteration + self.y0
yield (x, y)


# compute intersection between current frame and background, along pixel list
def intersect(self, frame, colorThreshold):
start = None
end = None
self.segments = []
if self.bgPixels is None:
self.computeBgPixels()
for i, (x, y) in enumerate(self.getPixels()):
fg = frame[y][x]
delta = max(abs(self.bgPixels[i] - array(fg, dtype=int16)))
#print x, "x", y, " : ", fg, "/", self.bgPixels[i], "->", delta
if delta > colorThreshold:
if start is None:
start = (x, y)
else:
end = (x, y)
elif start is not None:
self.segments.append( (start, (x, y)) )
start = None

# close last segment if any
if start is not None:
self.segments.append((start, (self.x1, self.y1)))
return self.segments


def __str__(self):
return "%s line @ (%d,%d)->(%d,%d) -> maxLen %d" % (
self.name, self.x0, self.y0, self.x1, self.y1, self.maxLen)


class CountingGate:
# abstraction of 2 lines on which detected movements
# are counted

# red and green line objects
green = None
red = None
# number of iterations to do in longest line
width = 0

def __init__(self, _green, _red):
self.green = Line("green", _green)
self.red = Line("red", _red)
width = max(len(self.red), len(self.green))


def setRed(self, _red):
self.red = -red
width = max(len(self.red), len(self.green))


def setGreen(self, _green):
self.green = _green
width = max(len(self.red), len(self.green))


def setBackground(self, frame):
self.green.setBackground(frame)
self.red.setBackground(frame)

def intersect(self, frame, colorThreshold):
self.green.intersect(frame, colorThreshold)
self.red.intersect(frame, colorThreshold)

# bounding box of gate
def bbox(self, margin = 0):
if red is None or green is None:
return None
x0 = min(self.red.x0, self.red.x1, self.green.x0, self.green.x1)
x1 = max(self.red.x0, self.red.x1, self.green.x0, self.green.x1)
y0 = min(self.red.y0, self.red.y1, self.green.y0, self.green.y1)
y1 = max(self.red.y0, self.red.y1, self.green.y0, self.green.y1)
return ((x0 - margin, y0 - margin), (x1 + margin, y1 + margin))


def redraw(self, image):
if self.green is not None:
self.green.redraw(image, (0, 255, 0))
if self.red is not None:
self.red.redraw(image, (0, 0, 255))
115 changes: 23 additions & 92 deletions lineFilter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
TODO
- revoir init de green et red si pas en argument
- dégager les 200 pemière frames de 14_3, ou trouver comment skip des frames sans y passer du temps
python lineFilter.py -i samples/raw/WP_20160319_004.mp4
python lineFilter.py -i samples/ldn1_14_3.avi --green 80 540 680 545 --red 80 500 680 500 -s 200

#TODO
#- deqgager les 200 premiere frames de 14_3, ou trouver comment skip des frames sans y passer du temps
#python lineFilter.py -i samples/raw/WP_20160319_005.stab.avi --green 330 109) 361 472 --red 489 112 498 468
#python lineFilter.py -i samples/ldn1_14_3.avi --green 80 540 680 545 --red 80 500 680 500 -s 200

"""
- let user draw lines in video window :
Expand All @@ -28,6 +26,8 @@
"""

from Gate import CountingGate, Line

# EXAMPLE :
# lineFilter.py -i samples/ldn1_14_3.avi --green 80 540 680 540 --red 80 500 680 500

Expand All @@ -38,10 +38,10 @@

parser = argparse.ArgumentParser()
parser.add_argument('--red', nargs = 4, type = int,
dest = 'redLine', default = (0, 0, 0, 0),
dest = 'redLine', default = [ 0, 0, 0, 0 ],
help = "(x,y)->(x,y) for red line")
parser.add_argument('--green', nargs = 4, type = int,
dest = 'greenLine', default = (0, 0, 0, 0),
dest = 'greenLine', default = [ 0, 0, 0, 0 ],
help = "(x,y)->(x,y) for green line")
parser.add_argument('-i', '--input', dest = 'inputFile',
default = 0,
Expand All @@ -52,6 +52,8 @@

args = parser.parse_args()

gate = CountingGate(args.greenLine, args.redLine)

# max len of buffer # TODO : add argument
bufferMax = 25

Expand All @@ -66,12 +68,7 @@

def redraw():
frame = buffer[bufferPos].copy()
cv2.line(frame, tuple(greenLine[0:2]), tuple(greenLine[2:4]), (0, 255, 0), 2)
cv2.line(frame, tuple(redLine[0:2]), tuple(redLine[2:4]), (0, 0, 255), 2)
for (s0, s1) in greenSegments:
cv2.line(frame, s0, s1, (255, 255, 255), 2)
for (s0, s1) in redSegments:
cv2.line(frame, s0, s1, (255, 255, 255), 2)
gate.redraw(frame)

cv2.imshow("video", frame)

Expand All @@ -83,49 +80,9 @@ def redraw():
exit(1)
buffer = [ frame ]
bufferPos = 0
bg = frame.copy()

# prepare red and green pixels
def prepareLine(bg, x0, y0, x1, y1):
result = []
# if x delta > y delta, enumerate delta x pixels else y ones
pix=lambda x,y : {
'x': x, 'y': y, 'bg': numpy.array(bg[y][x], dtype=numpy.int16)
}
if x0 == x1:
if y0 == y1:
return None
for y in range(y0 , y1):
result.append(pix(x0, y))
elif y0 == y1:
for x in range(x0, x1):
result.append(pix(x, y0))
elif abs(x1 - x0) > abs(y1 - y0):
a = float(y1 - y0) / float(x1 - x0)
b = y0 - a * x0
#print "line y = ", a, "x +", b, " for x in", x0, "..", x1
for x in range(x0, x1):
y = int(a * x + b)
result.append(pix(x, y))
else:
a = float(x1 - x0) / float(y1 - y0)
b = x0 - a * y0
#print "line x = ", a, "y +", b, " for y in", y0, "..", y1
for y in range(y0 , y1):
x = int(a * y + b)
result.append(pix(x, y))

print "prepareLine ->", result[0:3]
return result
bg = frame #.copy()


greenLine = args.greenLine
greenPixels = prepareLine(bg, *greenLine)
greenSegments = []

redLine = args.redLine
redPixels = prepareLine(bg, *redLine)
redSegments = []
gate.setBackground(bg)

redraw()

Expand All @@ -142,31 +99,29 @@ def prepareLine(bg, x0, y0, x1, y1):
# handle mouse to redraw red and green lines
drawing = None
def mouseHandler(event, x, y, flags, param):
global drawing, greenLine, greenPixels, redLine, redPixels
global drawing, gate

if event == cv2.EVENT_MBUTTONUP:
intersectPix(x, y)
elif event == cv2.EVENT_LBUTTONDOWN:
greenLine[0:2] = (x, y)
gate.green.setStart(x, y)
drawing = 'g'
elif event == cv2.EVENT_LBUTTONUP:
greenLine[2:4] = (x, y)
greenPixels = prepareLine(bg, *greenLine)
gate.green.setEnd(x, y)
drawing = None
print "Green line @ (%d,%d)->(%d,%d)" % tuple(greenLine)
print gate.green
elif event == cv2.EVENT_RBUTTONDOWN:
redLine[0:2] = (x, y)
gate.red.setStart(x, y)
drawing = 'r'
elif event == cv2.EVENT_RBUTTONUP:
redLine[2:4] = (x, y)
redPixels = prepareLine(bg, *redLine)
gate.red.setEnd(x, y)
drawing = None
print "Red line @ (%d,%d)->(%d,%d)" % tuple(redLine)
print gate.red
elif event == cv2.EVENT_MOUSEMOVE and drawing is not None:
if drawing == 'g':
greenLine[2:4] = (x, y)
gate.green.setEnd(x, y)
else:
redLine[2:4] = (x, y)
gate.red.setEnd(x, y)
else:
return
redraw()
Expand All @@ -177,29 +132,6 @@ def intersectPix(x, y):
- numpy.array(frame[y][x], dtype=numpy.int16)))
print x, "x", y, ":", delta

# compute intersection current frame and background, along pixel list
def intersect(pixels, frame):
start = None
end = None
result = []
for p in pixels:
fg = frame[p['y']][p['x']]
delta = max(abs(p['bg'] - numpy.array(fg, dtype=numpy.int16)))
#print p['x'], "x", p['y'], " : ", fg, "/", p['bg'], "->", delta
if delta > colorThreshold:
if start is None:
start = (p['x'],p['y'])
else:
end = (p['x'],p['y'])
elif start is not None:
result.append((start, (p['x'],p['y'])))
start = None

# close last segment if any
if start is not None:
result.append((start, (pixels[-1]['x'],pixels[-1]['y'])))
return result


def showInfo():
print "Frame number", frameNumber
Expand Down Expand Up @@ -255,8 +187,7 @@ def showInfo():
a creuser sur des exemples ...
"""

greenSegments = intersect(greenPixels, buffer[bufferPos])
redSegments = intersect(redPixels, buffer[bufferPos])
gate.intersect(buffer[bufferPos], colorThreshold)

# Display the resulting frame
redraw()
Expand Down

0 comments on commit d1a3a30

Please sign in to comment.