void Prototype01::guiSystemEvent(ofxUIEventArgs &e){
    string name = e.widget->getName();
    
    bool bSamplePalette = false;
    
    if (name == "n clusters"){
        bSamplePalette = true;
    } else if (name.find('.') != string::npos){
        ofxUIToggle *t = (ofxUIToggle*)e.widget;
        if (t != NULL){
            if (t->getValue()){
                img.loadImage(getDataPath()+"images/"+name);
                colorExtractedFbo.allocate(img.getWidth(),img.getHeight());
                bSamplePalette = true;
            }
        }
    }
    
    if(bSamplePalette && img.isAllocated()){
        ofImage smallImg;
        smallImg = img;
        smallImg.resize(img.getWidth()*0.25, img.getHeight()*0.25);
        const int colorCount = nPaletteColors;
        const int sampleCount = smallImg.getHeight() * smallImg.getWidth();
        cv::Mat colorSamples( sampleCount, 1, CV_32FC3 );
        
        // get our pixels
        unsigned char * pixels = smallImg.getPixels();
        
        // clear our list of colors
        palette.clear();
        
        // build our matrix of samples
        cv::MatIterator_<cv::Vec3f> sampleIt = colorSamples.begin<cv::Vec3f>();
        for(int i=0; i<sampleCount; i++){
            int pos = i * 3;
            *sampleIt = cv::Vec3f( pixels[pos], pixels[pos+1], pixels[pos+2] );
            sampleIt++;
        }
        
        // call kmeans
        cv::Mat labels, clusters;
        cv::kmeans( colorSamples, colorCount, labels, cv::TermCriteria(), 2, cv::KMEANS_RANDOM_CENTERS, clusters ); //cv::TermCriteria::COUNT, 8, 0
        
        for( int i = 0; i < colorCount; ++i ){
            ofColor clusterColor = ofColor( clusters.at<cv::Vec3f>(i,0)[0], clusters.at<cv::Vec3f>(i,0)[1], clusters.at<cv::Vec3f>(i,0)[2] );
            palette.push_back(clusterColor);
        }
        
        sortByDistance(palette);
    }
    
    bApplyMedian = true;
}
vector<ofColor> & ofxColorQuantizer::quantize(ofPixels inputImage){
	
	const int colorCount = numColors;
	const int sampleCount = inputImage.getHeight() * inputImage.getWidth();
	cv::Mat colorSamples( sampleCount, 1, CV_32FC3 );
	
	// get our pixels
	unsigned char * pixels = inputImage.getPixels();
	
	// clear our list of colors
	colors.clear();
	
	// build our matrix of samples
	cv::MatIterator_<cv::Vec3f> sampleIt = colorSamples.begin<cv::Vec3f>();
	for(int i=0; i<sampleCount; i++){
		int pos = i * 3;
		*sampleIt = cv::Vec3f( pixels[pos], pixels[pos+1], pixels[pos+2] );
		sampleIt++;
	}
	
	// call kmeans
	cv::Mat labels, clusters;
	cv::kmeans( colorSamples, colorCount, labels, cv::TermCriteria(), 2, cv::KMEANS_RANDOM_CENTERS, clusters ); //cv::TermCriteria::COUNT, 8, 0 
	
	// clear our list of colors
	colors.clear();
	
	for( int i = 0; i < colorCount; ++i ){
		ofColor clusterColor = ofColor( clusters.at<cv::Vec3f>(i,0)[0], clusters.at<cv::Vec3f>(i,0)[1], clusters.at<cv::Vec3f>(i,0)[2] );
		colors.push_back(clusterColor);
	}
	
	/*
	
	// add colors from labelz
	unsigned char * p = temp.getPixels();
	cv::MatIterator_<int> labelIt = labels.begin<int>();
	for(int i=0; i<colorCount; i++){
		
		ofColor newColor;
		newColor.r = clusterColors[*labelIt].r;
		newColor.g = clusterColors[*labelIt].g;
		newColor.b = clusterColors[*labelIt].b;
		 
		++labelIt;
		//cout << i << " " << colors[i] << endl;
	}
	
	*/
	
	return colors;
}
void SingleBrush::selfUpdate(){
    ofPushStyle();
    ofSetColor(255);
    
    video.update();
    
    if (bClean){
        colorAdded.begin();
        ofClear(0,0);
        colorAdded.end();
        
        brush.clear();
        canvas.beginBoth();
        background->draw();
        canvas.endBoth();
        
        bColorSample = true;
        bClean = false;
    }
    
    if(bColorSample && video.isInitialized()){
        ofImage smallImg;
        smallImg.setFromPixels(video.getPixels(), video.getWidth(), video.getHeight(), OF_IMAGE_COLOR);
        smallImg.resize(video.getWidth()*0.25, video.getHeight()*0.25);
        const int colorCount = nPaletteColors;
        const int sampleCount = smallImg.getHeight() * smallImg.getWidth();
        cv::Mat colorSamples( sampleCount, 1, CV_32FC3 );
        
        // get our pixels
        unsigned char * pixels = smallImg.getPixels();
        
        // clear our list of colors
        palette.clear();
        
        // build our matrix of samples
        cv::MatIterator_<cv::Vec3f> sampleIt = colorSamples.begin<cv::Vec3f>();
        for(int i=0; i<sampleCount; i++){
            int pos = i * 3;
            *sampleIt = cv::Vec3f( pixels[pos], pixels[pos+1], pixels[pos+2] );
            sampleIt++;
        }
        
        // call kmeans
        cv::Mat labels, clusters;
        cv::kmeans( colorSamples, colorCount, labels, cv::TermCriteria(), 2, cv::KMEANS_RANDOM_CENTERS, clusters ); //cv::TermCriteria::COUNT, 8, 0
        
        for( int i = 0; i < colorCount; ++i ){
            ofColor clusterColor = ofColor( clusters.at<cv::Vec3f>(i,0)[0], clusters.at<cv::Vec3f>(i,0)[1], clusters.at<cv::Vec3f>(i,0)[2] );
            palette.push_back(clusterColor);
        }
        
        sortByDistance(palette);
        
        bColorSample = false;
    }
    
    //  UPDATE
    //
    brush.update();
    //  RENDER
    //
    {
        //  Drawing on Canvas
        //
        {
            if(brush.bDown){
                if(brush.bInk){
                    colorAdded.begin();
                    ofClear(0, 0);
                    brushTexture.bind();
                    brush.draw();
                    brushTexture.unbind();
                    colorAdded.end();
                }
                
                water.swap();
                water.dst->begin();
                water.src->draw(0,0);
                ofSetColor(waterAmount);
                brush.drawMask();
                water.dst->end();
            }
            
            int width = ofGetWidth();
            int height = ofGetHeight();
            
            canvas.swap();
            canvas.dst->begin();
            colorAddShader.begin();
            colorAddShader.getShader().setUniformTexture("backbuffer", *(canvas.src), 0);
            colorAddShader.getShader().setUniformTexture("colorAddedTexture", colorAdded, 1);
            glBegin(GL_QUADS);
            glTexCoord2f(0, 0); glVertex3f(0, 0, 0);
            glTexCoord2f(width, 0); glVertex3f(width, 0, 0);
            glTexCoord2f(width, height); glVertex3f(width, height, 0);
            glTexCoord2f(0,height);  glVertex3f(0,height, 0);
            glEnd();
            colorAddShader.end();
            canvas.dst->end();
            
            //  Water Effect
            //
            water.swap();
            water.dst->begin();
            ofClear(0,255);
            absorveShader.begin();
            water.src->draw(0, 0);
            absorveShader.end();
            water.dst->end();
            
//            normals << *(water.dst);
            flow << *(water.dst);
            
            noise.begin();
            noiseShader.begin();
            noiseShader.getShader().setUniformTexture("normalsTexture", flow, 1);
            noiseShader.getShader().setUniformTexture("waterTexture", *(water.dst), 2);
            water.dst->draw(0,0);
            noiseShader.end();
            noise.end();
            
            canvas.swap();
            canvas.dst->begin();
            displaceShader.begin();
            displaceShader.getShader().setUniformTexture("normals", noise, 1);
            displaceShader.getShader().setUniformTexture("dampMap", *(water.dst), 2);
            canvas.src->draw(0, 0);
            displaceShader.end();
            canvas.dst->end();
        }
        
        
        
    }
    ofPopStyle();
}