"""
:filename: VideoWriterPlugin.py
:author: roar@tordivel.no
:requirements: Scorpion 9.3.0.515 or higher
Scorpion GUI plugin for creating video from single images
::
1.0.0.2, 11nov2015, RL: modified for autodoc
1.0.0.1, 07jun2012, roar@tordivel.no:
created
"""
__version__ = '1.0.0.2'
import os
import datetime
import cv
import arrToNumpy
from Scorpion import RegisterCallback,GetCameraImages,GetImageMatr,PluginChanged,GetStringValue,GetBoolValue,GetControlByHandle,SelectDirectory,SelectTagname
#-----------------------------------------------------------------------------
# VideoWriterPlugin implementation
#-----------------------------------------------------------------------------
[docs]class VideoWriterPlugin(object):
"""
Scorpion GUI plugin for creating video from single images
"""
def __init__(self,cntr,name):
self.iname=cntr.iname #full path name of control
self.name=name #this plugins name
self.loading=True #flag to disable control change event while loading
self.writer=None #the videowriter object
self.filename='' #current filename
self.framecnt=0 #number of frames in current video
cntr.deleteControls() #delete previous added controls if any
HOFFS = 80 #horizontal position of 2'nd controls
VOFFS = 22 #vertical spacing
y = VOFFS
self.gbSetup=cntr.addControl('GroupBox',0,0)
self.gbSetup.align=5
self.gbSetup.caption='Video generation'
self.lblSource=self.gbSetup.addControl('Label',8,y)
self.lblSource.caption='Source'
self.cbSource=self.gbSetup.addControl('ComboBox',HOFFS,self.lblSource.top-2)
self.cbSource.style=2
self.cbSource.onClick=self.controlChanged
self.cbActive=self.gbSetup.addControl('CheckBox',self.cbSource.right+8,self.lblSource.top)
self.cbActive.caption='Active'
self.cbActive.onClick=self.controlChanged
y+=VOFFS
self.lblFormat=self.gbSetup.addControl('Label',8,y)
self.lblFormat.caption='Video codec'
self.cbFormat=self.gbSetup.addControl('ComboBox',HOFFS,self.lblFormat.top-2)
self.cbFormat.style=2
#self.cbFormat.items=('Uncompressed','RGB(A)','I420','IYUV','MPEG-1','MPEG-4.2','MPEG-4.3','MPEG-4','H263','H263I','FLV1') #we don't support all
self.cbFormat.items=('Uncompressed','RGB(A)','I420','IYUV') #most common avi formats
self.cbFormat.itemIndex=2 #most compressing format
self.cbFormat.onClick=self.controlChanged
self.lblFps=self.gbSetup.addControl('Label',self.cbFormat.right+8,self.lblFormat.top)
self.lblFps.caption='Playback framerate [fps]'
self.eFps=self.gbSetup.addControl('Edit',self.lblFps.right+8,self.lblFps.top-2)
self.eFps.width=self.eFps.height+4
self.eFps.text='5'
self.eFps.onChange=self.controlChanged
y+=VOFFS
self.lblFolder=self.gbSetup.addControl('Label',8,y)
self.lblFolder.caption='Folder'
self.eFolder=self.gbSetup.addControl('Edit',HOFFS,self.lblFolder.top-2)
self.eFolder.right=self.eFps.left
self.eFolder.text='Images'
self.eFolder.onChange=self.controlChanged
self.bFolder=self.gbSetup.addControl('Button',self.eFps.right-self.eFps.height,self.eFolder.top)
self.bFolder.width=self.eFps.height
self.bFolder.height=self.eFps.height
self.bFolder.caption='...'
self.bFolder.onClick=self.bFolderClick
y+=VOFFS
self.lblGuard=self.gbSetup.addControl('Label',8,y)
self.lblGuard.caption='Guard'
self.eGuard=self.gbSetup.addControl('Edit',HOFFS,self.lblGuard.top-2)
self.eGuard.right=self.eFps.left
self.eGuard.text=''
self.eGuard.onChange=self.controlChanged
self.bGuard=self.gbSetup.addControl('Button',self.eFps.right-self.eFps.height,self.eGuard.top)
self.bGuard.width=self.eFps.height
self.bGuard.height=self.eFps.height
self.bGuard.caption='...'
self.bGuard.onClick=self.bGuardClick
y+=VOFFS
self.pState=self.gbSetup.addControl('Panel',8,y+2)
self.pState.width=10
self.pState.height=10
self.pState.bevelInner=0
self.pState.bevelOuter=1
self.pState.caption=''
self.pState.color='white'
self.lblFrameCnt=self.gbSetup.addControl('Label',self.pState.right+8,y)
self.lblFrameCnt.caption='-'
self.lblFilename=self.gbSetup.addControl('Label',HOFFS,y)
self.lblFilename.caption=''
self.updateSourceCombo()
self.loading=False
RegisterCallback('Actions.BeforeStart',self.actionsBeforeStart)
RegisterCallback('Actions.AfterStop',self.actionsAfterStop)
RegisterCallback('Actions.AfterGrab',self.actionsAfterGrab)
RegisterCallback('System.AccessControlChanged',self.systemAccessControlChanged)
[docs] def updateSourceCombo(self):
'''
populete list of images in combobox
'''
names=[]
imgs=GetCameraImages()
idx=self.cbSource.itemIndex #selected
if imgs.count>0:
for i in range(imgs.count):
names.append(imgs.get(i).name)
self.cbSource.items=tuple(names)
self.cbSource.itemIndex=max(0,min(idx,len(names)))
[docs] def getConfig(self):
'''
returns plugin configuration as string
'''
from SPB import CreateSpb
spb=CreateSpb()
#create a spb instance, populate with the plugin configuration
#and return the xml string
spb.setInt('version',1)
spb.setInt('source',self.cbSource.itemIndex)
spb.setBool('active',self.cbActive.checked)
spb.setInt('format',self.cbFormat.itemIndex)
spb.setFloat('fps',float(self.eFps.text))
spb.setText('folder',self.eFolder.text)
spb.setText('guard',self.eGuard.text)
return spb.xml
[docs] def setConfig(self,value):
'''
set plugin configuration from the string 'value'
'''
self.loading=True
from SPB import CreateSpb
spb=CreateSpb(value)
#extract plugin configuration from the spb object
if spb.getInt('version')==1:
self.cbSource.itemIndex=spb.getInt('source')
self.cbActive.checked=spb.getBool('active')
self.cbFormat.itemIndex=spb.getInt('format')
self.eFps.text=str(spb.getFloat('fps'))
self.eFolder.text=spb.getText('folder')
self.eGuard.text=spb.getText('guard')
self.loading=False
[docs] def bFolderClick(self,sender,args):
'''
show folder selection dialog
'''
folder=os.path.join(GetStringValue('System.Profile'),self.eFolder.text)
ok,folder=SelectDirectory(folder)
if ok:self.eFolder.text=os.path.relpath(folder,GetStringValue('System.Profile'))
[docs] def bGuardClick(self,sender,args):
'''
select guard tagname
'''
guard=SelectTagname(self.eGuard.text)
if guard<>'':self.eGuard.text=guard
[docs] def controlChanged(self,sender,args):
'''
notify configuration changed
'''
if not self.loading:
PluginChanged(self)
[docs] def enableControls(self):
'''
enable controls due to operation state
'''
running=GetBoolValue('System.Running')
service=GetBoolValue('System.Service') or GetBoolValue('System.Settings')
self.cbSource.enabled=service and not running
self.cbActive.enabled=not running
self.cbFormat.enabled=service and not running
self.eFps.enabled=service and not running
self.eFolder.enabled=not running
self.bFolder.enabled=not running
self.eGuard.enabled=service and not running
self.bGuard.enabled=service and not running
[docs] def systemAccessControlChanged(self,settings,service):
'''
update rights
'''
self.enableControls()
[docs] def actionsBeforeStart(self):
'''
start of video
'''
self.gbSetup.enabled=False #enables controls
self.framecnt=0
self.lblFrameCnt.caption='-'
self.enableControls()
[docs] def actionsAfterStop(self):
'''
end of video
'''
self.writer=None #closes video and deletes writer
self.gbSetup.enabled=True #enables controls
self.pState.color='white' #stopped
self.enableControls()
[docs] def actionsAfterGrab(self):
'''
add image to video
'''
def array2cv(a):
dtype2depth = {
'uint8': cv.IPL_DEPTH_8U,
'int8': cv.IPL_DEPTH_8S,
'uint16': cv.IPL_DEPTH_16U,
'int16': cv.IPL_DEPTH_16S,
'int32': cv.IPL_DEPTH_32S,
'float32': cv.IPL_DEPTH_32F,
'float64': cv.IPL_DEPTH_64F,
}
try:
nChannels = a.shape[2]
except:
nChannels = 1
cv_im = cv.CreateImageHeader((a.shape[1],a.shape[0]),dtype2depth[str(a.dtype)],nChannels)
cv.SetData(cv_im, a.tostring(),a.dtype.itemsize*nChannels*a.shape[1])
return cv_im
if self.cbActive.checked and GetBoolValue('System.Running') and not GetBoolValue('System.CameraSimulation'):
if (self.eGuard.text=='') or GetBoolValue(self.eGuard.text):
imgname=GetCameraImages().get(self.cbSource.itemIndex).name
src=GetImageMatr(imgname)
if self.writer==None:
try:
height,width=src.dim()
if self.cbFormat.itemIndex==0: fcc=0 #Uncompressed
elif self.cbFormat.itemIndex==1: fcc=cv.CV_FOURCC('D','I','B',' ') #RGB(A)
elif self.cbFormat.itemIndex==2: fcc=cv.CV_FOURCC('I','4','2','0') #I420
elif self.cbFormat.itemIndex==3: fcc=cv.CV_FOURCC('I','Y','U','V') #IYUV
elif self.cbFormat.itemIndex==4: fcc=cv.CV_FOURCC('P','I','M','1') #MPEG1
elif self.cbFormat.itemIndex==5: fcc=cv.CV_FOURCC('M','P','4','2') #MPEG-4.2
elif self.cbFormat.itemIndex==6: fcc=cv.CV_FOURCC('D','I','V','3') #MPEG-4.3
elif self.cbFormat.itemIndex==7: fcc=cv.CV_FOURCC('D','I','V','X') #MPEG-4
elif self.cbFormat.itemIndex==8: fcc=cv.CV_FOURCC('U','2','6','3') #H263
elif self.cbFormat.itemIndex==9: fcc=cv.CV_FOURCC('I','2','6','3') #H263I
elif self.cbFormat.itemIndex==10:fcc=cv.CV_FOURCC('F','L','V','1') #FLV1
else: fcc=-1 #select dialog
folder=os.path.join(GetStringValue('System.Profile'),self.eFolder.text)
fname='%s_%s.avi'%(imgname,datetime.datetime.now().strftime('%Y%m%d_%H%M%S'))
self.filename=os.path.join(folder,fname)
if not os.path.exists(folder): os.mkdir(folder)
if src.elemtype()=='uint8' and self.cbFormat.itemIndex==8:
color=False
else:
color=True
self.writer=cv.CreateVideoWriter(self.filename,fcc,float(self.eFps.text),(width,height),color)
self.lblFilename.caption=fname
self.pState.color='red'
except Exception,msg:
print Exception,msg
if self.writer:
try:
np=arrToNumpy.arrToNumpy(src)
img=array2cv(np)
cv.WriteFrame(self.writer,img)
self.framecnt+=1
self.lblFrameCnt.caption=str(self.framecnt)
except Exception,msg:
print Exception,msg
[docs]def CreatePlugin(hWnd, name=''):
'''
Scorpion Plugin Stub - Required
'''
cntr=GetControlByHandle(hWnd)
return VideoWriterPlugin(cntr,name)