[mousetrap] New Backends structure, no changes to methods calls, classes, return values



commit 373909d8c2bf6ed9685efc043879bdb97137f561
Author: Flavio Percoco Premoli <flaper87 gmail com>
Date:   Tue Jul 21 09:49:49 2009 +0200

    New Backends structure, no changes to methods calls, classes, return values

 src/ocvfw/backends/OcvfwBase.py   |  275 +++++++++++++++++++
 src/ocvfw/backends/OcvfwCtypes.py |   61 +++++
 src/ocvfw/backends/OcvfwPython.py |  242 +++++++++++++++++
 src/ocvfw/idm/color.py            |  525 +++++++++++++++++++++++++++++++++++++
 4 files changed, 1103 insertions(+), 0 deletions(-)
---
diff --git a/src/ocvfw/backends/OcvfwBase.py b/src/ocvfw/backends/OcvfwBase.py
new file mode 100644
index 0000000..bac6ce6
--- /dev/null
+++ b/src/ocvfw/backends/OcvfwBase.py
@@ -0,0 +1,275 @@
+# -*- coding: utf-8 -*-
+
+# Ocvfw
+#
+# Copyright 2009 Flavio Percoco Premoli
+#
+# This file is part of Ocvfw.
+#
+# Ocvfw is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License v2 as published
+# by the Free Software Foundation.
+#
+# Ocvfw is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ocvfw.  If not, see <http://www.gnu.org/licenses/>>.
+
+"""Little  Framework for OpenCV Library."""
+
+__id__        = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2008 Flavio Percoco Premoli"
+__license__   = "GPLv2"
+
+import os
+import re
+import time
+from .. import debug
+from .. import commons as co
+
+def exists_backend(bknd):
+    reg = re.compile(r'([A-Za-z0-9]+)\.py$', re.DOTALL)
+    dirname = os.path.dirname(__file__)
+
+    for f in os.listdir("%s/" % dirname):
+        if reg.match(f):
+            return True
+    return False
+
+def get_backend(bknd):
+    return __import__("%s" % bknd, globals(), locals(), [])
+
+class OcvfwBase:
+    
+    def __init__( self ):
+        """
+        Initialize the module and set its main variables.
+        """
+
+        self.img          = None
+        self.mhi          = None
+        self.img_lkpoints = { "current" : [],
+                              "last"    : [],
+                              "points"  : [] }
+
+        self.__lk_swap = False
+        self.imageScale   = 1.5
+
+    def set(self, key, value):
+        """
+        Changes some class settings
+
+        Arguments:
+        - self: The main object pointer.
+        - key: The key to change.
+        - value: The new value.
+        """
+        if hasattr(self, "%s" % key):
+            getattr(self, "%s" % key)(value)
+            debug.debug("OcvfwBase", "Changed %s value to %s" % (key, value))
+            return True
+        
+        debug.debug("OcvfwBase", "%s not found" % (key))
+        return False
+
+    def lk_swap(self, set=None):
+        """
+        Enables/Disable the lk points swapping action.
+
+        Arguments:
+        - self: The main object pointer.
+        - set: The new value. If None returns the current state.
+        """
+        
+        if set is None:
+            return self.__lk_swap
+        
+        self.__lk_swap = set
+
+    def new_image(self, size, num, ch):
+        """
+        Creates a new image 
+        """
+
+        if type(size) == "<type 'tuple'>":
+            size = co.cv.cvSize( size[0], size[1])
+
+        return co.cv.cvCreateImage( size, num, ch)
+
+    def set_camera_idx(self, idx):
+        """
+        Changes the camera device index.
+
+        Arguments:
+        - self: The main object pointer.
+        - idx: The camera index. For Example: 0 for /dev/video0
+        """
+        self.idx = idx
+
+    def wait_key(self, num):
+        """
+        Simple call to the co.hg.cvWaitKey function, which has to be called periodically.
+
+        Arguments:
+        - self: The main object pointer.
+        - num: An int value.
+        """
+        return co.hg.cvWaitKey(num)
+    
+    def start_camera(self, params = None):
+        """
+        Starts the camera capture using co.hg.
+
+        Arguments:
+        - params: A list with the capture properties. NOTE: Not implemented yet.
+        """
+        self.capture = co.hg.cvCreateCameraCapture( int(self.idx) )
+        debug.debug( "ocvfw", "cmStartCamera: Camera Started" )
+    
+    def query_image(self, bgr=False, flip=False):
+        """
+        Queries the new frame.
+
+        Arguments:
+        - self: The main object pointer.
+        - bgr: If True. The image will be converted from RGB to BGR.
+
+        Returns The image even if it was stored in self.img
+        """
+
+        frame = co.hg.cvQueryFrame( self.capture )
+
+        if not  self.img:
+            self.storage        = co.cv.cvCreateMemStorage(0)
+            self.imgSize        = co.cv.cvGetSize (frame)
+            self.img            = co.cv.cvCreateImage ( self.imgSize, 8, 3 )
+            #self.img.origin     = frame.origin
+            self.grey           = co.cv.cvCreateImage ( self.imgSize, 8, 1 )
+            self.yCrCb          = co.cv.cvCreateImage ( self.imgSize, 8, 3 )
+            self.prevGrey       = co.cv.cvCreateImage ( self.imgSize, 8, 1 )
+            self.pyramid        = co.cv.cvCreateImage ( self.imgSize, 8, 1 )
+            self.prevPyramid    = co.cv.cvCreateImage ( self.imgSize, 8, 1 )
+            self.small_img       = co.cv.cvCreateImage( co.cv.cvSize( co.cv.cvRound ( self.imgSize.width/self.imageScale),
+                                    co.cv.cvRound ( self.imgSize.height/self.imageScale) ), 8, 3 )
+        self.img = frame
+        co.cv.cvCvtColor(self.img, self.grey, co.cv.CV_BGR2GRAY)
+
+        self.wait_key(10)
+        return True
+    
+    def set_lkpoint(self, point):
+        """
+        Set a point to follow it using the L. Kallman method.
+
+        Arguments:
+        - self: The main object pointer.
+        - point: A co.cv.cvPoint Point.
+        """
+
+        cvPoint = co.cv.cvPoint( point.x, point.y )
+
+        self.img_lkpoints["current"] = [ co.cv.cvPointTo32f ( cvPoint ) ]
+
+        if self.img_lkpoints["current"]:
+            co.cv.cvFindCornerSubPix (
+                self.grey,
+                self.img_lkpoints["current"],
+                co.cv.cvSize (20, 20), co.cv.cvSize (-1, -1),
+                co.cv.cvTermCriteria (co.cv.CV_TERMCRIT_ITER | co.cv.CV_TERMCRIT_EPS, 20, 0.03))
+
+            point.set_opencv( cvPoint )
+            self.img_lkpoints["points"].append(point)
+
+            setattr(point.parent, point.label, point)
+
+            if len(self.img_lkpoints["last"]) > 0:
+                self.img_lkpoints["last"].append( self.img_lkpoints["current"][0] )
+
+            debug.debug( "ocvfw", "cmSetLKPoints: New LK Point Added" )
+        else:
+            self.img_lkpoints["current"] = []
+
+    def clean_lkpoints(self):
+        """
+        Cleans all the registered points.
+
+        Arguments:
+        - self: The main object pointer
+        """
+
+        self.img_lkpoints = { "current" : [],
+                              "last"    : [],
+                              "points"  : [] }
+
+    def show_lkpoints(self):
+        """
+        Callculate the optical flow of the set points and draw them in the image.
+
+        Arguments:
+        - self: The main object pointer.
+        """
+
+        # calculate the optical flow
+        optical_flow = co.cv.cvCalcOpticalFlowPyrLK (
+            self.prevGrey, self.grey, self.prevPyramid, self.pyramid,
+            self.img_lkpoints["last"], len( self.img_lkpoints["last"] ),
+            co.cv.cvSize (20, 20), 3, len( self.img_lkpoints["last"] ), None,
+            co.cv.cvTermCriteria (co.cv.CV_TERMCRIT_ITER|co.cv.CV_TERMCRIT_EPS, 20, 0.03), 0)
+
+        if isinstance(optical_flow[0], tuple):
+            self.img_lkpoints["current"], status = optical_flow[0]
+        else:
+            self.img_lkpoints["current"], status = optical_flow
+
+
+        # initializations
+        counter = 0
+        new_points = []
+
+        for point in self.img_lkpoints["current"]:
+
+            if not status[counter]:
+                continue
+
+            # this point is a correct point
+            current = self.img_lkpoints["points"][counter]
+            current.set_opencv(co.cv.cvPoint(int(point.x), int(point.y)))
+
+            new_points.append( point )
+
+            setattr(current.parent, current.label, current)
+
+            # draw the current point
+            current.parent.draw_point(point.x, point.y)
+
+            # increment the counter
+            counter += 1
+
+
+        #debug.debug( "ocvfw", "cmShowLKPoints: Showing %d LK Points" % counter )
+
+        # set back the self.imgPoints we keep
+        self.img_lkpoints["current"] = new_points
+
+
+    def swap_lkpoints(self):
+        """
+        Swap the LK method variables so the new points will be the last points.
+        This function has to be called after showing the new points.
+
+        Arguments:
+        - self: The main object pointer.
+        """
+
+        # swapping
+        self.prevGrey, self.grey               = self.grey, self.prevGrey
+        self.prevPyramid, self.pyramid         = self.pyramid, self.prevPyramid
+        self.img_lkpoints["last"], self.img_lkpoints["current"] = \
+                                   self.img_lkpoints["current"], self.img_lkpoints["last"]
+
+
diff --git a/src/ocvfw/backends/OcvfwCtypes.py b/src/ocvfw/backends/OcvfwCtypes.py
new file mode 100644
index 0000000..46b61ee
--- /dev/null
+++ b/src/ocvfw/backends/OcvfwCtypes.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+
+# Ocvfw
+#
+# Copyright 2009 Flavio Percoco Premoli
+#
+# This file is part of Ocvfw.
+#
+# Ocvfw is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License v2 as published
+# by the Free Software Foundation.
+#
+# Ocvfw is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ocvfw.  If not, see <http://www.gnu.org/licenses/>>.
+
+"""Little  Framework for OpenCV Library."""
+
+__id__        = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2008 Flavio Percoco Premoli"
+__license__   = "GPLv2"
+
+
+import time
+from OcvfwBase import OcvfwBase
+from .. import debug
+from .. import commons as co
+
+class OcvfwCtypes(OcvfwBase):
+    """
+    This Class controlls the main camera functions.
+    It works as a little framework for Openco.cv.
+
+    This Backend uses ctypes opencv python bindings.
+    """
+    
+
+    def __init__(self):
+        """
+        Initialize the module and set its main variables.
+        """
+        co.cv = __import__("ctypesopencv.cv",
+                        globals(),
+                        locals(),
+                        [''])
+        
+        co.hg = __import__("ctypesopencv.highgui",
+                        globals(),
+                        locals(),
+                        [''])
+ 
+        OcvfwBase.__init__(self)
+
+
+
diff --git a/src/ocvfw/backends/OcvfwPython.py b/src/ocvfw/backends/OcvfwPython.py
new file mode 100644
index 0000000..069143e
--- /dev/null
+++ b/src/ocvfw/backends/OcvfwPython.py
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+
+# Ocvfw
+#
+# Copyright 2009 Flavio Percoco Premoli
+#
+# This file is part of Ocvfw.
+#
+# Ocvfw is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License v2 as published
+# by the Free Software Foundation.
+#
+# Ocvfw is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ocvfw.  If not, see <http://www.gnu.org/licenses/>>.
+
+"""Little  Framework for OpenCV Library."""
+
+__id__        = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2008 Flavio Percoco Premoli"
+__license__   = "GPLv2"
+
+import time
+from OcvfwBase import OcvfwBase
+from .. import debug
+from .. import commons as co
+
+class OcvfwPython(OcvfwBase):
+    """
+    This Class controlls the main camera functions.
+    It works as a little framework for Openco.cv.
+
+    This Backend uses normal opencv python bindings.
+    """
+
+    co.cv = __import__("opencv.cv",
+                        globals(),
+                        locals(),
+                        [''])
+        
+    co.hg = __import__("opencv.highgui",
+                        globals(),
+                        locals(),
+                        [''])
+
+    def __init__( self ):
+        """
+        Initialize the module and set its main variables.
+        """
+
+        OcvfwBase.__init__(self)
+
+    def add_message(self, message, font=co.cv.CV_FONT_HERSHEY_COMPLEX, poss=None):
+        """
+        Write a message into the image.
+
+        Arguments:
+        - self: The main object pointer.
+        - message: A string with the message.
+        - font: An OpenCV font to use.
+        - poss: The position of the message in the image. NOTE: Not enabled yet.
+        """
+
+        font = co.cv.cvInitFont ( font, 1, 1, 0.0, 1, co.cv.CV_AA)
+        textSize, ymin = co.cv.cvGetTextSize (message, font)
+        pt1 = co.cv.cvPoint ( ( self.img.width - textSize.width ) / 2 , 20 )
+        co.cv.cvPutText (self.img, message, pt1, font, co.cv.cvScalar (255, 0, 0))
+
+    def get_haar_points(self, haarCascade, method=co.cv.CV_HAAR_DO_CANNY_PRUNING):
+        """
+        Search for points matching the haarcascade selected.
+
+        Arguments:
+        - self: The main object pointer.
+        - haarCascade: The selected cascade.
+        - methode: The search method to use. DEFAULT: co.cv.CV_HAAR_DO_CANNY_PRUNING.
+
+        Returns a list with the matches.
+        """
+
+        cascade = co.cv.cvLoadHaarClassifierCascade( haarCascade, self.imgSize )
+
+        if not cascade:
+            debug.exception( "ocvfw", "The Haar Classifier Cascade load failed" )
+
+        co.cv.cvResize( self.img, self.small_img, co.cv.CV_INTER_LINEAR )
+
+        co.cv.cvClearMemStorage( self.storage )
+
+        points = co.cv.cvHaarDetectObjects( self.small_img, cascade, self.storage, 1.2, 2, method, co.cv.cvSize(20, 20) )
+
+        if points:
+            matches = [ [ co.cv.cvPoint( int(r.x*self.imageScale), int(r.y*self.imageScale)), \
+                          co.cv.cvPoint( int((r.x+r.width)*self.imageScale), int((r.y+r.height)*self.imageScale) )] \
+                          for r in points]
+            debug.debug( "ocvfw", "cmGetHaarPoints: detected some matches" )
+            return matches
+
+    def get_haar_roi_points(self, haarCascade, rect, origSize=(0, 0), method=co.cv.CV_HAAR_DO_CANNY_PRUNING):
+        """
+        Search for points matching the haarcascade selected.
+
+        Arguments:
+        - self: The main object pointer.
+        - haarCascade: The selected cascade.
+        - methode: The search method to use. DEFAULT: co.cv.CV_HAAR_DO_CANNY_PRUNING.
+
+        Returns a list with the matches.
+        """
+
+        cascade = co.cv.cvLoadHaarClassifierCascade( haarCascade, self.imgSize )
+
+        if not cascade:
+            debug.exception( "ocvfw", "The Haar Classifier Cascade load failed" )
+
+        co.cv.cvClearMemStorage(self.storage)
+
+        imageROI = co.cv.cvGetSubRect(self.img, rect)
+
+        if cascade:
+            points = co.cv.cvHaarDetectObjects( imageROI, cascade, self.storage,
+                                    1.2, 2, method, co.cv.cvSize(20,20) )
+        else:
+            debug.exception( "ocvfw", "The Haar Classifier Cascade load Failed (ROI)" )
+
+        if points:
+            matches = [ [ co.cv.cvPoint( int(r.x+origSize[0]), int(r.y+origSize[1])), \
+                          co.cv.cvPoint( int(r.x+r.width+origSize[0]), int(r.y+r.height+origSize[1] ))] \
+                          for r in points]
+
+            debug.debug( "ocvfw", "cmGetHaarROIPoints: detected some matches" )
+            return matches
+
+
+
+
+    ##########################################
+    #                                        #
+    #          THIS IS NOT USED YET          #
+    #                                        #
+    ##########################################
+    def get_motion_points(self, imgRoi=None):
+        """
+        Calculate the motion points in the image.
+
+        Arguments:
+        - self: The main object pointer.
+        - start: The start ROI point.
+        - end: The end ROI point.
+        - num: The nomber of points to return
+
+        Returns A list with the points found.
+        """
+
+        mv = []
+        n_ = 4
+
+        timestamp = time.clock()/1.0
+
+        if imgRoi:
+            img     = co.cv.cvGetSubRect( self.img, imgRoi )
+            imgSize = co.cv.cvSize( imgRoi.width, imgRoi.height )
+            self.imgRoi = img
+        else:
+            img     = self.img
+            imgSize = self.imgSize
+
+        # Motion Related Variables
+        if not self.mhi or self.mhi.width != imgSize.width or self.mhi.height != imgSize.height:
+            self.buf        = [ 0, 0, 0, 0 ]
+            self.lastFm     = 0
+            self.mhiD       = 1
+            self.maxTD      = 0.5
+            self.minTD      = 0.05
+            self.mask       = co.cv.cvCreateImage( imgSize,  8, 1 )
+            self.mhi        = co.cv.cvCreateImage( imgSize, 32, 1 )
+            self.orient     = co.cv.cvCreateImage( imgSize, 32, 1 )
+            self.segmask    = co.cv.cvCreateImage( imgSize, 32, 1 )
+
+            co.cv.cvZero( self.mhi )
+
+            for i in range( n_ ):
+                self.buf[i] = co.cv.cvCreateImage( imgSize, 8, 1 )
+                co.cv.cvZero( self.buf[i] )
+
+        idx1 = self.lastFm
+
+        # convert frame to grayscale
+        co.cv.cvCvtColor( img, self.buf[self.lastFm], co.cv.CV_BGR2GRAY )
+
+        # index of (self.lastFm - (n_-1))th frame
+        idx2 = ( self.lastFm + 1 ) % n_
+        self.lastFm = idx2
+
+        silh = self.buf[idx2]
+
+        # Get difference between frames
+        co.cv.cvAbsDiff( self.buf[idx1], self.buf[idx2], silh )
+
+        # Threshold it
+        co.cv.cvThreshold( silh, silh, 30, 1, co.cv.CV_THRESH_BINARY )
+
+        # Update MHI
+        co.cv.cvUpdateMotionHistory( silh, self.mhi, timestamp, self.mhiD )
+
+        co.cv.cvCvtScale( self.mhi, self.mask, 255./self.mhiD, (self.mhiD - timestamp)*255./self.mhiD )
+
+        co.cv.cvCalcMotionGradient( self.mhi, self.mask, self.orient, self.maxTD, self.minTD, 3 )
+
+        co.cv.cvClearMemStorage( self.storage )
+
+        seq = co.cv.cvSegmentMotion( self.mhi, self.segmask, self.storage, timestamp, self.maxTD )
+
+        for i in range(0, seq.total):
+            if i < 0:  # case of the whole image
+                continue
+            else:  # i-th motion component
+                # Movement Rectangle
+                mRect = seq[i].rect
+
+                # reject very small components
+                if( mRect.width + mRect.height < 30 ):
+                    continue
+
+            center = co.cv.cvPoint( (mRect.x + mRect.width/2), (mRect.y + mRect.height/2) )
+
+            silhRoi = co.cv.cvGetSubRect(silh, mRect)
+            count = co.cv.cvNorm( silhRoi, None, co.cv.CV_L1, None )
+
+             # calculate number of points within silhouette ROI
+            if( count < mRect.width * mRect.height * 0.05 ):
+                continue
+
+            mv.append(center)
+
+        return mv
diff --git a/src/ocvfw/backends/__init__.py b/src/ocvfw/backends/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/ocvfw/idm/color.py b/src/ocvfw/idm/color.py
new file mode 100644
index 0000000..85c0fe3
--- /dev/null
+++ b/src/ocvfw/idm/color.py
@@ -0,0 +1,525 @@
+# -*- coding: utf-8 -*-
+
+# Ocvfw
+#
+# Copyright 2009 Flavio Percoco Premoli
+#
+# This file is part of Ocvfw.
+#
+# Ocvfw is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License v2 as published
+# by the Free Software Foundation.
+#
+# Ocvfw is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ocvfw.  If not, see <http://www.gnu.org/licenses/>>.
+
+
+"""Color IDM"""
+
+__id__        = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2008 Flavio Percoco Premoli"
+__license__   = "GPLv2"
+
+import ocvfw.commons as co
+from ocvfw.dev.camera import Camera, Capture, Point
+from ctypes import c_int 
+""" Using ctypes-opencv, instead of the python bindings provided by OpenCV. """
+from sys import argv, exit
+import math
+
+# IDM's Information
+# a_name: IDM's name
+#   This is used by the settings gui to identify the idm
+# a_description: IDM's Description
+# a_settings: Possible settings needed by the idm. For Example: { 'var_name' : { 'value' : default_value}, 'var_name2' : { 'value' : default_value} }  These settings are loaded from usrSettings.cfg in /home/username/.mousetrap.
+a_name = "color"
+a_description = "Color tracker using CAMshift algorithm"
+a_settings = {"hrange": {"value": 15}, "vscale": {"value": 10}, "selection_size": {"value": 30}}
+
+class Module(object):
+    """
+    This is the IDM's Main class, called by mousetrap.py in the load process.
+    """
+
+    def __init__(self, controller, stgs = {}):
+        """
+        IDM's init function.
+        
+        Arguments:
+        - self: The main object pointer.
+        - controller: mousetrap main class pointer. This is passed by MouseTrap's controller (mousetrap.py) when loaded.
+        - stgs: Possible settings loaded from the user's settings file. If there aren't settings the IDM will use the a_settings dict.
+        """
+        
+
+        # Controller instance
+        self.ctr          = controller
+        
+        self.cfg = self.ctr.cfg
+
+        if not self.cfg.has_section("color"):
+            self.cfg.add_section("color")
+        # Capture instance
+        # The capture is the object containing the image 
+        # and all the possible methods to modify it.
+        self.cap          = None
+        
+        # IDM's Settings dict
+        self.stgs         = stgs
+
+        # Prepares the IDM using the settings.
+        self.prepare_config()
+
+        #TODO: ADD CONDITIONAL TO ENSURE SETTINGS ARE SET EVEN IF YOU HAVE AN OLD CONFIG FILE
+
+        # Initialization of variables needed for color tracking CAMshift algorithm.
+
+        self.image = None
+        self.hsv = None
+
+        self.first_time=True # To keep track of whether or not we have initalized image objects
+
+        self.select_object = 0
+        self.track_object = 0
+        self.origin = None #needed?
+        self.selection = None
+        self.track_window = None
+        self.track_box = None
+        self.track_comp = None
+        self.hdims = 16 #Number of columns in the histogram
+
+        # Variables to control the ranges for the color mask.
+        self.vmin = c_int(10)   # Value
+        self.vmax = c_int(256)
+        self.smin = c_int(80)   # Saturation
+        self.smax = c_int(256)
+        self.hmin = c_int(0)    # Hue
+        self.hmax = c_int(180)  # out of 180, not 256
+
+
+    def prepare_config(self):
+        """
+        Prepares the IDM using the settings
+        
+        Arguments:
+        - self: The main object pointer
+        """
+        global a_settings
+        
+        self.debugLevel = self.ctr.cfg.getint("main", "debugLevel")
+        print self.debugLevel        
+
+        # If the dict is empty then 
+        # use the default settings defined in a_settings
+        if not self.stgs:
+            self.stgs = a_settings
+
+        # For each key do something if required by the module
+        for key in self.stgs:
+            pass
+
+    def hsv2rgb(self, hue):
+        """
+        Converts an HSV hue to RGB.
+        
+        Arguments:
+        - self: The main object pointer
+        - hue: the hue to convert to RGB.
+        """
+        rgb=[0,0,0]
+        
+        sector_data= ((0,2,1), (1,2,0), (1,0,2), (2,0,1), (2,1,0), (0,1,2))
+        hue *= 0.033333333333333333333333333333333
+        sector = co.cv.cvFloor(hue)
+        p = co.cv.cvRound(255*(hue - sector))
+        p ^= 255 if bool(sector & 1) else 0
+
+        rgb[sector_data[sector][0]] = 255
+        rgb[sector_data[sector][1]] = 0
+        rgb[sector_data[sector][2]] = p
+
+        return co.cv.cvScalar(rgb[2], rgb[1], rgb[0], 0)
+
+    def set_capture(self, cam):
+        """
+        Initialize the capture and sets the main settings.
+        
+        Arguments:
+        - self: The main object pointer
+        - cam: The camera device index. For Example: 0 = /dev/video0, 1 = /dev/video1
+        """
+        
+        # Starts the Capture using the async method.
+        # This means that self.cap.sync() wont be called periodically
+        # by the idm because the Capture syncs the image asynchronously (See dev/camera.py)
+        self.cap = Capture(async=False, idx=cam, backend="OcvfwCtypes")
+        
+        #for some reason this is necessary! why?!?
+
+        co.hg.cvNamedWindow( "Histogram", 1 )
+
+        if self.debugLevel >= 30:
+            co.hg.cvNamedWindow( "Mask", 1 )
+
+
+            co.hg.cvCreateTrackbar( "Vmin", "Mask", self.vmin, 256 )
+            co.hg.cvCreateTrackbar( "Vmax", "Mask", self.vmax, 256 )
+            co.hg.cvCreateTrackbar( "Smin", "Mask", self.smin, 256 )
+            co.hg.cvCreateTrackbar( "Smax", "Mask", self.smax, 256 )
+            co.hg.cvCreateTrackbar( "Hmin", "Mask", self.hmin, 180 )
+            co.hg.cvCreateTrackbar( "Hmax", "Mask", self.hmax, 180 )
+
+        # This sets the final image default color to rgb. The default color is bgr.
+        self.cap.change(color="rgb")
+        self.cap.set_camera("lk_swap", True)
+
+    def _convertColorDepth(self, color):
+        """
+        Converts from 16 to 8 bit color depth. Necessary
+        for OpenCV functions and GDK colors to interact as the
+        former expects colors from 0-255 and the latter expects
+        0-65535.
+        
+        Arguments:
+        - self: The main object pointer
+        - color: The integer color value to convert to 0-255
+        """
+        return int((color / 65535.0) * 255)
+
+    def rgb2hue(self, red, green, blue):
+        """
+        Converts the rgb values from the config file into the corresponding hue value.
+        This method was stolen from the gtk source!
+        """
+
+        hue = 0.0
+          
+        if (red > green):
+            if (red > blue):
+                cmax = red
+            else:
+                cmax = blue
+            
+            if (green < blue):
+                cmin = green
+            else:
+                cmin = blue;
+        else:
+            if (green > blue):
+                cmax = green
+            else:
+                cmax = blue
+           
+            if (red < blue):
+                cmin = red
+            else:
+                cmin = blue
+        
+        val = cmax
+        
+        if (cmax != 0.0):
+            sat = (cmax - cmin) / cmax
+        else:
+            sat = 0.0
+        
+        if (sat == 0.0):
+            hue = 0.0
+        else:
+            delta = cmax - cmin
+            
+            if (red == cmax):
+                hue = (green - blue) / delta
+            elif (green == cmax):
+                hue = 2 + (blue - red) / delta
+            elif (blue == cmax):
+                hue = 4 + (red - green) / delta
+            
+            hue /= 6.0;
+            
+            if (hue < 0.0):
+                hue += 1.0
+            elif (hue > 1.0):
+                hue -= 1.0
+
+        return (hue * 360) / 2
+
+    def update_hue_range(self, *args):
+        """
+        WARNING: HACK by Ryan
+        This method is used as a callback connected to the color picker
+        save button's click event. I had to do this because we need to update
+        the hue min/max in this idm whenever the user saves a new color.
+        However, we can't poll a file's status to see if it's changed, so
+        we routed the event to two callbacks.
+        
+        Suggestion: Maybe use a dictionary for configure settings and
+        serialize it on quit. This would trivialize querying a settings
+        structure and allow us comparatively free use of the data. Right now
+        we're forced to keep in mind how often we query settings because
+        hard drives are SLOW.
+        """
+
+        temphue = self.rgb2hue(float(self.cfg.get("color", "red")), float(self.cfg.get("color", "green")), float(self.cfg.get("color", "blue")))
+        hrange = int(self.cfg.get("color","hrange")) / 2
+        self.hmin.value = int(max(temphue - hrange, 0))
+        self.hmax.value = int(min(temphue + hrange, 180))
+
+    def histogram_init(self):
+        """
+        Initializes and displays a color histogram of the selected area
+
+        Arguments:
+        - self: The main object pointer
+        """
+
+        co.cv.cvCalcHist( [self.hue], self.hist, 0, self.mask )
+        min_val, max_val = co.cv.cvGetMinMaxHistValue(self.hist)
+        hbins = self.hist.bins[0]
+        co.cv.cvConvertScale( hbins, hbins, 255. / max_val if max_val else 0., 0 )
+        co.cv.cvZero( self.histimg )
+        bin_w = self.histimg.width / self.hdims
+        for i in xrange(self.hdims):
+            val = co.cv.cvRound( co.cv.cvGetReal1D(hbins,i)*self.histimg.height/255 )
+            color = self.hsv2rgb(i*180./self.hdims)
            co.cv.cvRectangle( self.histimg, co.cv.cvPoint(i*bin_w,self.histimg.height),
+                             co.cv.cvPoint((i+1)*bin_w,self.histimg.height - val),
+                             color, -1, 8, 0 )
+        if self.debugLevel >= 30:
+            co.hg.cvShowImage( "Histogram", self.histimg )
+
+    def get_capture(self):
+        """
+        Gets the last queried and formated image.
+        Function used by the mousetrap/ui/main.py 
+        to get the output image
+
+        Arguments:
+        - self: The main object pointer
+
+        returns self.cap.resize(200, 160, True)
+        """
+        
+        
+        
+        # Called to update image with latest frame from webcam
+        self.cap.sync()
+
+        #self.image = self.cap.image().origin needed??
+        self.image = self.cap.image()
+
+        
+        if self.first_time:
+            # Initialization of images.  Only needs to happen once.
+
+            # TODO: What is a better way to get the image size?
+            self.hue = co.cv.cvCreateImage( co.cv.cvGetSize(self.image), 8, 1 )
+            self.mask = co.cv.cvCreateImage(  co.cv.cvGetSize(self.image), 8, 1 )
+            self.backproject = co.cv.cvCreateImage(  co.cv.cvGetSize(self.image), 8, 1 )
+            self.hist = co.cv.cvCreateHist( [self.hdims], co.cv.CV_HIST_ARRAY, [[0, 180]] )
+            self.histimg = co.cv.cvCreateImage( co.cv.cvSize(320,200), 8, 3 )
+            self.temp = co.cv.cvCreateImage(  co.cv.cvGetSize(self.image), 8, 3) #needed?
+            co.cv.cvZero( self.histimg )
+
+            #Initialization of hue range from config file.
+            temphue = self.rgb2hue(float(self.cfg.get("color", "red")), float(self.cfg.get("color", "green")), float(self.cfg.get("color", "blue")))
+            hrange = int(self.cfg.get("color","hrange")) / 2
+            self.hmin.value = int(max(temphue - hrange, 0))
+            self.hmax.value = int(min(temphue + hrange, 180))
+
+
+            #Creates object selection box
+            self.origin = co.cv.cvPoint(self.image.width / 2, self.image.height / 2)
+            self.selection = co.cv.cvRect(self.origin.x-50,self.origin.y-50,100,100)
+
+            self.first_time=False
+
+        self.hsv = self.cap.color("hsv", channel=3, copy=True) # Convert to HSV
+
+        # If tracking
+        if self.track_object != 0:
+
+            #Masks pixels that fall outside desired range
+            scalar1=co.cv.cvScalar(self.hmin.value,self.smin.value,min(self.vmin.value,self.vmax.value),0)
+            scalar2=co.cv.cvScalar(self.hmax.value,self.smax.value,max(self.vmin.value,self.vmax.value),0)       
+            co.cv.cvInRangeS( self.hsv, scalar1, scalar2, self.mask )
+
+            co.cv.cvSplit(self.hsv, self.hue)
+
+            # If tracking, first time
+            if self.track_object < 0:
+                co.cv.cvSetImageROI( self.hue, self.selection) 
+                co.cv.cvSetImageROI( self.mask, self.selection)
+
+                self.histogram_init()
+
+                co.cv.cvResetImageROI( self.hue )
+                co.cv.cvResetImageROI( self.mask )
+                self.track_window = self.selection
+                self.track_object = 1
+            co.cv.cvCalcBackProject( [self.hue], self.backproject, self.hist )
+            co.cv.cvAnd(self.backproject, self.mask, self.backproject)
+
+            #CamShift algorithm is called
+            niter, self.track_comp, self.track_box = co.cv.cvCamShift( self.backproject, self.track_window,
+                        co.cv.cvTermCriteria( co.cv.CV_TERMCRIT_EPS | co.cv.CV_TERMCRIT_ITER, 10, 1 ))
+            self.track_window = self.track_comp.rect
+            
+            if not self.origin:
+                self.track_box.angle = -self.track_box.angle
+
+            # Ensures that track_box size is always at least 0x0
+            if math.isnan(self.track_box.size.height): 
+                self.track_box.size.height = 0
+            if math.isnan(self.track_box.size.width): 
+                self.track_box.size.width = 0
+
+            #Creates the ellipse around the tracked object
+            co.cv.cvEllipseBox( self.image, self.track_box, co.cv.CV_RGB(0,255,0), 3, co.cv.CV_AA, 0 )
+
+            #Updates cursor location information
+            if (not hasattr(self.cap, "obj_center")):
+                self.cap.add(Point("point", "obj_center", ( int(self.track_box.center.x), int(self.track_box.center.y )), parent=self.cap, follow=False))
+            else:
+                self.cap.obj_center.set_opencv(co.cv.cvPoint(int(self.track_box.center.x), int(self.track_box.center.y)))
+
+        #Displays selection box before tracking starts
+        if not self.track_object:
+            co.cv.cvSetImageROI( self.image, self.selection )
+            co.cv.cvXorS( self.image, co.cv.cvScalarAll(255), self.image )
+            co.cv.cvResetImageROI( self.image )
+        
+        if self.debugLevel >= 30:
+            co.hg.cvShowImage( "Mask", self.mask)
+        
+        self.cap.color("rgb", channel=3, copy=True)
+
+        # Calls the resize method passing the new with, height
+        # specifying that the new image has to be a copy of the original
+        # so, self.cap.resize will copy the original instead of modifying it.
+        return self.cap
+
+    def startTracking(self):
+        """
+        Starts the tracking algorithm. This exists because
+        we set up keyboard input in the main view to start
+        and stop tracking. Maybe generalize this functionality
+        to all idms?
+        
+        Arguments:
+        - self: The main object pointer
+        
+        Raises:
+        - ValueError: If either the selection height or width are less
+        than or equal to zero.
+        """
+        if (self.selection.width and self.selection.height <= 0):
+            raise ValueError()
+        
+        self.track_object = -1
+    
+    def stopTracking(self):
+        """
+        Stops the tracking algorithm. This exists because
+        we set up keyboard input in the main view to start
+        and stop tracking. Maybe generalize this functionality
+        to all idms?
+        
+        Arguments:
+        - self: The main object pointer
+        """
+        
+        self.track_object = 0
+
+    def selSizeUp(self):
+        """
+        Increases the size of the selection window.
+
+        Arguments:
+        - self: The main object pointer
+        """
+        if 6 <= self.selection.x <=self.image.width-self.selection.width-6 and 6 <= self.selection.y <= self.image.height-self.selection.height-6:
+            self.selection = co.cv.cvRect(self.selection.x-5,self.selection.y-5,self.selection.width+10,self.selection.height+10)
+
+    def selSizeDown(self):
+        """
+        Decreases the size of the selection window.
+
+        Arguments:
+        - self: The main object pointer
+        """
+
+        if self.selection.width > 10 and self.selection.height > 10:
+            self.selection = co.cv.cvRect(self.selection.x+5,self.selection.y+5,self.selection.width-10,self.selection.height-10)
+    
+    def selPositionLeft(self):
+        """
+        Changes the location of the selection window.
+
+        Arguments:
+        - self: The main object pointer
+        """
+
+        if 6 <= self.selection.x <= self.image.width: 
+            self.selection=co.cv.cvRect(self.selection.x-5,self.selection.y,self.selection.width,self.selection.height)
+
+
+    def selPositionRight(self):
+        """
+        Changes the location of the selection window.
+
+        Arguments:
+        - self: The main object pointer
+        """
+
+        if 0 <= self.selection.x <= self.image.width-self.selection.width-6:
+            self.selection=co.cv.cvRect(self.selection.x+5,self.selection.y,self.selection.width,self.selection.height)
+        
+
+    def selPositionUp(self):
+        """
+        Changes the location of the selection window.
+
+        Arguments:
+        - self: The main object pointer
+        """
+        if 6 <= self.selection.y <= self.image.height:
+            self.selection=co.cv.cvRect(self.selection.x,self.selection.y-5,self.selection.width,self.selection.height)
+
+    def selPositionDown(self):
+        """
+        Changes the location of the selection window.
+
+        Arguments:
+        - self: The main object pointer
+        """
+        if 0 <= self.selection.y <= self.image.height-self.selection.height-6:
+            self.selection=co.cv.cvRect(self.selection.x,self.selection.y+5,self.selection.width,self.selection.height)
+    
+        
+    def get_pointer(self):
+        """
+        Returns the new MousePosition.
+        Function used to pass the Mouse Pointer position
+        to the Scripts.
+
+        Arguments:
+        - self: The main object pointer
+        """
+
+        # The return value has to be a Point() type object
+        # Following the forehad IDM, The return is self.cap.obj_center
+        # which is created in the get_image function as an attribute
+        # of self.cap
+
+        if hasattr(self.cap, "obj_center"):
+            return self.cap.obj_center
+        else:
+            pass
+
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]