home Forums # Technical Support Fuzzy system for image segmentation slow Reply To: Fuzzy system for image segmentation slow

#1888
Unknown
Member

Thank you for your answer. I effectively use FL 5.0, compiled with C++11.

I will try to make the code as clear as possible.
Everything lies in a CBFuzzyModel class, that declares some members :


fl::Engine* fuzzyEngineRGB;
fl::InputVariable* deltaColorVar;
fl::InputVariable* deltaIntensityVar;

At the creation of the instance of this class, the private method initCodebook() is called. Basically, it initialises the background model (the 2 vectors) and the fuzzy engine.

void CBFuzzyModel::initCodebook(int rows, int cols) {
	cbMain = new std::vector<codeword>*[rows];
	for(int i = 0; i < rows; ++i)
		cbMain[i] = new std::vector<codeword>[cols];

	cbCache = new std::vector<codeword>*[rows];
	for(int i = 0; i < rows; ++i)
		cbCache[i] = new std::vector<codeword>[cols];

	fuzzyEngineRGB = new fl::Engine("fuzzyEngineRGB");

	deltaColorVar = new fl::InputVariable;
	deltaColorVar->setName("DeltaColor");
	deltaColorVar->setRange(0.000, 255.000);
	deltaColorVar->addTerm(new fl::Trapezoid("COLOR_FAVORABLE", 0.000, 0.000, 10.0, 50.0));
	deltaColorVar->addTerm(new fl::Trapezoid("COLOR_DEFAVORABLE", 10.0, 50.0, 255.000, 255.000));
	fuzzyEngineRGB->addInputVariable(deltaColorVar);

	deltaIntensityVar = new fl::InputVariable;
	deltaIntensityVar->setName("DeltaIntensity");
	deltaIntensityVar->setRange(0.000, 442.000);
	fuzzyEngineRGB->addInputVariable(deltaIntensityVar);

	fl::OutputVariable* decision = new fl::OutputVariable;
	decision->setName("DecisionIsBackground");
	decision->setRange(0.000, 1.000);
	decision->setDefaultValue(fl::nan);
	decision->addTerm(new fl::Triangle("LOW", 0.0f, 1.0f/6.0f, 1.0f/3.0f));
	decision->addTerm(new fl::Triangle("MEDIUM", 1.0f/3.0f, 1.0f/2.0f, 2.0f/3.0f));
	decision->addTerm(new fl::Triangle("HIGH", 2.0f/3.0f, 5.0f/6.0f, 1.0f));
	fuzzyEngineRGB->addOutputVariable(decision);

	fuzzyEngineRGB->configure("AlgebraicProduct", "AlgebraicSum", "AlgebraicProduct", "AlgebraicSum", "Centroid");
}

Then, the model is updated using a new frame using the update() method. It takes in parameter the frame.
An explanation of the background model : it is represented by a vector of “codebooks”, one per pixel. One codebook is a vector of “Codewords” that represent one entry for the pixel from the learning (here it is a struct containing several values Bmin, Bmax, f, l…).
For the first learning frame, every pixel’s codebook is empty so 1 codeword is created in each codebook.
Starting from the 2nd learning frame, we test the existence of a matching in the pixel’s codebook using the fuzzy system in method fuzzyRGBTest(). It takes as parameters the color of the observation (xt) and the codeword we attempt to match.
Step III in the end of this method does some cleaning stuff.


void CBFuzzyModel::update(const Mat& frameColor) {
	if(t>  nbLearningFrames) return;
	for(int i=0;i<frameColor.rows;i++)
	{
		for(int j=0;j<frameColor.cols;j++)
		{
			//std::cout << "(" << j << ", " << i << ")" << std::endl;
			Vec3b pix =  frameColor.at<Vec3b>(i,j);
			std::vector<codeword>& cm =cbMain[i][j];
			float B = std::sqrt(pix[0]*pix[0]+ pix[1]*pix[1] + pix[2]*pix[2]);
			bool found = false;

			// Test each codeword
			for(unsigned int k=0;k<cm.size();k++)
			{
				// if (DEBUG) std::cout << "(" << i << ", " << j << ")" << std::endl;
		
				float xt[3] = {float(pix[2]), float(pix[1]), float(pix[0])};	// this is the color vector of the observed pixel

				if (fuzzyRGBTest(xt, cm[k]) && !found) // Matching found
				{
					found=true;
 					cm[k].R = (cm[k].f * cm[k].R + pix[2]) / (cm[k].f + 1);
					cm[k].G = (cm[k].f * cm[k].G + pix[1]) / (cm[k].f + 1);
					cm[k].B = (cm[k].f * cm[k].B + pix[0]) / (cm[k].f + 1);
					cm[k].Bmin = MIN(B, cm[k].Bmin);
					cm[k].Bmax = MAX(B, cm[k].Bmax);
					cm[k].l= MAX(cm[k].l, this->t - cm[k].last);
					cm[k].last=t;
					cm[k].f++;
				 }else{
					cm[k].l++;
				 }
			}
			if(!found) // no matching = create new codeword
			{
                                codeword n={};
				n.R = pix[2];
				n.G = pix[1];
				n.B = pix[0];
				n.Bmin=B;
				n.Bmax=B;
				n.f=1;
 				n.l=t-1;
				n.first=t;
				n.last=t;
				cm.push_back(n);
			}
		}
	}

	// step III wrap around lambda
	if (t == nbLearningFrames)
	{
		for(int i=0;i<frameColor.rows;i++)
		{
			for(int j=0;j<frameColor.cols;j++)
			{
				std::vector<codeword>& cm =cbMain[i][j];
				for(unsigned int k=0;k<cm.size();k++)
				{
					cm[k].l = MAX(cm[k].l, (nbLearningFrames - cm[k].last + cm[k].first - 1));
				}
				// on supprime les CW du main dont la MNRL est >= Tdel
				cm.erase( remove_if(cm.begin(), cm.end(), [&](codeword& c) { return c.l>Tdel;} ), cm.end() );
			}
		}
		std::cout << "Learning finished." << std::endl;
	}

	t++;
}

The fuzzyRGBTest() method does the following : compute the observed pixel’s brightness B and the color distorsion between observed pixel and the codeword cw.
Then, fuzzy thresholds for deltaIntensityVar terms are computed (in this code, Brightness and Intensity have the same meaning). Once computed, the deltaIntensityVar is emptied of previous terms, then filled with new corresponding Terms. Finally, the Ruleblock is defined and set in the engine. Finally the engine is processed after verifications, and this functions returns true if the defuzzified decision output value is > 0.5.


bool CBFuzzyModel::fuzzyRGBTest(const float pix[3], const codeword& cw) {
	float retValue = -1;
	float B = std::sqrt(pix[0]*pix[0] + pix[1]*pix[1] + pix[2]*pix[2]);
	float xt[3] = {float(pix[0]), float(pix[1]), float(pix[2])};
	float vm[3] = {cw.R, cw.G, cw.B};
	float colorDist = this->colorDist(xt, vm);

        // Compute fuzzy thresholds
	float gapBrightness = 15.0f;
	float divider = 4.0f;
	float brightnessMin = cw.Bmin-gapBrightness;
	float brightnessMax = cw.Bmax+gapBrightness;
	float intervalBrightness = brightnessMax - brightnessMin;
	for (int i=0 ; i<deltaIntensityVar->numberOfTerms() ; ++i)
		deltaIntensityVar->removeTerm(i);

	deltaIntensityVar->addTerm(new fl::Trapezoid("BRIGHTNESS_DEFAVORABLE1",
			0.000, 0.000, CLAMP(brightnessMin-intervalBrightness, 0.0f, 442.0f), brightnessMin) );
	deltaIntensityVar->addTerm(new fl::Triangle("BRIGHTNESS_MOY_FAVORABLE1",
			CLAMP(brightnessMin-intervalBrightness, 0.0f, 442.0f), brightnessMin, CLAMP(brightnessMin + intervalBrightness/divider, 0.0f, 442.0f) ));
	deltaIntensityVar->addTerm(new fl::Trapezoid("BRIGHTNESS_FAVORABLE",
			brightnessMin, CLAMP(brightnessMin + intervalBrightness/divider, 0.0f, 442.0f), CLAMP(brightnessMax - intervalBrightness/divider, 0.0f, 442.0f),
			brightnessMax));
	deltaIntensityVar->addTerm(new fl::Triangle("BRIGHTNESS_MOY_FAVORABLE2",
			CLAMP(brightnessMax - intervalBrightness/divider, 0.0f, 442.0f), brightnessMax, CLAMP(brightnessMax+intervalBrightness, 0.0f, 442.0f)));
	deltaIntensityVar->addTerm(new fl::Trapezoid("BRIGHTNESS_DEFAVORABLE2",
			brightnessMax,  CLAMP(brightnessMax+intervalBrightness, 0.0f, 442.0f), 442.0f, 442.0f));

	// RuleBlock RGB
	fl::RuleBlock* ruleblockRGB = new fl::RuleBlock;
	ruleblockRGB->setConjunction(new fl::Minimum);
	ruleblockRGB->setDisjunction(new fl::Maximum);
	ruleblockRGB->setActivation(new fl::Minimum);
	ruleblockRGB->addRule(fl::Rule::parse("if DeltaColor is COLOR_FAVORABLE and "	// +(+o) = +
			 "DeltaIntensity is not BRIGHTNESS_DEFAVORABLE1 and DeltaIntensity is not BRIGHTNESS_DEFAVORABLE2 "
					 "then DecisionIsBackground is HIGH", fuzzyEngineRGB));
	ruleblockRGB->addRule(fl::Rule::parse("if DeltaColor is COLOR_DEFAVORABLE and "	// -+ = o
					 "DeltaIntensity is BRIGHTNESS_FAVORABLE "
					 "then DecisionIsBackground is MEDIUM", fuzzyEngineRGB));
	ruleblockRGB->addRule(fl::Rule::parse("if DeltaColor is COLOR_FAVORABLE and "	// +- = o
			 "DeltaIntensity is BRIGHTNESS_DEFAVORABLE1 or DeltaIntensity is BRIGHTNESS_DEFAVORABLE2 "
					 "then DecisionIsBackground is LOW", fuzzyEngineRGB));
	ruleblockRGB->addRule(fl::Rule::parse("if DeltaColor is COLOR_DEFAVORABLE and "	// -(o-) = -
					 "DeltaIntensity is not BRIGHTNESS_FAVORABLE "
					"then DecisionIsBackground is LOW", fuzzyEngineRGB));
	fuzzyEngineRGB->addRuleBlock(ruleblockRGB);

	std::string status;
	if (not fuzzyEngineRGB->isReady(&status)) {
		printf("Engine not ready.\n");
		throw fl::Exception("Engine not ready. "
			"The following errors were encountered:\n" + status, FL_AT);
		return -1;
	}
	else {
		deltaIntensityVar->setInputValue(abs(B));
		fl::InputVariable* deltaColorVar = fuzzyEngineRGB->getInputVariable("DeltaColor");
		deltaColorVar->setInputValue(colorDist);

		fuzzyEngineRGB->process();

		fl::OutputVariable* decision = fuzzyEngineRGB->getOutputVariable("DecisionIsBackground");
		retValue = decision->getOutputValue();
	}
	return retValue > fuzzyResultThresh;
}