def findBlobs(images, masks, minArea=1, maxArea=-1): """ images and masks should contain SimpleCV images! """ maker = BlobMaker() # TODO: Automatically update the recursion limit! return [maker.extractFromBinary(m, i, minArea, maxArea) for m, i in zip(masks, images)]
class DiffSegmentation(SegmentationBase): """ This method will do image segmentation by looking at the difference between two frames. grayOnly - use only gray images. threshold - The value at which we consider the color difference to be significant enough to be foreground imagery. The general usage is >>> segmentor = DiffSegmentation() >>> cam = Camera() >>> while(1): >>> segmentor.addImage(cam.getImage()) >>> if(segmentor.isReady()): >>> img = segmentor.getSegmentedImage() """ mError = False mLastImg = None mCurrImg = None mDiffImg = None mColorImg = None mGrayOnlyMode = True mThreshold = 10 mBlobMaker = None def __init__(self, grayOnly=False, threshold=(10, 10, 10)): self.mGrayOnlyMode = grayOnly self.mThreshold = threshold self.mError = False self.mCurrImg = None self.mLastImg = None self.mDiffImg = None self.mColorImg = None self.mBlobMaker = BlobMaker() def addImage(self, img): """ Add a single image to the segmentation algorithm """ if (img is None): return if (self.mLastImg == None): if (self.mGrayOnlyMode): self.mLastImg = img.toGray() self.mDiffImg = Image(self.mLastImg.getEmpty(1)) self.mCurrImg = None else: self.mLastImg = img self.mDiffImg = Image(self.mLastImg.getEmpty(3)) self.mCurrImg = None else: if (self.mCurrImg is not None): #catch the first step self.mLastImg = self.mCurrImg if (self.mGrayOnlyMode): self.mColorImg = img self.mCurrImg = img.toGray() else: self.mColorImg = img self.mCurrImg = img cv.AbsDiff(self.mCurrImg.getBitmap(), self.mLastImg.getBitmap(), self.mDiffImg.getBitmap()) return def isReady(self): """ Returns true if the camera has a segmented image ready. """ if (self.mDiffImg is None): return False else: return True def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = False return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mCurrImg = None self.mLastImg = None self.mDiffImg = None def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self.mDiffImg def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ retVal = None if (whiteFG): retVal = self.mDiffImg.binarize(thresh=self.mThreshold) else: retVal = self.mDiffImg.binarize(thresh=self.mThreshold).invert() return retVal def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ retVal = [] if (self.mColorImg is not None and self.mDiffImg is not None): retVal = self.mBlobMaker.extractFromBinary( self.mDiffImg.binarize(thresh=self.mThreshold), self.mColorImg) return retVal def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None del mydict['mBlobMaker'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class MorphologyFeatureExtractor(FeatureExtractorBase): """ This feature extractor collects some basic morphology infromation about a given image. It is assumed that the object to be recognized is the largest object in the image. The user must provide a segmented white on black blob image. This operation then straightens the image and collects the data. """ mNBins = 12 mBlobMaker = None mThresholdOpeation = None def __init__(self, thresholdOperation=None): """ The threshold operation is a function of the form binaryimg = threshold(img) the simplest example would be: def binarize_wrap(img): """ self.mNBins = 12 self.mBlobMaker = BlobMaker() self.mThresholdOpeation = thresholdOperation def setThresholdOperation(self, threshOp): """ The threshold operation is a function of the form binaryimg = threshold(img) the simplest example would be: def binarize_wrap(img): return img.binarize() """ self.mThresholdOperation = threshOp def extract(self, img): """ This method takes in a image and returns some basic morphology characteristics about the largest blob in the image. The if a color image is provided the threshold operation is applied. """ retVal = None if(self.mThresholdOpeation is not None): bwImg = self.mThresholdOpeation(img) else: bwImg = img.binarize() if( self.mBlobMaker is None ): self.mBlobMaker = BlobMaker() fs = self.mBlobMaker.extractFromBinary(bwImg,img) if( fs is not None and len(fs) > 0 ): fs = fs.sortArea() retVal = [] retVal.append(fs[0].mArea/fs[0].mPerimeter) retVal.append(fs[0].mAspectRatio) retVal.append(fs[0].mHu[0]) retVal.append(fs[0].mHu[1]) retVal.append(fs[0].mHu[2]) retVal.append(fs[0].mHu[3]) retVal.append(fs[0].mHu[4]) retVal.append(fs[0].mHu[5]) retVal.append(fs[0].mHu[6]) return retVal def getFieldNames(self): """ This method gives the names of each field in the feature vector in the order in which they are returned. For example, 'xpos' or 'width' """ retVal = [] retVal.append('area over perim') retVal.append('AR') retVal.append('Hu0') retVal.append('Hu1') retVal.append('Hu2') retVal.append('Hu3') retVal.append('Hu4') retVal.append('Hu5') retVal.append('Hu6') return retVal def getNumFields(self): """ This method returns the total number of fields in the feature vector. """ return self.mNBins def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None del mydict['mBlobMaker'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class DiffSegmentation(SegmentationBase): """ This method will do image segmentation by looking at the difference between two frames. grayOnly - use only gray images. threshold - The value at which we consider the color difference to be significant enough to be foreground imagery. The general usage is >>> segmentor = DiffSegmentation() >>> cam = Camera() >>> while(1): >>> segmentor.addImage(cam.getImage()) >>> if(segmentor.isReady()): >>> img = segmentor.getSegmentedImage() """ mError = False mLastImg = None mCurrImg = None mDiffImg = None mColorImg = None mGrayOnlyMode = True mThreshold = 10 mBlobMaker = None def __init__(self, grayOnly=False, threshold = (10,10,10) ): self.mGrayOnlyMode = grayOnly self.mThreshold = threshold self.mError = False self.mCurrImg = None self.mLastImg = None self.mDiffImg = None self.mColorImg = None self.mBlobMaker = BlobMaker() def addImage(self, img): """ Add a single image to the segmentation algorithm """ if( img is None ): return if( self.mLastImg == None ): if( self.mGrayOnlyMode ): self.mLastImg = img.toGray() self.mDiffImg = Image(self.mLastImg.getEmpty(1)) self.mCurrImg = None else: self.mLastImg = img self.mDiffImg = Image(self.mLastImg.getEmpty(3)) self.mCurrImg = None else: if( self.mCurrImg is not None ): #catch the first step self.mLastImg = self.mCurrImg if( self.mGrayOnlyMode ): self.mColorImg = img self.mCurrImg = img.toGray() else: self.mColorImg = img self.mCurrImg = img self.mDiffImg = Image(cv2.absdiff(self.mCurrImg.getNumpy(), self.mLastImg.getNumpy())) return def isReady(self): """ Returns true if the camera has a segmented image ready. """ if( self.mDiffImg is None ): return False else: return True def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = False return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mCurrImg = None self.mLastImg = None self.mDiffImg = None def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self.mDiffImg def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ retVal = None if( whiteFG ): retVal = self.mDiffImg.binarize(thresh=self.mThreshold) else: retVal = self.mDiffImg.binarize(thresh=self.mThreshold).invert() return retVal def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ retVal = [] if( self.mColorImg is not None and self.mDiffImg is not None ): retVal = self.mBlobMaker.extractFromBinary(self.mDiffImg.binarize(thresh=self.mThreshold),self.mColorImg) return retVal def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None del mydict['mBlobMaker'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class ColorSegmentation(SegmentationBase): """ Perform color segmentation based on a color model or color provided. This class uses ColorModel.py to create a color model. """ mColorModel = [] mError = False mCurImg = [] mTruthImg = [] mBlobMaker = [] def __init__(self): self.mColorModel = ColorModel() self.mError = False self.mCurImg = Image() self.mTruthImg = Image() self.mBlobMaker = BlobMaker() def addImage(self, img): """ Add a single image to the segmentation algorithm """ self.mTruthImg = img self.mCurImg = self.mColorModel.threshold(img) return def isReady(self): """ Returns true if the camera has a segmented image ready. """ return True; def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = false return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mColorModel.reset() def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self.mCurImg def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ return self.mCurImg def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ return self.mBlobMaker.extractFromBinary(self.mCurImg,self.mTruthImg) # The following are class specific methods def addToModel(self, data): self.mColorModel.add(data) def subtractModel(self, data): self.mColorModel.remove(data) def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None del mydict['mBlobMaker'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class MorphologyFeatureExtractor(FeatureExtractorBase): """ This feature extractor collects some basic morphology infromation about a given image. It is assumed that the object to be recognized is the largest object in the image. The user must provide a segmented white on black blob image. This operation then straightens the image and collects the data. """ mNBins = 12 mBlobMaker = None mThresholdOpeation = None def __init__(self, thresholdOperation=None): """ The threshold operation is a function of the form binaryimg = threshold(img) the simplest example would be: def binarize_wrap(img): """ self.mNBins = 12 self.mBlobMaker = BlobMaker() self.mThresholdOpeation = thresholdOperation def setThresholdOperation(self, threshOp): """ The threshold operation is a function of the form binaryimg = threshold(img) the simplest example would be: def binarize_wrap(img): return img.binarize() """ self.mThresholdOperation = threshOp def extract(self, img): """ This method takes in a image and returns some basic morphology characteristics about the largest blob in the image. The if a color image is provided the threshold operation is applied. """ retVal = None if (self.mThresholdOpeation is not None): bwImg = self.mThresholdOpeation(img) else: bwImg = img.binarize() if (self.mBlobMaker is None): self.mBlobMaker = BlobMaker() fs = self.mBlobMaker.extractFromBinary(bwImg, img) if (fs is not None and len(fs) > 0): fs = fs.sortArea() retVal = [] retVal.append(fs[0].mArea / fs[0].mPerimeter) retVal.append(fs[0].mAspectRatio) retVal.append(fs[0].mHu[0]) retVal.append(fs[0].mHu[1]) retVal.append(fs[0].mHu[2]) retVal.append(fs[0].mHu[3]) retVal.append(fs[0].mHu[4]) retVal.append(fs[0].mHu[5]) retVal.append(fs[0].mHu[6]) return retVal def getFieldNames(self): """ This method gives the names of each field in the feature vector in the order in which they are returned. For example, 'xpos' or 'width' """ retVal = [] retVal.append('area over perim') retVal.append('AR') retVal.append('Hu0') retVal.append('Hu1') retVal.append('Hu2') retVal.append('Hu3') retVal.append('Hu4') retVal.append('Hu5') retVal.append('Hu6') return retVal def getNumFields(self): """ This method returns the total number of fields in the feature vector. """ return self.mNBins def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None del mydict['mBlobMaker'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class ColorSegmentation(SegmentationBase): """ Perform color segmentation based on a color model or color provided. This class uses ColorModel.py to create a color model. """ mColorModel = [] mError = False mCurImg = [] mTruthImg = [] mBlobMaker = [] def __init__(self): self.mColorModel = ColorModel() self.mError = False self.mCurImg = Image() self.mTruthImg = Image() self.mBlobMaker = BlobMaker() def addImage(self, img): """ Add a single image to the segmentation algorithm """ self.mTruthImg = img self.mCurImg = self.mColorModel.threshold(img) return def isReady(self): """ Returns true if the camera has a segmented image ready. """ return True def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = false return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mColorModel.reset() def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self.mCurImg def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ return self.mCurImg def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ return self.mBlobMaker.extractFromBinary(self.mCurImg, self.mTruthImg) # The following are class specific methods def addToModel(self, data): self.mColorModel.add(data) def subtractModel(self, data): self.mColorModel.remove(data) def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None del mydict['mBlobMaker'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class MOGSegmentation(SegmentationBase): """ Background subtraction using mixture of gausians. For each pixel store a set of gaussian distributions and try to fit new pixels into those distributions. One of the distributions will represent the background. history - length of the pixel history to be stored nMixtures - number of gaussian distributions to be stored per pixel backgroundRatio - chance of a pixel being included into the background model noiseSigma - noise amount learning rate - higher learning rate means the system will adapt faster to new backgrounds """ mError = False mDiffImg = None mColorImg = None mReady = False # OpenCV default parameters history = 200 nMixtures = 5 backgroundRatio = 0.7 noiseSigma = 15 learningRate = 0.7 bsMOG = None def __init__(self, history = 200, nMixtures = 5, backgroundRatio = 0.7, noiseSigma = 15, learningRate = 0.7): try: import cv2 except ImportError: raise ImportError("Cannot load OpenCV library which is required by SimpleCV") return if not hasattr(cv2, 'BackgroundSubtractorMOG'): raise ImportError("A newer version of OpenCV is needed") return self.mError = False self.mReady = False self.mDiffImg = None self.mColorImg = None self.mBlobMaker = BlobMaker() self.history = history self.nMixtures = nMixtures self.backgroundRatio = backgroundRatio self.noiseSigma = noiseSigma self.learningRate = learningRate self.mBSMOG = cv2.BackgroundSubtractorMOG(history, nMixtures, backgroundRatio, noiseSigma) def addImage(self, img): """ Add a single image to the segmentation algorithm """ if( img is None ): return self.mColorImg = img self.mDiffImg = Image(self.mBSMOG.apply(img.getNumpyCv2(), None, self.learningRate), cv2image=True) self.mReady = True return def isReady(self): """ Returns true if the camera has a segmented image ready. """ return self.mReady def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = false return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mModelImg = None self.mDiffImg = None def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self.mDiffImg def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ return self.mDiffImg def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ retVal = [] if( self.mColorImg is not None and self.mDiffImg is not None ): retVal = self.mBlobMaker.extractFromBinary(self.mDiffImg ,self.mColorImg) return retVal def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None self.mDiffImg = None del mydict['mBlobMaker'] del mydict['mDiffImg'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class RunningSegmentation(SegmentationBase): """ RunningSegmentation performs segmentation using a running background model. This model uses an accumulator which performs a running average of previous frames where: accumulator = ((1-alpha)input_image)+((alpha)accumulator) """ mError = False mAlpha = 0.1 mThresh = 10 mModelImg = None mDiffImg = None mCurrImg = None mBlobMaker = None mGrayOnly = True mReady = False def __init__(self, alpha=0.7, thresh=(20,20,20)): """ Create an running background difference. alpha - the update weighting where: accumulator = ((1-alpha)input_image)+((alpha)accumulator) threshold - the foreground background difference threshold. """ self.mError = False self.mReady = False self.mAlpha = alpha self.mThresh = thresh self.mModelImg = None self.mDiffImg = None self.mColorImg = None self.mBlobMaker = BlobMaker() def addImage(self, img): """ Add a single image to the segmentation algorithm """ if( img is None ): return self.mColorImg = img if( self.mModelImg == None ): self.mModelImg = Image(cv.CreateImage((img.width,img.height), cv.IPL_DEPTH_32F, 3)) self.mDiffImg = Image(cv.CreateImage((img.width,img.height), cv.IPL_DEPTH_32F, 3)) else: # do the difference cv.AbsDiff(self.mModelImg.getBitmap(),img.getFPMatrix(),self.mDiffImg.getBitmap()) #update the model cv.RunningAvg(img.getFPMatrix(),self.mModelImg.getBitmap(),self.mAlpha) self.mReady = True return def isReady(self): """ Returns true if the camera has a segmented image ready. """ return self.mReady def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = false return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mModelImg = None self.mDiffImg = None def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self._floatToInt(self.mDiffImg) def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ retVal = None img = self._floatToInt(self.mDiffImg) if( whiteFG ): retVal = img.binarize(thresh=self.mThresh) else: retVal = img.binarize(thresh=self.mThresh).invert() return retVal def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ retVal = [] if( self.mColorImg is not None and self.mDiffImg is not None ): eightBit = self._floatToInt(self.mDiffImg) retVal = self.mBlobMaker.extractFromBinary(eightBit.binarize(thresh=self.mThresh),self.mColorImg) return retVal def _floatToInt(self,input): """ convert a 32bit floating point cv array to an int array """ temp = cv.CreateImage((input.width,input.height), cv.IPL_DEPTH_8U, 3) cv.Convert(input.getBitmap(),temp) return Image(temp) def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None self.mModelImg = None self.mDiffImg = None del mydict['mBlobMaker'] del mydict['mModelImg'] del mydict['mDiffImg'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()
class RunningSegmentation(SegmentationBase): """ RunningSegmentation performs segmentation using a running background model. This model uses an accumulator which performs a running average of previous frames where: accumulator = ((1-alpha)input_image)+((alpha)accumulator) """ mError = False mAlpha = 0.1 mThresh = 10 mModelImg = None mDiffImg = None mCurrImg = None mBlobMaker = None mGrayOnly = True mReady = False def __init__(self, alpha=0.7, thresh=(20,20,20)): """ Create an running background difference. alpha - the update weighting where: accumulator = ((1-alpha)input_image)+((alpha)accumulator) threshold - the foreground background difference threshold. """ self.mError = False self.mReady = False self.mAlpha = alpha self.mThresh = thresh self.mModelImg = None self.mDiffImg = None self.mColorImg = None self.mBlobMaker = BlobMaker() def addImage(self, img): """ Add a single image to the segmentation algorithm """ if( img is None ): return self.mColorImg = img if( self.mModelImg == None ): self.mModelImg = Image(np.zeros((img.height, img.width, 3)).astype(np.float32)) self.mDiffImg = Image(np.zeros((img.height, img.width, 3)).astype(np.float32)) else: # do the difference self.mDiffImg = Image(cv2.absdiff(self.mModelImg.getNumpy(), self.mDiffImg.getNumpy())) #update the model npimg = np.zeros((img.height, img.width, 3)).astype(np.float32) npimg = self.mModelImg.getFPNumpy() cv2.accumulateWeighted(img.getFPNumpy(), npimg, self.mAlpha) print npimg self.mModelImg = Image(npimg) #cv.RunningAvg(img.getFPMatrix(),self.mModelImg.getBitmap(),self.mAlpha) self.mReady = True return def isReady(self): """ Returns true if the camera has a segmented image ready. """ return self.mReady def isError(self): """ Returns true if the segmentation system has detected an error. Eventually we'll consruct a syntax of errors so this becomes more expressive """ return self.mError #need to make a generic error checker def resetError(self): """ Clear the previous error. """ self.mError = false return def reset(self): """ Perform a reset of the segmentation systems underlying data. """ self.mModelImg = None self.mDiffImg = None def getRawImage(self): """ Return the segmented image with white representing the foreground and black the background. """ return self._floatToInt(self.mDiffImg) def getSegmentedImage(self, whiteFG=True): """ Return the segmented image with white representing the foreground and black the background. """ retVal = None img = self._floatToInt(self.mDiffImg) if( whiteFG ): retVal = img.binarize(thresh=self.mThresh) else: retVal = img.binarize(thresh=self.mThresh).invert() return retVal def getSegmentedBlobs(self): """ return the segmented blobs from the fg/bg image """ retVal = [] if( self.mColorImg is not None and self.mDiffImg is not None ): eightBit = self._floatToInt(self.mDiffImg) retVal = self.mBlobMaker.extractFromBinary(eightBit.binarize(thresh=self.mThresh),self.mColorImg) return retVal def _floatToInt(self,inputimg): """ convert a 32bit floating point cv array to an int array """ temp = inputimg.getNumpy() temp = temp * 255.0 temp = temp.astype(np.uint8) #temp = cv.CreateImage((input.width,input.height), cv.IPL_DEPTH_8U, 3) #cv.Convert(input.getBitmap(),temp) return Image(temp) def __getstate__(self): mydict = self.__dict__.copy() self.mBlobMaker = None self.mModelImg = None self.mDiffImg = None del mydict['mBlobMaker'] del mydict['mModelImg'] del mydict['mDiffImg'] return mydict def __setstate__(self, mydict): self.__dict__ = mydict self.mBlobMaker = BlobMaker()