Source code for pysteg.sql.scaling

#! /usr/bin/env python
## -*- coding: utf-8 -*-
## (C) 2012: Hans Georg Schaathun <georg@schaathun.net> 

"""
This module defines a scaling model, to scale features prior to 
classification.  It is used by the SVModel class, but is designed
with loose coupling to facilitate reuse with other classification
algorithms.

The ScaleModel class implements some of the interface of FeatureVector
and can be used in lieu thereof when getting feature values from
images.

The implementation is slow.  Each feature value depends on three
tables and three records are queried separately from Feature,
FeatureValue, and Scaling.  Combining the three in one view 
to be queried in one operation is expected to be faster.

This module will auto-connect to the database and must be loaded
after options have been processed, to ensure correct connection.
The reason for this is that it depends on views defined server side.
"""

print "[pysteg.sql.scaling]"

from sqlobject import *
from sqlobject.views import *
from . import *
from .aux import isDuplicateError
import numpy as np

sqlConnect()

[docs]class ScaleModel(SQLObject): """This is a complete scaling model, with scaling formulæ for each feature. It implements part of the interface of FeatureVector and can be passed to the :meth:`getFeatures` methods of Image, ImageSet, and TestSet to return complete scaled feature vectors with canonical coordinate ordering.""" testset = ForeignKey( "TestSet" ) scales = SQLMultipleJoin( "Scaling", joinColumn="model_id" ) dim = IntCol( default=None ) def __iter__( self ): return self.scales.orderBy( "feature_id" ).__iter__() def theFeatures( self, image, verbosity=3 ): if verbosity > 2: print "[ScaleModel.theFeatures]", self.id print image fv = list(ScaledFeatureValue.getFeatures( scalemodel=self,image=image,verbosity=verbosity)) N = len(fv) if N < self.getDim(): if verbosity > 1: print "[ScaleModel.theFeatures] Missing data (%s/%s)." % ( N, self.getDim()) print image print self raise MissingDataException elif N > self.getDim(): raise Exception, "Too many feature values retrieved." return fv
[docs] def destroy(self,values=False): "Delete the model from the data base." for s in self.scales: s.destroySelf() print "[destroy]", self self.destroySelf()
[docs] def getDim(self): "Return the feature space dimensionality." if self.dim == None: self.dim = self.scales.count() return self.dim
@classmethod def calc( cls, fv, testset, verbosity=0 ): S = cls( testset=testset ) S.calculate( fv, testset, verbosity=verbosity ) return S def calculate( self, fv, testset, verbosity=0 ): if self.dim == None: self.dim = 0 for f in fv: (factor,addterm) = calcScale( testset, f, verbosity=verbosity ) try: Scaling( model=self, feature=f, factor=factor, addterm=addterm ) self.dim += 1 except StandardError as e: if not isDuplicateError(e): print "[Scaling] Unknown error." raise S = Scaling.selectBy( svmodel=self, feature=f ) if verbosity > 0: print "[Scaling] Record already exists." print S S.factor = factor S.addterm = addterm return
[docs]class Scaling(SQLObject): "The Scaling object holds the model to scale a particular feature." feature = ForeignKey( "Feature" ) model = ForeignKey( "ScaleModel", cascade=True ) idx = DatabaseIndex( 'model', 'feature', unique=True ) factor = FloatCol( default=1 ) addterm = FloatCol( default=0 )
def calcScale( tset, feature, verbosity=0 ): fv = tset.images.throughTo.features.filter( FeatureValue.q.feature == feature ) mn = fv.min("value") mx = fv.max("value") if mn == None or mx == None: if fv.count() == 0: if verbosity > 1: print "[calcScale] Missing data." raise MissingDataException, "Features have not been extracted." else: raise Exception, "Unknown error: min or max returns None." (lower, upper) = (-1,+1) range = upper - lower factor = range/(mx-mn) addterm = (mx+mn)/2 if verbosity > 2: print feature, (mn,mx) print feature, (factor,addterm) return (factor,addterm)
[docs]class ScaledFeatureValue(SQLObject): """This is an attempt to start on an object to fetch multiple SQL records in one operation to save time. NOT COMPLETE. """ class sqlmeta: fromDatabase = True columnList = True idName = "id" idType = str #key = StringCol() #value = FloatCol() #rawvalue = FloatCol() #addterm = FloatCol() #factor = FloatCol() #image = ForeignKey("Image") #scalemodel = ForeignKey("ScaleModel") @classmethod def getFeatures(cls,image,scalemodel,verbosity=0): try: iid = image.id except AttributeError: iid = image try: sid = scalemodel.id except AttributeError: sid = scalemodel if verbosity > 2: print "[ScaledFeatureValue.getFeatures]", iid, sid return cls.selectBy( imageID=iid, scalemodelID=sid ) def getFID(self): return self.fid def __cmp__(self,r): return cmp(self.getFID(),r.getFID())
[docs] def getValue(self): "Return the scaled feature value." return self.value