- improved PiCameraPipeline (added names for procs, better thread mgmt)

- added VideoSource to piCameraPipeline



git-svn-id: http://moon:8086/svn/software/trunk/projects/opencv@330 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2016-10-22 07:50:06 +00:00
parent 7412e813bc
commit 4bf4c483a4
4 changed files with 108 additions and 81 deletions
+5 -48
View File
@@ -21,6 +21,7 @@ from picamera import PiCamera
from piCameraPipeline import PiCameraPipeline from piCameraPipeline import PiCameraPipeline
from piCameraPipeline.PiCameraPipeline import RgbProcess from piCameraPipeline.PiCameraPipeline import RgbProcess
from piCameraPipeline.PiCameraPipeline import RgbProcessorAdapter from piCameraPipeline.PiCameraPipeline import RgbProcessorAdapter
from piCameraPipeline.VideoSource import VideoSource
width = 320 width = 320
height = 240 height = 240
@@ -42,52 +43,9 @@ framerate = args["framerate"]
seconds = args["seconds"] seconds = args["seconds"]
with_ev3 = args["with_ev3"] with_ev3 = args["with_ev3"]
class VideoSource(RgbProcessorAdapter):
def __init__(self, fileName, resolution, framerate):
super(VideoSource, self).__init__(resolution)
self.fileName = fileName
self.resolution = resolution
self.framerate = framerate
self.thread = None
self.camera = None
self.cancel = False
if fileName == 'piCamera':
self.camera = PiCamera()
self.camera.resolution = (self.resolution[0], self.resolution[1])
self.camera.framerate = self.framerate
else:
self.needRgbConversion = False
self.thread = Thread(target=self.fileReadThread)
def fileReadThread(self):
pass
def start(self):
if self.thread is not None:
self.thread.start()
pass
else:
self.camera.start_recording(self, format="bgr")
def stop(self):
if self.thread is not None:
self.cancel = True
self.thread.join()
else:
self.camera.stop_recording()
def fileReadThread(self):
cap = cv2.VideoCapture(self.fileName)
while not self.cancel:
ret, frame = cap.read()
if ret:
self.write(frame)
time.sleep(1.0/self.framerate)
class MyRgbProcess(RgbProcess): class MyRgbProcess(RgbProcess):
def __init__(self, brick, resolution=(320, 240, 3), numEntries=2, next=None): def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None, brick=None):
super(MyRgbProcess, self).__init__(resolution, numEntries, next) super(MyRgbProcess, self).__init__(name, resolution, numEntries, next)
self.brick = brick self.brick = brick
def process(self): def process(self):
@@ -145,7 +103,7 @@ if with_ev3:
with ev3.EV3() as brick: with ev3.EV3() as brick:
videoSource = VideoSource(videoFile, (width,height,3), framerate) videoSource = VideoSource(videoFile, (width,height,3), framerate)
proc = MyRgbProcess(brick, (240, 320, 3), 4) proc = MyRgbProcess('MyRgbProcess', (240, 320, 3), 4, brick)
videoSource.processorAdd(proc) videoSource.processorAdd(proc)
videoSource.start() videoSource.start()
@@ -155,14 +113,13 @@ if with_ev3:
proc.stop() proc.stop()
else: else:
videoSource = VideoSource(videoFile, (width,height,3), framerate) videoSource = VideoSource(videoFile, (width,height,3), framerate)
proc = MyRgbProcess(None, (240, 320, 3), 4) proc = MyRgbProcess('MyRgbProcess', (240, 320, 3), 4)
videoSource.processorAdd(proc) videoSource.processorAdd(proc)
videoSource.start() videoSource.start()
print("[INFO] sampling THREADED frames from `" + videoFile + "` at " + str(framerate) + " frame/s") print("[INFO] sampling THREADED frames from `" + videoFile + "` at " + str(framerate) + " frame/s")
time.sleep(seconds) time.sleep(seconds)
videoSource.stop() videoSource.stop()
proc.stop()
# do a bit of cleanup # do a bit of cleanup
cv2.destroyAllWindows() cv2.destroyAllWindows()
+46 -27
View File
@@ -60,8 +60,9 @@ class Fifo(object):
return data return data
class RgbProcess(Fifo): class RgbProcess(Fifo):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None): def __init__(self, name='RgbProcess', resolution=(320, 240, 3), numEntries=2, next=None):
super(RgbProcess, self).__init__((numEntries, ) + resolution) super(RgbProcess, self).__init__((numEntries, ) + resolution)
self.name = name
self.next = next self.next = next
self.thread = Thread(target=self.run) self.thread = Thread(target=self.run)
self.cancel = False self.cancel = False
@@ -74,9 +75,10 @@ class RgbProcess(Fifo):
# called on first frame # called on first frame
def onFirstFrame(self): def onFirstFrame(self):
self.thread.start() self.start()
if self.next is not None:
self.next.onFirstFrame() def onLastFrame(self):
self.stop()
# may be overriden to process in caller context # may be overriden to process in caller context
def onData(self, data): def onData(self, data):
@@ -84,31 +86,46 @@ class RgbProcess(Fifo):
# thread main loop # thread main loop
def run(self): def run(self):
self.fps = FPS().start() self.started()
while not self.cancel: while not self.cancel:
self.process() self.process()
self.frames += 1 self.frames += 1
self.stopped()
def started(self):
print(self.name + ": started()")
self.fps = FPS().start()
if self.next is not None:
self.next.onFirstFrame()
def stopped(self):
self.fps.stop()
print(self.name + ": stopped()")
print(self.name + ": Processed " + str(self.frames) + " frames")
print(self.name + ": FPS = " + str(self.frames/self.fps.elapsed()))
# abstractmethod # abstractmethod
def process(self): def process(self):
pass pass
def start(self):
if not self.thread.is_alive():
self.thread.start()
# should be called to exit thread # should be called to exit thread
def stop(self): def stop(self):
self.fps.stop() if self.thread.is_alive():
print("Processed " + str(self.frames) + " frames") if self.next is not None:
print("FPS = " + str(self.frames/self.fps.elapsed())) self.next.stop()
self.cancel = True self.cancel = True
self.thread.join() self.thread.join()
if self.next is not None:
self.next.stop()
class RgbProcessorAdapter(object): class RgbProcessorAdapter(object):
def __init__(self, resolution=(320, 240, 3)): def __init__(self, resolution=(320, 240, 3)):
self.resolution = resolution self.resolution = resolution
self.frameSize = resolution[0]*resolution[1]*resolution[2] self.frameSize = resolution[0]*resolution[1]*resolution[2]
self.size = 0 self.size = 0
self.frames = 0
self.fps = None self.fps = None
self.processors = [] self.processors = []
self.needRgbConversion = True self.needRgbConversion = True
@@ -121,18 +138,15 @@ class RgbProcessorAdapter(object):
return True return True
def write(self, data): def write(self, data):
if data is None:
return
if self.size == 0: if self.size == 0:
for proc in self.processors: for proc in self.processors:
proc.onFirstFrame() proc.onFirstFrame()
self.fps = FPS().start() self.fps = FPS().start()
if data is None:
return
self.size += len(data)
self.frames += len(data)/self.frameSize
res = (self.resolution[0], self.resolution[1]) res = (self.resolution[0], self.resolution[1])
if self.needRgbConversion: if self.needRgbConversion:
@@ -140,6 +154,8 @@ class RgbProcessorAdapter(object):
else: else:
rgbData = data rgbData = data
self.size += rgbData.size
for proc in self.processors: for proc in self.processors:
proc.onData(rgbData) proc.onData(rgbData)
@@ -149,16 +165,19 @@ class RgbProcessorAdapter(object):
def flush(self): def flush(self):
if self.size > 0: if self.size > 0:
self.fps.stop() self.fps.stop()
print("Recorded " + str(self.frames) + " frames (" + str(self.size) + " bytes)") frames = self.size/self.frameSize
print("FPS = " + str(self.frames/self.fps.elapsed())) print("Recorded " + str(frames) + " frames (" + str(self.size) + " bytes)")
print("FPS = " + str(frames/self.fps.elapsed()))
for proc in self.processors:
proc.onLastFrame()
if ("__main__" == __name__): if ("__main__" == __name__):
import cv2 import cv2
# Unit test with to threaded processors # Unit test with to threaded processors
class MyRgbProcess1(RgbProcess): class MyRgbProcess1(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None): def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess1, self).__init__(resolution, numEntries, next) super(MyRgbProcess1, self).__init__(name, resolution, numEntries, next)
def process(self): def process(self):
data = self.read(1.0) data = self.read(1.0)
@@ -173,8 +192,8 @@ if ("__main__" == __name__):
self.next.write(cv2.cvtColor(gray_blurred,cv2.COLOR_GRAY2BGR)) self.next.write(cv2.cvtColor(gray_blurred,cv2.COLOR_GRAY2BGR))
class MyRgbProcess2(RgbProcess): class MyRgbProcess2(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None): def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess2, self).__init__(resolution, numEntries, next) super(MyRgbProcess2, self).__init__(name, resolution, numEntries, next)
def process(self): def process(self):
data = self.read(1.0) data = self.read(1.0)
@@ -191,8 +210,8 @@ if ("__main__" == __name__):
camera.resolution = (320, 240) camera.resolution = (320, 240)
camera.framerate = 60 camera.framerate = 60
frameDim = (camera.resolution[0], camera.resolution[1], 3) frameDim = (camera.resolution[0], camera.resolution[1], 3)
myProcessor2 = MyRgbProcess2((240, 320, 3), 4) myProcessor2 = MyRgbProcess2('Process 2', (240, 320, 3), 4)
myProcessor1 = MyRgbProcess1((240, 320, 3), 4, myProcessor2) myProcessor1 = MyRgbProcess1('Process 1', (240, 320, 3), 4, myProcessor2)
myRgbProcessorAdapter = RgbProcessorAdapter(frameDim) myRgbProcessorAdapter = RgbProcessorAdapter(frameDim)
myRgbProcessorAdapter.processorAdd(myProcessor1) myRgbProcessorAdapter.processorAdd(myProcessor1)
camera.start_recording(myRgbProcessorAdapter, format="bgr") camera.start_recording(myRgbProcessorAdapter, format="bgr")
+51
View File
@@ -0,0 +1,51 @@
import time
import cv2
from threading import Thread
from picamera import PiCamera
from piCameraPipeline.PiCameraPipeline import RgbProcessorAdapter
class VideoSource(RgbProcessorAdapter):
def __init__(self, fileName, resolution, framerate):
super(VideoSource, self).__init__(resolution)
self.fileName = fileName
self.resolution = resolution
self.framerate = framerate
self.thread = None
self.camera = None
self.cancel = False
if fileName == 'piCamera':
self.camera = PiCamera()
self.camera.resolution = (self.resolution[0], self.resolution[1])
self.camera.framerate = self.framerate
else:
self.needRgbConversion = False
self.thread = Thread(target=self.fileReadThread)
def fileReadThread(self):
pass
def start(self):
if self.thread is not None:
if not self.thread.is_alive():
self.thread.start()
else:
self.camera.start_recording(self, format="bgr")
def stop(self):
if self.thread is not None:
if self.thread.is_alive():
self.cancel = True
self.thread.join()
else:
self.camera.stop_recording()
def fileReadThread(self):
cap = cv2.VideoCapture(self.fileName)
while not self.cancel:
ret, frame = cap.read()
if ret:
self.write(frame)
else:
break
time.sleep(1.0/self.framerate)
self.flush()
+6 -6
View File
@@ -10,8 +10,8 @@ if ("__main__" == __name__):
# Unit test with to threaded processors # Unit test with to threaded processors
class MyRgbProcess1(RgbProcess): class MyRgbProcess1(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None): def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess1, self).__init__(resolution, numEntries, next) super(MyRgbProcess1, self).__init__(name, resolution, numEntries, next)
def process(self): def process(self):
data = self.read(1.0) data = self.read(1.0)
@@ -26,8 +26,8 @@ if ("__main__" == __name__):
self.next.write(cv2.cvtColor(gray_blurred,cv2.COLOR_GRAY2BGR)) self.next.write(cv2.cvtColor(gray_blurred,cv2.COLOR_GRAY2BGR))
class MyRgbProcess2(RgbProcess): class MyRgbProcess2(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None): def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess2, self).__init__(resolution, numEntries, next) super(MyRgbProcess2, self).__init__(name, resolution, numEntries, next)
def process(self): def process(self):
data = self.read(1.0) data = self.read(1.0)
@@ -44,8 +44,8 @@ if ("__main__" == __name__):
camera.resolution = (320, 240) camera.resolution = (320, 240)
camera.framerate = 60 camera.framerate = 60
frameDim = (camera.resolution[0], camera.resolution[1], 3) frameDim = (camera.resolution[0], camera.resolution[1], 3)
myProcessor2 = MyRgbProcess2((240, 320, 3), 4) myProcessor2 = MyRgbProcess2('Process 2', (240, 320, 3), 4)
myProcessor1 = MyRgbProcess1((240, 320, 3), 4, myProcessor2) myProcessor1 = MyRgbProcess1('Process 1', (240, 320, 3), 4, myProcessor2)
myRgbProcessorAdapter = RgbProcessorAdapter(frameDim) myRgbProcessorAdapter = RgbProcessorAdapter(frameDim)
myRgbProcessorAdapter.processorAdd(myProcessor1) myRgbProcessorAdapter.processorAdd(myProcessor1)
camera.start_recording(myRgbProcessorAdapter, format="bgr") camera.start_recording(myRgbProcessorAdapter, format="bgr")