Advertisement
Guest User

OpenCV connection to Blender25

a guest
Sep 18th, 2010
1,426
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 21.51 KB | None | 0 0
  1. #!/usr/bin/python
  2. # OpenCV and Blender - Test1 Sept 19, 2010
  3. # by HartsAntler - bhartsho@yahoo.com
  4. # License: GNU GPL3
  5. # Tested with Ubuntu Lucid and Blender2.54
  6.  
  7. '''
  8. Hacking - Ram Drive Workaround:
  9.     mkdir /tmp/ramdrive
  10.     sudo mount -t ramfs /dev/ram10 /tmp/ramdrive/
  11.     sudo chmod 777 /tmp/ramdrive
  12.  
  13.  
  14. Getting Blender Connected:
  15.     0. sudo apt-get install python-opencv python-pygame python3
  16.  
  17.     1. download posix_ipc from http://semanchuk.com/philip/posix_ipc
  18.     2. cd posix_ipc-0.8.1/
  19.     3. sudo python setup.py install
  20.     4. sudo python3 setup.py install
  21.     5. set the path to blender25 below `PATH2BLENDER`
  22.  
  23.     (blender will not respect local py3 installations? this step should be optional)
  24.     6. cp -Rv /usr/local/lib/python3.1/dist-packages/posix_ipc.so /<change me>/blender25/2.53/python/lib/python3.1/site-packages/.
  25.  
  26. #6 will fail if your local python is Python 3.1.2 [GCC 4.4.3] and Blender is compiled with Python 3.1.1 [GCC 4.3.3]
  27. ImportError: /home/brett/pyppet2/blender25/2.53/python/lib/python3.1/site-packages/posix_ipc.so: undefined symbol: PyUnicodeUCS4_FromString
  28.  
  29. '''
  30. PATH2BLENDER = 'blender25/blender'
  31.  
  32. Size640x480_RGBA = 1228800
  33. import os, sys, time
  34.  
  35. SHARED_MEMORY = '/mysharedmem'      # '/tmp/something' is invlid is tmp sharedmemory has not been created
  36. SEMAPHORE_NAME = '/mysemaphore'
  37.  
  38. PY_MAJOR_VERSION = sys.version_info[0]
  39. if PY_MAJOR_VERSION > 2: NULL_CHAR = 0
  40. else: NULL_CHAR = '\0'
  41.  
  42.  
  43. import multiprocessing, ctypes
  44. from multiprocessing import sharedctypes
  45.  
  46. posix_ipc = None
  47. try: import posix_ipc
  48. except: print( 'posix_ipc not installed' )
  49.  
  50. import mmap
  51.  
  52.  
  53. def shm_write(mapfile, s):
  54.     """Writes the string s to the mapfile"""
  55.     mapfile.seek(0)
  56.     #s += '\0'  # I append a trailing NULL in case I'm communicating with a C program.
  57.     if PY_MAJOR_VERSION > 2: s = s.encode()
  58.     mapfile.write(s)
  59.  
  60. def shm_read_slowly(mapfile):
  61.     """Reads a string from the mapfile and returns that string"""
  62.     mapfile.seek(0)
  63.     s = [ ]
  64.     c = mapfile.read_byte()
  65.     while c != NULL_CHAR:
  66.         s.append(c)
  67.         c = mapfile.read_byte()
  68.     if PY_MAJOR_VERSION > 2: s = [chr(c) for c in s]
  69.     s = ''.join(s)  
  70.     return s
  71.  
  72. def shm_read(mapfile):
  73.     """Reads a string from the mapfile and returns that string"""
  74.     mapfile.seek(0)
  75.     return mapfile.read(Size640x480_RGBA)
  76.  
  77. '''
  78. if 0:       # ctypes can not load libc
  79.     import ctypes.util
  80.     libc = ctypes.util.find_library('libc')
  81.     print libc
  82.     libc = ctypes.CDLL('/usr/lib/libc.a')
  83.     print libc
  84.     raise
  85. '''
  86.  
  87. class BlenderConnection(object):
  88.     def __init__(self):
  89.         if posix_ipc:
  90.             print( 'trying to open sharedmemory')
  91.             self.shm = memory = posix_ipc.SharedMemory(SHARED_MEMORY)
  92.             # MMap the shared memory
  93.             self.mapfile = mmap.mmap(memory.fd, memory.size, mmap.MAP_PRIVATE)      # MAP_PRIVATE=copy-on-write
  94.             #os.close(memory.fd)        # also valid
  95.             memory.close_fd()
  96.             print( 'sharedmem', self.mapfile)
  97.             self.semaphore = posix_ipc.Semaphore(SEMAPHORE_NAME)
  98.  
  99.         self.bimage = im = bpy.data.images.new('_opencv_')
  100.         im.source = 'FILE'
  101.         im.filepath = '/tmp/ramdrive/dump.png'
  102.         tex = bpy.data.textures[0]
  103.         tex.type = 'IMAGE'      # invalidates object, get again
  104.         self.btexture = tex = bpy.data.textures[0]
  105.         tex.image = im
  106.         self.bmat = mat = bpy.data.materials[0]
  107.         mat.use_transparency=True
  108.         mat.alpha = .0
  109.         mat.emit = 1.0
  110.         mat.specular_intensity = .0
  111.  
  112.         ts = mat.texture_slots[0]
  113.         ts.use_map_alpha=True
  114.  
  115.         scn = bpy.data.scenes[0]
  116.         scn.game_settings.material_mode = 'GLSL'
  117.  
  118.         self.setup_blender_loop()
  119.  
  120.     def setup_blender_loop(self):       # hacks like this should not have to be pulled anymore!?
  121.         bpy.ops.screen.animation_play('EXEC_DEFAULT')
  122.         for area in bpy.context.window.screen.areas:
  123.             print(area.type)
  124.             if area.type == 'VIEW_3D':
  125.                 #print('viewportshade', area.viewport_shade)
  126.                 for reg in area.regions:
  127.                     print( '\tregion: ', reg.type )
  128.                     if reg.type == 'WINDOW':
  129.                         print( 'adding callback' )
  130.                         reg.callback_add(self.loop, (area,reg), 'POST_PIXEL')
  131.  
  132.     def loop( self, area, reg ):
  133.         if posix_ipc:
  134.             self.semaphore.acquire()
  135.             data = shm_read( self.mapfile )
  136.             self.semaphore.release()
  137.             print( len(data) )
  138.         if self.bimage.bindcode:
  139.             #self.bimage.gl_free()
  140.             self.bimage.reload()
  141.  
  142. if '--blender' in sys.argv:
  143.     import bpy
  144.     bc = BlenderConnection()
  145.  
  146. else:
  147.     import pygame
  148.     #import Image, ImageDraw, ImageChops
  149.     import gtk, glib, cairo, pango, gobject
  150.  
  151.     import opencv as cv
  152.     from opencv import highgui
  153.     cv.cvSetNumThreads(3)       # 4 threads might be wasteful
  154.     print( 'opencv threads', cv.cvGetNumThreads() )
  155.  
  156.     _colorspaces = '''
  157.     CV_BGR2GRAY
  158.     CV_BGR2HLS
  159.     CV_BGR2HSV
  160.     CV_BGR2Lab
  161.     CV_BGR2Luv
  162.     CV_BGR2RGB
  163.     CV_BGR2XYZ
  164.     CV_BGR2YCrCb
  165.     '''
  166.     ColorSpaces = {}
  167.     ColorSpacesByValue = {}
  168.     for name in _colorspaces.splitlines():
  169.         name = name.strip()
  170.         if name:
  171.             value = getattr(cv,name)
  172.             ColorSpacesByValue[ value ] = name
  173.             ColorSpaces[ name ] = value
  174.  
  175. BG_RED = 0.98
  176. BG_GREEN = 0.98
  177. BG_BLUE = 0.99
  178. BG_ALPHA = 0.0
  179. BG_COLOR = (BG_RED,BG_GREEN,BG_BLUE,BG_ALPHA)
  180.  
  181. def transparent_window( win, color=BG_COLOR, decorate=False ):
  182.     win.set_decorated( decorate )
  183.     # Tell GTK+ that we want to draw the windows background ourself.
  184.     # If we don't do this then GTK+ will clear the window to the
  185.     # opaque theme default color, which isn't what we want.
  186.     win.set_app_paintable(True)
  187.     make_transparent( win, color )
  188.  
  189.  
  190. def expose_transparent(widget, event):
  191.     cr = widget.window.cairo_create()
  192.     r,g,b,a = widget._trans_color_hack
  193.     cr.set_source_rgba(r, g, b, a) # Transparent
  194.     # Draw the background
  195.     cr.set_operator(cairo.OPERATOR_SOURCE)
  196.     cr.paint()
  197.     return False
  198.  
  199. def make_transparent(widget, color=BG_COLOR ):
  200.     widget._trans_color_hack = color
  201.     # The X server sends us an expose event when the window becomes
  202.     # visible on screen. It means we need to draw the contents.  On a
  203.     # composited desktop expose is normally only sent when the window
  204.     # is put on the screen. On a non-composited desktop it can be
  205.     # sent whenever the window is uncovered by another.
  206.     #
  207.     # The screen-changed event means the display to which we are
  208.     # drawing changed. GTK+ supports migration of running
  209.     # applications between X servers, which might not support the
  210.     # same features, so we need to check each time.
  211.     widget.connect('expose-event', expose_transparent)
  212.     #win.connect('screen-changed', self.screen_changed)
  213.     # To check if the display supports alpha channels, get the colormap
  214.     screen = widget.get_screen()
  215.     colormap = screen.get_rgba_colormap()
  216.     # Now we have a colormap appropriate for the screen, use it
  217.     widget.set_colormap(colormap)
  218.     return False
  219.  
  220.  
  221. '''
  222. useful utils:
  223. cv.Ipl2NumPy
  224. cv.Ipl2PIL
  225. cv.NumPy2Ipl
  226. cv.NumPy2PIL
  227. cv.PIL2Ipl
  228. cv.PIL2NumPy
  229.  
  230. notes:
  231. CV_ADAPTIVE_THRESH_GAUSSIAN_C
  232. CV_ADAPTIVE_THRESH_MEAN_C
  233. CV_CALIB_CB_ADAPTIVE_THRESH
  234. CV_THRESH_BINARY
  235. CV_THRESH_BINARY_INV
  236. #something else? CV_THRESH_MASK     # adaptive only?
  237. #CV_THRESH_OTSU
  238. CV_THRESH_TOZERO
  239. CV_THRESH_TOZERO_INV
  240. CV_THRESH_TRUNC
  241. cvAdaptiveThreshold
  242. cvThreshHist
  243. cvThreshold
  244.  
  245. cvAdaptiveThreshold(*args)
  246.    cvAdaptiveThreshold(CvArr src, CvArr dst, double max_value, int adaptive_method = 0,
  247.        int threshold_type = 0, int block_size = 3,
  248.        double param1 = 5)
  249.  
  250. cvThreshold(*args)
  251.    cvThreshold(CvArr src, CvArr dst, double threshold, double max_value,
  252.        int threshold_type) -> double
  253.  
  254.  
  255. '''
  256.  
  257.  
  258.  
  259. def pygame_to_pil_img(pg_img):
  260.     imgstr = pygame.image.tostring(pg_img, 'RGB')
  261.     return Image.fromstring('RGB', pg_img.get_size(), imgstr)
  262.  
  263. def pil_to_pygame_img(pil_img):
  264.     imgstr = pil_img.tostring()
  265.     return pygame.image.fromstring(imgstr, pil_img.size, 'RGB')
  266.  
  267. class Trackable(object):
  268.     def __init__(self, haar):
  269.         self.haar = haar
  270.         self._cv_storage = cv.cvCreateMemStorage(0)
  271.         self.score = .0
  272.         self.rects = []
  273.         self.color = None
  274.         self.grayscale = None
  275.  
  276.     #       cv.cvSetImageROI( grayscale, cv.cvRect(fx, fy, fw, fh) )
  277.     #       cv.cvClearMemStorage(storage)   # this invalidates the f.x, f.* attributes
  278.     def detector( self, grayscale, scale=1 ):
  279.         self.grayscale = grayscale
  280.         storage = self._cv_storage
  281.         cv.cvClearMemStorage(storage)
  282.         # equalize histogram
  283.         cv.cvEqualizeHist(grayscale, grayscale)
  284.  
  285.         _rects = cv.cvHaarDetectObjects(grayscale, self.haar, storage, 1.2, 2, cv.CV_HAAR_DO_CANNY_PRUNING, cv.cvSize(25, 25))
  286.         rects = []
  287.         if _rects:
  288.             for r in _rects:
  289.                 rects.append( pygame.rect.Rect(r.x*scale, r.y*scale, r.width*scale, r.height*scale) )
  290.         return rects
  291.  
  292. _cfg_ubytes =  'active alpha blur athresh_block_size thresh_min thresh_max'.split()
  293. _cfg_ubytes += 'sobel_xorder sobel_yorder sobel_aperture'.split()
  294. _cfg_ubytes += 'split_red split_green split_blue'.split()
  295. FXtypes = 'FXsplit FXstencil FXblur FXsobel FXathresh FXthresh FXdetect'.split()
  296. _cfg_ubytes += FXtypes
  297. class LayerConfig( ctypes.Structure ):
  298.     _fields_ = [ ('colorspace',ctypes.c_int) ]
  299.     for tag in _cfg_ubytes: _fields_.append( (tag, ctypes.c_ubyte) )
  300.     #for tag in _cfg_ints: _fields_.append( (tag, ctypes.c_int) )
  301.     del tag
  302.  
  303. class UI(object):
  304.     def __init__(self, active, layers, rawimage):
  305.         self.active = active        # shared
  306.         self.layers = layers        # shared
  307.         self.rawimage = rawimage
  308.  
  309.         ## gtk ##
  310.         self.window = win = gtk.Window()
  311.         win.set_size_request( 900, 480 )
  312.         win.set_title( 'Harts OpenCV Blender Demo' )
  313.         win.connect('destroy', lambda w: gtk.main_quit() )
  314.         transparent_window( win, decorate=True )
  315.         root = gtk.HBox(); root.set_border_width( 3 )
  316.         win.add( root )
  317.  
  318.         #####################################
  319.         eb = gtk.EventBox()
  320.         root.pack_start( eb, expand=False )
  321.         self._drawing_area = da = gtk.DrawingArea()
  322.         da.set_size_request( 640,480 )
  323.         da.connect('realize', self.realize)
  324.         eb.add( da )
  325.         make_transparent(da)
  326.  
  327.         ##################
  328.         eb = gtk.EventBox()
  329.         root.pack_start( eb, expand=True )
  330.         split = gtk.VBox(); eb.add( split )
  331.         make_transparent(split)
  332.  
  333.         header = gtk.HBox(); split.pack_start( header, expand=False )
  334.         b = gtk.Button('open blender')
  335.         b.connect('clicked', lambda b: os.system('%s -P %s --blender &'%(PATH2BLENDER, sys.argv[0])) )
  336.         header.pack_start( b, expand=False )
  337.  
  338.         b = gtk.ToggleButton('[-]'); b.set_active(True)
  339.         b.connect('toggled', lambda b: win.set_decorated( b.get_active() ) )
  340.         header.pack_start( b, expand=False )
  341.        
  342.  
  343.         #ex = gtk.Expander( 'settings' ); ex.set_expanded(False)
  344.         #split.pack_start( ex, expand=False )
  345.         #ex = gtk.Expander( 'adjust layers' ); ex.set_expanded(True)
  346.         #split.pack_start( ex, expand=True)
  347.  
  348.         note = gtk.Notebook()
  349.         note.set_tab_pos( gtk.POS_RIGHT )
  350.         #ex.add( note )
  351.         split.pack_start( note )
  352.         for layer in layers:
  353.                 cspace = ColorSpacesByValue[ layer.colorspace ]
  354.                 tag = cspace.split('2')[-1]
  355.                 page = gtk.HBox()
  356.                 h = gtk.HBox()
  357.                 b = gtk.CheckButton()
  358.                 b.connect('toggled', lambda b,lay: setattr(lay,'active',bool(b.get_active())), layer)
  359.                 h.pack_start( b, expand=False )
  360.                 h.pack_start( gtk.Label(tag) )
  361.                 note.append_page( page, h )
  362.                 h.show_all()
  363.                 b.set_active( bool(layer.active) )
  364.  
  365.                 col1, col2 = gtk.VBox(), gtk.VBox()
  366.                 page.pack_start( col1, expand=False )
  367.                 page.pack_start( col2, expand=True )
  368.  
  369.                 fxgroups = {}
  370.                 for name in FXtypes:
  371.                     bx = gtk.VBox()
  372.                     fxgroups[ name.split('FX')[-1] ] = bx
  373.                     frame = gtk.Frame(); frame.add( bx )
  374.                     val = getattr( layer, name )
  375.                     b = gtk.CheckButton( name )
  376.                     b.set_active( bool(val) )
  377.                     b.connect('toggled', lambda b,lay,nam: setattr(lay,nam,bool(b.get_active())), layer, name)
  378.                     frame.set_label_widget( b )
  379.                     col2.pack_end( frame )
  380.  
  381.                 for name in dir(layer):
  382.                     if not name.startswith('_') and name not in ['colorspace','active']+FXtypes:
  383.                         val = getattr( layer, name )
  384.                         bx = None
  385.                         for fx in fxgroups:
  386.                             if name.startswith(fx):
  387.                                 bx = fxgroups[fx]
  388.                                 break
  389.                         if not bx:
  390.                             adjust = gtk.Adjustment(
  391.                                 value=val,
  392.                                 lower=0, upper=255,
  393.                                 step_incr=1 )
  394.                             adjust.connect("value_changed", lambda a,lay,nam: setattr(lay,nam,int(a.value)), layer,name)
  395.                             scale = gtk.HScale( adjust ); scale.set_value_pos(gtk.POS_RIGHT)
  396.                             scale.set_digits(0)
  397.                             frame = gtk.Frame( name )
  398.                             frame.add( scale )
  399.                             col2.pack_start( frame )
  400.                         else:
  401.                             if fx=='split':
  402.                                 b = gtk.CheckButton( name )
  403.                                 b.set_active( bool(getattr(layer,name)) )
  404.                                 b.connect('toggled', lambda b,lay,nam: setattr(lay,nam,bool(b.get_active())), layer, name)
  405.                                 bx.pack_start( b )
  406.                             else:
  407.                                 upper = 255
  408.                                 lower = 0
  409.                                 step = 1
  410.                                 if name.startswith('sobel'):
  411.                                     upper = 31; lower = 1; step=2
  412.                                 adjust = gtk.Adjustment(
  413.                                     value=val,
  414.                                     lower=lower, upper=upper,
  415.                                     step_incr=step )
  416.                                 adjust.connect("value_changed", lambda a,lay,nam: setattr(lay,nam,int(a.value)), layer,name)
  417.                                 scale = gtk.HScale( adjust ); scale.set_value_pos(gtk.POS_RIGHT)
  418.                                 scale.set_digits(0)
  419.                                 row = gtk.HBox()
  420.                                 row.pack_start( gtk.Label( name.split(fx)[-1].replace('_',' ') ), expand=False )
  421.                                 row.pack_start( scale )
  422.                                 bx.pack_start( row )
  423.  
  424.         win.show_all()
  425.  
  426.     def realize( self, da ):
  427.         wid = da.window.xid
  428.         os.environ['SDL_WINDOWID'] = str(wid)       # child fork respects environ
  429.         self.subprocess = p = multiprocessing.Process(target=subprocess, args=(self.active,self.layers,self.rawimage))
  430.         p.start()
  431.         #p.join()
  432.         time.sleep(1)
  433.         print( 'trying to open sharedmemory')
  434.         #self.shm = memory = posix_ipc.SharedMemory(SHARED_MEMORY)
  435.         # MMap the shared memory
  436.         #self.mapfile = mmap.mmap(memory.fd, memory.size, mmap.MAP_PRIVATE)
  437.         #os.close(memory.fd)        # also valid
  438.         #memory.close_fd()
  439.         #print( 'sharedmem', self.mapfile)
  440.         #self.semaphore = posix_ipc.Semaphore(SEMAPHORE_NAME)
  441.         #glib.timeout_add( 300, self.check_shm )
  442.  
  443.     def check_shm( self ):
  444.         self.semaphore.acquire()
  445.         data = shm_read( self.mapfile )
  446.         self.semaphore.release()
  447.         #print len(data)
  448.         #print self.rawimage[0]     # ctypes is slightly faster or slower than posix_ipc?
  449.         return True
  450.  
  451. class Camera(object):
  452.     try:    ## opencv haar detect is multithreaded! ##
  453.         DO_HAAR = True
  454.         FaceCascade = cv.cvLoadHaarClassifierCascade('haarcascades/haarcascade_frontalface_alt.xml', cv.cvSize(1,1))
  455.         EyesCascade = cv.cvLoadHaarClassifierCascade('haarcascades/haarcascade_eye.xml', cv.cvSize(1,1))
  456.     except:
  457.         print( 'download opencv latest source code, and copy the haarcascades folder to here')
  458.         DO_HAAR = False
  459.  
  460.     def exit(self):
  461.         self.mapfile.close()
  462.         # I could call memory.unlink() here but in order to demonstrate
  463.         # unlinking at the module level I'll do it that way.
  464.         posix_ipc.unlink_shared_memory( SHARED_MEMORY )
  465.         print( 'subprocess clean exit')
  466.  
  467.     def __init__(self, layers, rawimage):
  468.         self.layers = layers
  469.         self.rawimage = rawimage
  470.         self.shm = memory = posix_ipc.SharedMemory(SHARED_MEMORY, posix_ipc.O_CREAT, size=Size640x480_RGBA)
  471.         self.mapfile = mmap.mmap(memory.fd, memory.size, mmap.ACCESS_WRITE)#, mmap.MAP_PRIVATE)
  472.         memory.close_fd()
  473.         print( 'sharedmemory created', self.mapfile)
  474.         self.semaphore = posix_ipc.Semaphore(SEMAPHORE_NAME, posix_ipc.O_CREAT)
  475.  
  476.  
  477.         pygame.display.init()
  478.         SSBACKEND = pygame.transform.get_smoothscale_backend()
  479.         if SSBACKEND == 'GENERIC':
  480.             try: pygame.transform.set_smoothscale_backend( 'SSE' ); SSBACKEND = 'SSE'
  481.             except: print( 'SSE backend not available')
  482.         print( 'smooth scale backend', SSBACKEND)
  483.  
  484.  
  485.         self.prevfaces = None
  486.         self.active = True
  487.         self.index = 0
  488.         for arg in sys.argv:
  489.             if arg.startswith('camera='): self.index = int(arg.split('=')[-1]); break
  490.         self.camera_pointer = highgui.cvCreateCameraCapture(self.index)     # this is the old swig bindings ubuntu lucid works fine
  491.  
  492.         # HIGHGUI ERROR: V4L: setting property #16 is not supported
  493.         #highgui.cvSetCaptureProperty( self.camera_pointer, highgui.CV_CAP_PROP_CONVERT_RGB, True )
  494.         ## default color space is BGR - linux ##
  495.         self.resize_capture( 640, 480 )
  496.         self.resize_output( 640, 480 )
  497.  
  498.         if self.DO_HAAR:
  499.             self.track_face = Trackable( self.FaceCascade )
  500.  
  501.     def resize_capture( self, x,y ):
  502.         self.cwidth = x
  503.         self.cheight = y
  504.         highgui.cvSetCaptureProperty( self.camera_pointer, highgui.CV_CAP_PROP_FRAME_WIDTH, self.cwidth )
  505.         highgui.cvSetCaptureProperty( self.camera_pointer, highgui.CV_CAP_PROP_FRAME_HEIGHT, self.cheight )
  506.         highgui.cvSetCaptureProperty( self.camera_pointer, highgui.CV_CAP_PROP_FPS, 30 )
  507.  
  508.         self._rgb8 = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 3)
  509.         self._rgb32 = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_32F, 3)
  510.         self._gray8 = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 1)
  511.         self._gray32 = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_32F, 1)
  512.  
  513.         self._R = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 1)
  514.         self._G = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 1)
  515.         self._B = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 1)
  516.         self._A = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 1)
  517.  
  518.  
  519.     def resize_output( self, x, y ):
  520.         self.owidth = x
  521.         self.oheight = y
  522.         pygame.display.set_mode((x,y), 0, 32 )      # size, flags, depth
  523.         self.screen = pygame.display.get_surface()
  524.  
  525.     def loop(self):
  526.         self.semaphore.release()
  527.         ## BGR - linux
  528.         _frame = highgui.cvQueryFrame(self.camera_pointer)      # grabFrame returns 1?
  529.         if not _frame: print( 'lost connection to webcam?')
  530.  
  531.         self.screen.fill( (0,0,0,0) )
  532.         surf = self.screen.copy()
  533.         surf.fill( (0,0,255) )
  534.         surf.set_alpha(255)
  535.         stencil = []
  536.  
  537.         ## pre allocated ##
  538.         _rgb8 = self._rgb8
  539.         _rgb32 = self._rgb32
  540.         _gray8 = self._gray8
  541.         _gray32 = self._gray32
  542.  
  543.         for layer in self.layers:
  544.             if layer.active:
  545.                 a = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 3)
  546.                 cv.cvCvtColor(_frame, a, layer.colorspace)
  547.                 #print 'colorspaced converted'
  548.                 ## FX
  549.                 if layer.FXsplit:
  550.                     _a = cv.cvCreateImage((self.cwidth,self.cheight), cv.IPL_DEPTH_8U, 4)
  551.                     cv.cvCvtColor(a, _a, cv.CV_RGB2RGBA)
  552.                     cv.cvSplit( _a, self._R, self._G, self._B, self._A )
  553.                     if layer.split_red: a = self._R
  554.                     elif layer.split_green: a = self._G
  555.                     elif layer.split_blue: a = self._B
  556.  
  557.                 if layer.FXblur:            # blur before threshing
  558.                     blur = layer.blur
  559.                     if blur < 1: blur = 1
  560.                     cv.cvSmooth( a, a, cv.CV_BLUR, blur )
  561.                 if layer.FXsobel and layer.sobel_aperture % 2 and layer.sobel_aperture < 32:
  562.                     if layer.sobel_xorder < layer.sobel_aperture and layer.sobel_yorder < layer.sobel_aperture:
  563.                         if a.nChannels == 1:
  564.                             cv.cvSobel( a, _gray32, layer.sobel_xorder, layer.sobel_yorder, layer.sobel_aperture )  #xorder, yorder, aperture
  565.                             cv.cvConvert( _gray32, a )#; cv.cvCvtColor(_sobel8, _sobel, cv.CV_GRAY2RGB)
  566.                         else:
  567.                             cv.cvSobel( a, _rgb32, layer.sobel_xorder, layer.sobel_yorder, layer.sobel_aperture )   #xorder, yorder, aperture
  568.                             cv.cvConvert( _rgb32, a )#; cv.cvCvtColor(_sobel8, _sobel, cv.CV_GRAY2RGB)
  569.                 if layer.FXthresh:
  570.                     cv.cvThreshold( a, a, layer.thresh_min, layer.thresh_max, cv.CV_THRESH_BINARY )
  571.                 if layer.FXathresh:
  572.                     blocksize = layer.athresh_block_size
  573.                     if blocksize <= 2: blocksize = 3
  574.                     if blocksize % 2 != 1: blocksize += 1
  575.                     if a.nChannels == 1:
  576.                         cv.cvAdaptiveThreshold(a, a, 255, cv.CV_ADAPTIVE_THRESH_MEAN_C, cv.CV_THRESH_BINARY, blocksize )
  577.                     else:
  578.                         cv.cvCvtColor(a, _gray8, cv.CV_RGB2GRAY)
  579.                         cv.cvAdaptiveThreshold(_gray8, _gray8, 255, cv.CV_ADAPTIVE_THRESH_MEAN_C, cv.CV_THRESH_BINARY, blocksize )
  580.                         cv.cvCvtColor(_gray8, a, cv.CV_GRAY2RGB)
  581.  
  582.                 if a.nChannels == 1:
  583.                         cv.cvCvtColor(a, _rgb8, cv.CV_GRAY2RGB)
  584.                         a = _rgb8
  585.                 ## pygame
  586.                 b = pygame.image.frombuffer(a.imageData, (self.cwidth,self.cheight), 'RGB')
  587.                 b.set_alpha( layer.alpha )
  588.                 if layer.FXstencil: stencil.append( b )
  589.                 surf.blit(b, (0,0))
  590.  
  591.         self.screen.lock()
  592.         array = pygame.surfarray.pixels_alpha(self.screen)
  593.         if stencil:
  594.             stencil = pygame.transform.average_surfaces( stencil )
  595.             alpha = pygame.surfarray.pixels3d( stencil )
  596.             array[:] = alpha[:,:,0]
  597.             del alpha
  598.         else: array[:] = 255            # values higher than 256 are additive!
  599.         del array
  600.         self.screen.unlock()
  601.         self.screen.blit( surf, (0,0) )
  602.         #data = pygame.image.tostring(self.screen, 'RGBA')
  603.         pygame.display.flip()
  604.         #self.rawimage.value = data
  605.         #self.semaphore.acquire()       # waiting for Blender to update to python 3.1.2 and support directly setting a RGBA buffer
  606.         #shm_write( self.mapfile, data )
  607.         #self.semaphore.release()
  608.  
  609.         # this is an ugly hack #
  610.         #tmp = pygame.transform.scale( self.screen, (320,240) )
  611.         os.system('mv /tmp/ramdrive/_dump.png /tmp/ramdrive/dump.png')      # atomic
  612.         pygame.image.save(self.screen, '/tmp/ramdrive/_dump.png')
  613.  
  614.         return self.active
  615.  
  616.  
  617.  
  618. def subprocess( active, layers, rawimage ):
  619.     cam = Camera( layers, rawimage )
  620.     while active.value: cam.loop()
  621.     cam.exit()
  622.  
  623.  
  624. if __name__ == '__main__' and '--blender' not in sys.argv:
  625.     #CV_BGR2HLS
  626.     #CV_BGR2Luv
  627.     #CV_BGR2XYZ
  628.     _default_spaces = [
  629.         (cv.CV_BGR2RGB,),
  630.         (cv.CV_BGR2HSV,),
  631.         (cv.CV_BGR2Lab,),
  632.         (cv.CV_BGR2YCrCb,),
  633.     ]
  634.     active = sharedctypes.Value('i', 1, lock=False)
  635.     rawimage = sharedctypes.Array( ctypes.c_char, Size640x480_RGBA, lock=True )
  636.     layers = sharedctypes.Array( LayerConfig, _default_spaces, lock=True )
  637.     for layer in layers:
  638.         layer.alpha = 32
  639.         layer.thresh_min = 32
  640.         layer.thresh_max = 200
  641.         layer.blur = 2
  642.         layer.athresh_block_size = 3
  643.         layer.sobel_xorder = 1
  644.         layer.sobel_yorder = 1
  645.         layer.sobel_aperture = 5
  646.     layers[0].active = 1
  647.     layers[0].alpha = 128
  648.  
  649.     gui = UI( active, layers, rawimage )
  650.     gtk.main()
  651.     gui.active.value = 0
  652.     print( 'waiting for child to exit')
  653.     time.sleep(1)
  654.     gui.subprocess.join()
  655.     print( 'main process exit')
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement