def createWeights(ftb, ctb, project, featureThreshold, imagesOnly):
    # Build the classifier (basically a set of weights)
    message = ''
    trainFts = wndcharm.FeatureSet.FeatureSet_Discrete()

    classId = 0
    for ds in project.listChildren():
        message += 'Processing dataset id:%d\n' % ds.getId()
        message += addToFeatureSet(ftb, ds, trainFts, classId, imagesOnly)
        classId += 1

    tmp = trainFts.ContiguousDataMatrix()
    weights = wndcharm.FeatureSet.FisherFeatureWeights.NewFromFeatureSet(trainFts)

    if featureThreshold < 1.0:
        nFeatures = ceil(len(weights.names) * featureThreshold)
        message += 'Selecting top %d features\n' % nFeatures
        weights = weights.Threshold(nFeatures)
        trainFts = reduceFeatures(trainFts, weights)

    version = trainFts.feature_vector_version

    # Save the features, weights and classes to tables
    # TODO:Delete existing tables
    #if getProjectTableFile(tcOutF, tcF.tableName, proj):
    ctb.createClassifierTables(weights.names, version)
    message += 'Created classifier tables ids: %d %d %d version:%s\n' % (
        ctb.tcF.tableId, ctb.tcW.tableId, ctb.tcL.tableId, version)

    # We've (ab)used imagenames_list to hold the image ids
    ids = [long(a) for b in trainFts.imagenames_list for a in b]
    classIds = [a for b in [[i] * len(z) for i, z in izip(xrange(
                    len(trainFts.imagenames_list)), trainFts.imagenames_list)]
                for a in b]
    featureMatrix = trainFts.data_matrix
    featureNames = weights.names
    featureWeights = weights.values
    classNames = trainFts.classnames_list

    ctb.saveClassifierTables(ids, classIds, featureMatrix,
                             featureNames, featureWeights, classNames)

    WndcharmStorage.addFileAnnotationTo(ctb.tcF, project)
    WndcharmStorage.addFileAnnotationTo(ctb.tcW, project)
    WndcharmStorage.addFileAnnotationTo(ctb.tcL, project)

    message += 'Saved classifier\n'

    classifierName = WndcharmStorage.CLASSIFIER_WNDCHARM_NAMESPACE
    ns = WndcharmStorage.createClassifierTagSet(
        ctb.tcL.conn, classifierName, project.getName(), classNames, project)
    message += 'Created tagset: %s\n' % ns

    return trainFts, weights, message
def extractFeatures(ftb, ds, newOnly, chNames, imageId = None, im = None):
    message = ''
    tc = ftb.tc

    # dataset must be explicitly provided because an image can be linked to
    # multiple datasets in which case im.getDataset() doesn't work
    if not im:
        if not imageId:
            #raise Exception('No input image')
            raise omero.ServerError('No input image')

        im = ftb.conn.getObject('Image', imageId)
        if not im:
            return 'Image id:%d not found\n' % imageId
    else:
        imageId = im.getId()

    tid = WndcharmStorage.getAttachedTableFile(ftb.tc, ds)
    if tid:
        if not ftb.openTable(tid):
            return message + '\nERROR: Table not opened\n'
        version = unwrap(ftb.versiontag.getTextValue())
        # version seems to be in unicode
        message += 'Opened table id:%d version:%s\n' % (tid, str(version))

        if newOnly and ftb.tableContainsId(imageId):
            return message + 'Image id:%d features already in table' % imageId

    # FIXME: default is convert multichannel to greyscale unless user input

    # Calculate features for an image channel
    # Optionally prepend the channel label to each feature name and combine
    ftall = None
    for c in xrange( len( chNames ) ):
	    
        wndcharm_matrix = PyImageMatrix()
        wndcharm_matrix.allocate( im.getSizeX(), im.getSizeY() )
        numpy_matrix = wndcharm_matrix.as_ndarray()

        numpy_matrix[:] = im.getPrimaryPixels().getPlane(theZ=0,theC=c,theT=0)
        feature_plan = wndcharm.StdFeatureComputationPlans.getFeatureSet();
        options = "" # This is where you can tell wnd-charm to normalize pixel intensities, 
                     # take ROIs etc. ... leave blank for now.
        ft = Signatures.NewFromFeatureComputationPlan( wndcharm_matrix, feature_plan, options )

        ft.names = [WndcharmStorage.insert_channel_name(
                    n, chNames[c]) for n in ft.names]
        ft.source_path = im.getName()
        if not ftall:
            ftall = ft
        else:
            ftall.names += ft.names
            ftall.values += ft.values

    # Save the features to a table
    if not tid:
        ftb.createTable(ftall.names, ft.version)
        version = unwrap(ftb.versiontag.getTextValue())
        message += 'Created new table id:%d version:%s\n' % (
            ftb.tc.tableId, version)
        message += WndcharmStorage.addFileAnnotationTo(tc, ds)

    if version != ft.version:
        return message + 'Incompatible version: Stored=%s Calculated=%s' % (
            version, ft.version)
    ftb.saveFeatures(imageId, ftall)

    return message + 'Extracted features from Image id:%d\n' % imageId