- 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.PiCameraPipeline import RgbProcess
from piCameraPipeline.PiCameraPipeline import RgbProcessorAdapter
from piCameraPipeline.VideoSource import VideoSource
width = 320
height = 240
@@ -42,52 +43,9 @@ framerate = args["framerate"]
seconds = args["seconds"]
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):
def __init__(self, brick, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess, self).__init__(resolution, numEntries, next)
def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None, brick=None):
super(MyRgbProcess, self).__init__(name, resolution, numEntries, next)
self.brick = brick
def process(self):
@@ -145,7 +103,7 @@ if with_ev3:
with ev3.EV3() as brick:
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.start()
@@ -155,14 +113,13 @@ if with_ev3:
proc.stop()
else:
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.start()
print("[INFO] sampling THREADED frames from `" + videoFile + "` at " + str(framerate) + " frame/s")
time.sleep(seconds)
videoSource.stop()
proc.stop()
# do a bit of cleanup
cv2.destroyAllWindows()
+46 -27
View File
@@ -60,8 +60,9 @@ class Fifo(object):
return data
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)
self.name = name
self.next = next
self.thread = Thread(target=self.run)
self.cancel = False
@@ -74,9 +75,10 @@ class RgbProcess(Fifo):
# called on first frame
def onFirstFrame(self):
self.thread.start()
if self.next is not None:
self.next.onFirstFrame()
self.start()
def onLastFrame(self):
self.stop()
# may be overriden to process in caller context
def onData(self, data):
@@ -84,31 +86,46 @@ class RgbProcess(Fifo):
# thread main loop
def run(self):
self.fps = FPS().start()
self.started()
while not self.cancel:
self.process()
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
def process(self):
pass
def start(self):
if not self.thread.is_alive():
self.thread.start()
# should be called to exit thread
def stop(self):
self.fps.stop()
print("Processed " + str(self.frames) + " frames")
print("FPS = " + str(self.frames/self.fps.elapsed()))
self.cancel = True
self.thread.join()
if self.next is not None:
self.next.stop()
if self.thread.is_alive():
if self.next is not None:
self.next.stop()
self.cancel = True
self.thread.join()
class RgbProcessorAdapter(object):
def __init__(self, resolution=(320, 240, 3)):
self.resolution = resolution
self.frameSize = resolution[0]*resolution[1]*resolution[2]
self.size = 0
self.frames = 0
self.fps = None
self.processors = []
self.needRgbConversion = True
@@ -121,17 +138,14 @@ class RgbProcessorAdapter(object):
return True
def write(self, data):
if data is None:
return
if self.size == 0:
for proc in self.processors:
proc.onFirstFrame()
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])
@@ -140,6 +154,8 @@ class RgbProcessorAdapter(object):
else:
rgbData = data
self.size += rgbData.size
for proc in self.processors:
proc.onData(rgbData)
@@ -149,16 +165,19 @@ class RgbProcessorAdapter(object):
def flush(self):
if self.size > 0:
self.fps.stop()
print("Recorded " + str(self.frames) + " frames (" + str(self.size) + " bytes)")
print("FPS = " + str(self.frames/self.fps.elapsed()))
frames = self.size/self.frameSize
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__):
import cv2
# Unit test with to threaded processors
class MyRgbProcess1(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess1, self).__init__(resolution, numEntries, next)
def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess1, self).__init__(name, resolution, numEntries, next)
def process(self):
data = self.read(1.0)
@@ -173,8 +192,8 @@ if ("__main__" == __name__):
self.next.write(cv2.cvtColor(gray_blurred,cv2.COLOR_GRAY2BGR))
class MyRgbProcess2(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess2, self).__init__(resolution, numEntries, next)
def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess2, self).__init__(name, resolution, numEntries, next)
def process(self):
data = self.read(1.0)
@@ -191,8 +210,8 @@ if ("__main__" == __name__):
camera.resolution = (320, 240)
camera.framerate = 60
frameDim = (camera.resolution[0], camera.resolution[1], 3)
myProcessor2 = MyRgbProcess2((240, 320, 3), 4)
myProcessor1 = MyRgbProcess1((240, 320, 3), 4, myProcessor2)
myProcessor2 = MyRgbProcess2('Process 2', (240, 320, 3), 4)
myProcessor1 = MyRgbProcess1('Process 1', (240, 320, 3), 4, myProcessor2)
myRgbProcessorAdapter = RgbProcessorAdapter(frameDim)
myRgbProcessorAdapter.processorAdd(myProcessor1)
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
class MyRgbProcess1(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess1, self).__init__(resolution, numEntries, next)
def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess1, self).__init__(name, resolution, numEntries, next)
def process(self):
data = self.read(1.0)
@@ -26,8 +26,8 @@ if ("__main__" == __name__):
self.next.write(cv2.cvtColor(gray_blurred,cv2.COLOR_GRAY2BGR))
class MyRgbProcess2(RgbProcess):
def __init__(self, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess2, self).__init__(resolution, numEntries, next)
def __init__(self, name, resolution=(320, 240, 3), numEntries=2, next=None):
super(MyRgbProcess2, self).__init__(name, resolution, numEntries, next)
def process(self):
data = self.read(1.0)
@@ -44,8 +44,8 @@ if ("__main__" == __name__):
camera.resolution = (320, 240)
camera.framerate = 60
frameDim = (camera.resolution[0], camera.resolution[1], 3)
myProcessor2 = MyRgbProcess2((240, 320, 3), 4)
myProcessor1 = MyRgbProcess1((240, 320, 3), 4, myProcessor2)
myProcessor2 = MyRgbProcess2('Process 2', (240, 320, 3), 4)
myProcessor1 = MyRgbProcess1('Process 1', (240, 320, 3), 4, myProcessor2)
myRgbProcessorAdapter = RgbProcessorAdapter(frameDim)
myRgbProcessorAdapter.processorAdd(myProcessor1)
camera.start_recording(myRgbProcessorAdapter, format="bgr")