Exemplo n.º 1
0
void testApp :: checkForCommonFill ( ofxCvGrayscaleImage& imageOut, ofxCvGrayscaleImage& image1, ofxCvGrayscaleImage& image2 )
{
	int noPixels;
	noPixels = imageOut.width * imageOut.height;

	unsigned char* imageOutPixels;
	unsigned char* image1Pixels;
	unsigned char* image2Pixels;
	
	imageOutPixels	= new unsigned char[ noPixels ];
	image1Pixels	= image1.getPixels();
	image2Pixels	= image2.getPixels();
	
	for( int i=0; i<noPixels; i++ )
	{
		if
		( 
			image1Pixels[ i ] == 255 &&
			image2Pixels[ i ] == 255
		)
		{
			imageOutPixels[ i ] = 255;
		}
		else
		{
			imageOutPixels[ i ] = 0;
		}
	}
	
	imageOut.setFromPixels( imageOutPixels, imageOut.width, imageOut.height );
	
	delete[] imageOutPixels;
}
Exemplo n.º 2
0
	void convert(ofxCvGrayscaleImage &src, ofImage &dst) {
		for(int i = 0; i < src.height*src.width; i += 1) {
			if(src.getPixels()[i]==0) {
				dst.getPixels()[i*4] = 0;
			} else {
				dst.getPixels()[i*4] = 0xffffffff;
			}
		}
		dst.update();
	}
Exemplo n.º 3
0
void ofApp::drawPointCloud(ofxCvGrayscaleImage grayImage) {
    int w = 640;
    int h = 480;
    ofMesh mesh;
    mesh.setMode(OF_PRIMITIVE_POINTS);
    //int step = 8;
    int counter = 0;
    
    unsigned char * pix = grayImage.getPixels();
    
    for(int y = 0; y < h; y += step) {
        counter++;
        int start = 0;
        if (stepOffset) { // if we are using the step offset
            if ((counter)%2) {
                start = step/2;
            }
        }
        for(int x = start; x < w; x += step) {
            if(kinect.getDistanceAt(x, y) > 0 && pix[x+y*w]>0) {
                mesh.addColor(kinect.getColorAt(x,y));
                mesh.addVertex(kinect.getWorldCoordinateAt(x, y));
                ofPoint test = kinect.getWorldCoordinateAt(x, y);
                if (makeTriangles){     // add to the triangles if required
                    triangulation.addPoint(test);
                }
            }
        }
    }
    
    if (makeTriangles){     // add to the triangles if required
        triangulation.triangulate();
    }
    glPointSize(3);
    ofPushMatrix();
    // the projected points are 'upside down' and 'backwards'
    ofScale(1, -1, -1);
    ofTranslate(0, 0, -1000); // center the points a bit
    ofEnableDepthTest(); if (makeTriangles){     // add to the triangles if required
        triangulation.draw();
    } else {
        mesh.drawVertices();
    }
    ofNoFill();
    ofDisableDepthTest();
    ofPopMatrix();
}
Exemplo n.º 4
0
void thresholdCalculator::drawBrightnessScanGraph(int x, int y, ofxCvGrayscaleImage & img, bool bIsVertical, float threshold_p,
												  float threshold_g, string graphname)
{
	unsigned char * tempPixels = img.getPixels();
	
	ofPushMatrix();
	ofTranslate(x, y, 0);
	
	ofSetColor(255, 255, 255, 100);
	ofBeginShape();
	
	if (!bIsVertical) {
		int nLine = scanY;
		for (int i = 0; i < img.width; i++){
			ofVertex(i, 255 - (int)tempPixels[i + img.width * nLine]);
		}
	} else {
		int nLine = scanX;
		for (int i = 0; i < img.height; i++){
			ofVertex(i, 255 - (int)tempPixels[nLine + i * img.width]);
		}
	}
	
	ofEndShape(false);
	
	ofSetColor(255, 0, 0, 80);
	ofLine(0, 255 - threshold_p, img.width, 255 - threshold_p);
	
	ofSetColor(0, 0, 255, 80);
	ofLine(0, 255 - threshold_g, img.width, 255 - threshold_g);
	
	ofSetColor(120, 120, 120, 80);
	ofLine(0, 255 - getMinInWhite(), img.width, 255 - getMinInWhite());
	ofLine(0, 255 - getPupilAvg(), img.width, 255 - getPupilAvg());
	
	ofSetColor(120, 120, 255, 80);
	ofLine(0, 255 - getGlintThreshold(true), img.width, 255 - getGlintThreshold(true));
	
		
	ofSetColor(255, 255, 255);
	ofRect(0, 0, img.width, img.height);
	ofDrawBitmapString(graphname, 1, 255 + 12);
	
	ofPopMatrix();
	
}
Exemplo n.º 5
0
//---------------------------------------------------------------------------------
void videoBlob::set(ofxCvBlob myBlob, ofxCvColorImage myImage, ofxCvGrayscaleImage myMask){

	memcpy(&blob, &myBlob, sizeof(ofxCvBlob));

	// now, let's get the data in,
	int w = blob.boundingRect.width;
	int h = blob.boundingRect.height;
	int imgw = myImage.width;
	int imgh = myImage.height;
	int imgx = blob.boundingRect.x;
	int imgy = blob.boundingRect.y;

	unsigned char * blobRGBA = new unsigned char [ w * h * 4 ];
	unsigned char * colorPixels 	= myImage.getPixels();
	unsigned char * grayPixels 		= myMask.getPixels();

	for (int i = 0; i < w; i++){
		for (int j = 0; j < h; j++){
			int posTex = (j * w + i)*4;
			int posGray = ((j+imgy)*imgw + (i + imgx));
			int posCol = posGray * 3;
			blobRGBA[posTex + 0] = colorPixels[posCol + 0];
			blobRGBA[posTex + 1] = colorPixels[posCol + 1];
			blobRGBA[posTex + 2] = colorPixels[posCol + 2];
			blobRGBA[posTex + 3] = grayPixels[posGray];
		}
	}

//	myTexture.clear();
//	myTexture.allocate(w,h,GL_RGBA);

	unsigned char * black = new unsigned char [ofNextPow2(w) * ofNextPow2(h) * 4];
	memset(black, 0, ofNextPow2(w) * ofNextPow2(h) * 4);
//	myTexture.loadData(black, ofNextPow2(w), ofNextPow2(h), GL_RGBA);
//	myTexture.loadData(blobRGBA, w, h, GL_RGBA);

	delete black;
	delete blobRGBA;

	pos.x = blob.centroid.x;
	pos.y = blob.centroid.y;
	scale = 1;
	angle = 0;

}
Exemplo n.º 6
0
void BackgroundLearner::learnBackground( ofxCvGrayscaleImage & graySrc, float rate )
{
	
	unsigned char * pixels = graySrc.getPixels();
	if( framesLearned == 0 ) rate = 1;
	
	float dRate = 1 - rate;
	
	
	for( int i = 0; i < w*h; i++)
	{
		imageFloat[i] = dRate * imageFloat[i] + rate * pixels[i];
		imageByte[i] = (unsigned char)(imageFloat[i]);
	}
	


	grayImg.setFromPixels(imageByte,w,h);
}
void ofxOpticalFlowLK :: update ( ofxCvGrayscaleImage& source )
{
	update( source.getPixels(), source.width, source.height, OF_IMAGE_GRAYSCALE );
}
Exemplo n.º 8
0
void glintLineChecker::update(ofxCvGrayscaleImage & eyeImg, int nGlints, ofxCvContourFinder & contourFinder, bool bUseGlintInBrightEye, ofxCvContourFinder & contourFinderBright){
	
	if (nGlints == 2) {
		
		lineSegments.clear();
		unsigned char * pixels = eyeImg.getPixels();
		
		for (int j = 0; j < eyeImg.height; j++){
			lineSegment temp;
			bool bStarted = false;
			
			for (int i = 0; i < eyeImg.width - 1; i++) {
				
				int pixela = pixels [ j * eyeImg.width + i];
				int pixelb = pixels [ j * eyeImg.width + i + 1];
				
				if ((pixela == 255) && (pixelb == 0)) {
					// yeah!! we are starting !! 
					temp.startx = i;
					temp.starty = j;
					bStarted = true;
				}
				
				if ((pixela == 0) && (pixelb == 255)) {
					
					if (bStarted == true) {
						// cool we are ending :)
						temp.endx = i;
						temp.endy = j;
						temp.distance = temp.endx - temp.startx;
						
						lineSegments.push_back(temp);
						//printf("adding line segment %i %i %i %i -- %i \n", temp.startx, temp.starty, temp.endx, temp.endy, temp.distance );
						
						bStarted = false;
					}
				}
			}
		}
		
		if (bDeleteLine) {
			// remove_if doesn't work now, so for now..
//			lineSegments.erase(remove_if(lineSegments.begin(), lineSegments.end(), glintChecker::lineInRange), lineSegments.end());
			for (int i = 0; i < lineSegments.size(); i++) {
				if (lineInRange(lineSegments[i])) {
					lineSegments.erase(lineSegments.begin() + i);
					i--;
				}
			}
			
			for (int i = 0; i < lineSegments.size(); i++) {
				if (bUseGlintInBrightEye) {
					if (lineCrossGlintInBrightEye(lineSegments[i], contourFinderBright)) {
						lineSegments.erase(lineSegments.begin() + i);
						i--;
					}
				}
			}
		}
		
		cvSetZero(myStripesImage.getCvImage());
		unsigned char * stripepixels = myStripesImage.getPixels();
		
		for (int i = 0; i < lineSegments.size(); i++) {
			int startx = lineSegments[i].startx;
			int endx = lineSegments[i].endx;
			int y = lineSegments[i].starty;
			for (int j = startx; j < endx; j++){
				stripepixels[y * myStripesImage.width + j] = 255;
			}
		}
		myStripesImage.flagImageChanged();
		int nBlobs = linesFinder.findContours(myStripesImage, 100, 10000, 1, false, true);
		
		
		leftGlintID = -1;
		rightGlintID = -1;

		if (nBlobs > 0) {
			ofRectangle foundLinesRect = linesFinder.blobs[0].boundingRect;
			
			for (int i = 0; i < contourFinder.blobs.size(); i++){
				ofRectangle blobRect = contourFinder.blobs[i].boundingRect;
				if (ofInRange(foundLinesRect.x, blobRect.x, blobRect.x + blobRect.width) &&
					(ofInRange(foundLinesRect.y, blobRect.y, blobRect.y + blobRect.height) ||
					 ofInRange(foundLinesRect.y + foundLinesRect.height, blobRect.y, blobRect.y + blobRect.height))){
						leftGlintID = i;
					} else if (ofInRange(foundLinesRect.x + foundLinesRect.width, blobRect.x, blobRect.x + blobRect.width) &&
							   (ofInRange(foundLinesRect.y, blobRect.y, blobRect.y + blobRect.height) ||
								ofInRange(foundLinesRect.y + foundLinesRect.height, blobRect.y, blobRect.y + blobRect.height))) {
						rightGlintID = i;
					}
			}
		}
	}
}
Exemplo n.º 9
0
//--------------------------------------------------------------
void eyeTracker::update(ofxCvGrayscaleImage & grayImgFromCam, float threshold, float minSize, float maxSize,  float minSquareness) {

    //threshold?
    //threshold = thresh;

    grayImgPreWarp.setFromPixels(grayImgFromCam.getPixels(), grayImgFromCam.width, grayImgFromCam.height);		// TODO: there's maybe an unnecessary grayscale image (and copy) here...

    if( flipX || flipY ) {
        grayImgPreWarp.mirror(flipY, flipX);
    }

    /*  // before we were scaling and translating, but this is removed for now

     if (fabs(xoffset-1) > 0.1f || fabs(yoffset-1) > 0.1f){
    	grayImgPreWarp.translate(xoffset, yoffset);
    }

    if (fabs(scalef-1) > 0.1f){
    	grayImgPreWarp.scale(scalef, scalef);
    }*/

    grayImg = grayImgPreWarp;



    grayImgPreModification = grayImg;
    grayImg.blur(5);

    if (bUseContrast == true) {
        grayImg.applyBrightnessContrast(brightness,contrast);
    }

    if (bUseGamma == true) {
        grayImg.applyMinMaxGamma(gamma);
    }

    grayImg += edgeMask;

    threshImg = grayImg;


    threshImg.contrastStretch();
    threshImg.threshold(threshold, true);


    // the dilation of a 640 x 480 image is very slow, so let's just do a ROI near the thing we like:

    threshImg.setROI(currentEyePoint.x-50, currentEyePoint.y-50, 100,100);	// 200 pix ok?
    if (bUseDilate == true) {
        for (int i = 0; i < nDilations; i++) {
            threshImg.dilate();
        }
    }
    threshImg.resetROI();



    bFoundOne = false;

    int		whoFound = -1;

    int num = contourFinder.findContours(threshImg, minSize, maxSize, 100, false, true);
    if( num ) {

        for(int k = 0; k < num; k++) {



            float ratio =	contourFinder.blobs[k].boundingRect.width < contourFinder.blobs[k].boundingRect.height ?
                            contourFinder.blobs[k].boundingRect.width / contourFinder.blobs[k].boundingRect.height :
                            contourFinder.blobs[k].boundingRect.height / contourFinder.blobs[k].boundingRect.width;

            float arcl = contourFinder.blobs[k].length;
            float area = contourFinder.blobs[k].area;
            float compactness = (float)((arcl*arcl/area)/FOUR_PI);

            if (bUseCompactnessTest	== true && compactness > maxCompactness) {
                continue;
            }


            //printf("compactness %f \n", compactness);

            //lets ignore rectangular blobs
            if( ratio > minSquareness) {
                currentEyePoint = contourFinder.blobs[k].centroid;
                currentNormPoint.x = currentEyePoint.x;
                currentNormPoint.y = currentEyePoint.y;

                currentNormPoint.x /= w;
                currentNormPoint.y /= h;


                bFoundOne = true;
                whoFound = k;

                break;
            }
        }
    }

    if (bFoundOne && whoFound != -1) {



        // do some convex hull stuff:
        CvSeq* ptseq = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour),sizeof(CvPoint), storage );
        CvSeq* hull;
        CvPoint pt0;

        for(int i = 0; i < contourFinder.blobs[whoFound].nPts; i++ ) {

            pt0.x = contourFinder.blobs[whoFound].pts[i].x;
            pt0.y = contourFinder.blobs[whoFound].pts[i].y;
            cvSeqPush( ptseq, &pt0 );

        }
        hull = cvConvexHull2( ptseq, 0, CV_CLOCKWISE, 0 );
        int hullcount = hull->total;



        // -------------------------------- TRY TO GET A GOOD ELLIPSE HELLS YEAH !!

        int MYN = hullcount;
        float x[MYN], y[MYN];
        double p[6];
        double ellipseParam[5];
        float theta;
        FitEllipse fitter;
        for (int i=0; i<MYN; i++) {
            CvPoint pt = **CV_GET_SEQ_ELEM( CvPoint*, hull, i);
            x[i] = pt.x;
            y[i] =  pt.y;
        }
        double xc, yc;
        double xa, ya;
        double la, lb;
        fitter.apply(x,y,MYN);
        p[0] = fitter.Axx;
        p[1] = fitter.Axy;
        p[2] = fitter.Ayy;
        p[3] = fitter.Ax;
        p[4] = fitter.Ay;
        p[5] = fitter.Ao;

        bool bOk = solve_ellipse(p,ellipseParam);

        ofxCvBlob temp;


        if (bOk == true) {

            //float *params_ellipse = pupilGeometries[whichEye].params_ellipse;
            float axis_a = ellipseParam[0];
            float axis_b = ellipseParam[1];
            float cx 	 = ellipseParam[2];
            float cy 	 = ellipseParam[3];
            theta	 = ellipseParam[4];
            float aspect = axis_b/axis_a;

            for (int i = 0; i < 5; i++) {
                eyeTrackedEllipse.ellipseParam[i] = ellipseParam[i];
            }

            //theta = ofRandom(0,TWO_PI);


            int resolution = 24;

            ofxPoint2f ptsForRotation[resolution];

            for (int i=0; i<resolution; i++) {
                float t = TWO_PI * (float)i/(float)resolution;
                float ex = cx + (axis_a * cos(t ));
                float ey = cy + (axis_b * sin(t ));
                ptsForRotation[i].set(ex,ey);
            }

            for (int i=0; i<resolution; i++) {
                ptsForRotation[i].rotate(theta * RAD_TO_DEG, ofxPoint2f(cx, cy));
            }

            currentEyePoint.set(cx, cy);
            currentNormPoint.x = currentEyePoint.x;
            currentNormPoint.y = currentEyePoint.y;
            currentNormPoint.x /= w;
            currentNormPoint.y /= h;


        } else {


            bFoundOne = false;

        }

        cvRelease((void **)&hull);

    }
Exemplo n.º 10
0
//----------------------------------------------------
void eyeTracker::update(ofxCvGrayscaleImage & grayImgFromCam) {
	
	// get the image from input manager.
	currentImg.setFromPixels(grayImgFromCam.getPixels(), grayImgFromCam.width, grayImgFromCam.height);	

	// get the small size image to find eye position.
	if (divisor !=1) smallCurrentImg.scaleIntoMe(currentImg, CV_INTER_LINEAR);
	
	// get the eye position
	bFoundOne = eFinder.update(smallCurrentImg, threshold_e, minBlobSize_e, maxBlobSize_e, true);	
	
	if (eFinder.centroid.x > w - (targetRect.width/2) || eFinder.centroid.x < (targetRect.width/2) ||
		eFinder.centroid.y > h - (targetRect.height/2) || eFinder.centroid.y < (targetRect.height/2)){
		bFoundOne = false;
	}

	bFoundEye = false;
	bool bFoundPupil = false;
	
	if (bFoundOne){
		
		targetRect.x = eFinder.centroid.x - (targetRect.width/2);
		targetRect.y = eFinder.centroid.y - (targetRect.height/2);
		
		// make big eye image
		currentImg.setROI(targetRect);
		
		if (magRatio != 1) {
			magCurrentImg.scaleIntoMe(currentImg, CV_INTER_CUBIC);			// magnify by bicubic
		} else {
			magCurrentImg.setFromPixels(currentImg.getRoiPixels(), targetRect.width, targetRect.height);
		}
		
		currentImg.resetROI();
		
		// get current bright eye image & dark eye image
		bIsBrightEye = getBrightEyeDarkEye();
		
		// get glint position in a bright eye image, if needed. <= shoul be here..? think about it.
		if (bIsBrightEye && bUseGlintinBrightEye) {
			thresCal.update(smallCurrentImg, eFinder.diffImg, currentImg, targetRect, true);
			gFinder.findGlintCandidates(magCurrentImg, thresCal.getGlintThreshold(true), minBlobSize_g, maxBlobSize_g, true);
			targetRectBright = targetRect;
		}
		
		// find Pupil image again with the big eye image. (try double ellipse fit later?)
		if (!bIsBrightEye){
			
			// get the averages of pupil & white part.
			if (bUseAutoThreshold_g || bUseAutoThreshold_p){
				thresCal.update(smallCurrentImg, eFinder.diffImg, currentImg, targetRect, false);
			}
			
			if (bUseAutoThreshold_g) threshold_g = thresCal.getGlintThreshold(false);
			else threshold_g = threshold_g_frompanel;
			
			// get glint position with dark eye image.
			gFinder.update(magCurrentImg, threshold_g, minBlobSize_g, maxBlobSize_g, bUseGlintinBrightEye);
			
			if (gFinder.bFound){
				
				if (bUseAutoThreshold_p) threshold_p = thresCal.getPupilThreshold();
				else threshold_p = threshold_p_frompanel;
				
				if (bUseHomography && gFinder.bFourGlints){
					// Homography..
					ofxCvGrayscaleAdvanced* temp = homographyCal.getWarpedImage(magCurrentImg, gFinder, magRatio);
					bFoundPupil = pFinder.update(*temp, threshold_p, minBlobSize_p, maxBlobSize_p, targetRect);
					
				} else {
					
					bFoundPupil = pFinder.update(magCurrentImg, threshold_p, minBlobSize_p, maxBlobSize_p, targetRect);
				}
				
				if (bFoundPupil){
					pupilCentroid = pFinder.currentPupilCenter;
					bFoundEye = true;
					targetRectDark = targetRect;
				}
			}
		}
	}	
	//	cout << "bFoundOne: " << bFoundOne << "  bFoundPupil: " << bFoundPupil << " bFoundGlint: " << gFinder.bFound << endl;
}
//==============================================================
void DepthHoleFiller::fillBlobsWithInterpolatedData (ofxCvGrayscaleImage &depthImage){
	
	// interpolates between one edge of the hole and the other
	
	unsigned char *depthPixels =      depthImage.getPixels();
	unsigned char *blobsPixels = ofxCv8uC1_Blobs.getPixels();
	
	const unsigned char HOLE = 255;
	int row = 0;
	int index=0;
	
	int runIndexA;
	int runIndexB;
	unsigned char runValueA;
	unsigned char runValueB;
	
	for (int y=0; y<KH; y++){
		runIndexA = 0;
		runIndexB = 0;
		
		bool bRunStarted = false;
		unsigned char bval0;
		unsigned char bval1;
		row = y*KW;
		
		for (int x=1; x<KW; x++){
			index = row + x; 
			bval0 = blobsPixels[index-1];
			bval1 = blobsPixels[index  ];
			
			if ((bval0 != HOLE) && (bval1 == HOLE)){
				runIndexA = index;
				runValueA = depthPixels[index-1];
				bRunStarted = true;
			}
			if (bRunStarted){
				if ((bval0 == HOLE) && (bval1 != HOLE)){
					runIndexB = index-1;
					runValueB = depthPixels[index];
					bRunStarted = false;
					
					// since we have identified a hole run, fill it appropriately
					int runlen = (runIndexB - runIndexA);
					int vallen = (runValueB - runValueA);
					
					// interpolate between the values.
					if (runlen <= 1){
						int va = runValueA;
						int vb = runValueB;
						unsigned char val = (unsigned char)((va+vb)/2);
						for (int i=runIndexA; i<=runIndexB; i++){
							blobsPixels[i] = val;
						}
					} else {
						float runlenf = (float)(runlen);
						float vallenf = (float)(vallen);
						for (int i=runIndexA; i<=runIndexB; i++){
							float tf = (float)(i-runIndexA)/runlenf;
							float vf = runValueA + tf*vallenf; 
							unsigned char val = (unsigned char)(vf + 0.5);
							blobsPixels[i] = val;
						}
					}
					
				}
			}
			
		}
		
	}
}
Exemplo n.º 12
0
//--------------------------------------------------------------
void Wind::calculateTiny( ofxCvGrayscaleImage& img )
{
	
	int img_cell_height = img.height/(TINY_HEIGHT+2);
	int img_cell_width = img.width/(TINY_WIDTH+2);
	
	int img_row_count = img.height/img_cell_height;
	int img_col_count = img.width/img_cell_width;
	
	unsigned char* pixels = img.getPixels();
	
	/*
	int tx=-1;
	int ty=-1;	
	if ( mouse_x_pct >= 0.0f && mouse_x_pct <= 1.0f && mouse_y_pct >= 0.0f && mouse_y_pct <= 1.0f )
	{
		tx = mouse_x_pct*TINY_WIDTH;
		ty = mouse_y_pct*TINY_HEIGHT;
	}*/
	
	for ( int i=1; i<img_row_count-1; i++ )
	{
		for ( int j=1; j<img_col_count-1; j++ )
		{
			// loop through everything in this cell, average, and max
			int start_x = j*img_cell_width - img_cell_width/2;			
			int end_x = start_x + 2.0f*img_cell_width;
			
			int start_y = i*img_cell_height - img_cell_height/2;
			int end_y = start_y + 2.0f*img_cell_height;
			
			float max = 0;
			int total = 0;
			for ( int u = start_y; u<end_y; u++ )
			{
				int base = u*img.width;
				
				// calculate u falloff factor
				float u_factor = 1.0f-(2.0f*fabsf( ((float)(u-start_y))/(end_y-start_y) - 0.5f ));
				
				for ( int v = start_x; v<end_x; v++ )
				{
					// get value
					int index = base + v;
					float val = (float)pixels[index];
					
					// calculate v falloff facotr
					float v_factor = 1.0f-(2.0f*fabsf( ((float)(v-start_x))/(end_x-start_x) - 0.5f ));
					
					// apply falloff factors
					val *= (u_factor+v_factor);
					
					// average
					total += val;
					// max
					if ( max < val )
						max = val;
				}
			}
			
			float average = (float)total/(img_cell_height*img_cell_width*4);
			
			/*
			if ( i-1 == ty && j-1 == tx )
				tiny[(i-1)*TINY_WIDTH+(j-1)] = 255;
			else*/
				tiny[(i-1)*TINY_WIDTH+(j-1)] = (unsigned char)(average*0.5f+max*0.5f);
		}
	}
}