コード例 #1
0
///////////////////////////////////////////////////////////////////////////////
//
//      Run simplified version of Hertzmann's painterly image filter.
//      You probably will want to use the Draw_Stroke funciton and the
//      Stroke class to help.
//      Return success of operation.
//
///////////////////////////////////////////////////////////////////////////////
bool TargaImage::NPR_Paint()
{
	TargaImage ref_image = TargaImage(*this);
	TargaImage canvas = TargaImage(width, height); //Constant color that will get painted on
	
	int x, y, i, j, g, m;
	int r0, g0, b0, r1, g1, b1;
	typedef tuple<int, int, double> error_point;

	double d, area_error;
	int T = 25; //Error threshold
	static const unsigned int arr[] = {7, 3, 1}; //Brush sizes
	vector<int> rs (arr, arr + sizeof(arr) / sizeof(arr[0]) );

	int rad;
	//*****
	//Paint
	//*****
	for(size_t b=0; b < rs.size(); b++) { //For each brush size
		ref_image.Filter_Gaussian_N(2*rs[b]+1); //referenceImage
		g = 2*rs[b]+1; //Could also be 2*rs[b]+1
		rad = 3*rs[b];
		//***Paint a layer***
		vector <Stroke> strokes;
		//Find all of the grid block centers
		vector < tuple<int, int> > centers;
		centers.reserve( (width/g + 1)* (height/g + 1) );
		for( x = g/2; x < g*(width/g); x+=g ) {
			for( y = g/2; y < g*(height/g); y+=g ) {
				centers.push_back( make_tuple(x, y) );
			}
		}
		//Construct overlapping blocks around right and bottom edge, Possibly Unnecessary
		if (width % g) { //Hold x constant equal to width-g/2-1, loop down the column increasing y			
			x = width - g/2 - 1;
			for( y = g/2; y < g*(height/g); y+=g ) {
				centers.push_back( make_tuple(x, y) );
			}
		}
		if (height % g) {
			y = height - g/2 - 1; //Hold y constant equal to height-g/2-1, loop across the row increasing x
			for( x = g/2; x < g*(width/g); x+=g ) {
				centers.push_back( make_tuple(x, y) );
			}
		}
		//if both x_extra and y_extra then need final bottom right corner block, probably unnecessary		
		

		for( size_t c=0; c < centers.size(); c++ ) { //For each grid center
			tie (x, y) = centers[c];
				//Find the error in the area/region/block
				vector < error_point > errors;
				errors.reserve(g*g);
				area_error = 0;
				for (j = -g/2; j<=g/2; ++j) {
					for (i = -g/2; i<=g/2; ++i) {
						m = (width*(y+j) + (x+i))*4; //Location of current pixel
						tie (r0, g0, b0) = make_tuple(ref_image.data[m], ref_image.data[m+1], ref_image.data[m+2]);
						tie (r1, g1, b1) = make_tuple(canvas.data[m], canvas.data[m+1], canvas.data[m+2]);
						//Calculate euclidean distance
						d = sqrt( (double) (r1-r0)*(r1-r0) + (g1-g0)*(g1-g0) + (b1-b0)*(b1-b0) ); 
						//Save the coordinate and its error
						errors.push_back(error_point(x+i, y+j, d));
						area_error += d;
					}//i
				}//j
				if( area_error > T ) {
					//Find largest error point
					sort(errors.begin(), errors.end(), cmp_errors);					
					tie (i, j, d) = errors.front();
					//Build a Stroke at loacation x,y with radius and value of r,g,b,alpha
					m = (width*j + i)*4; //Location of current pixel
					Stroke s = Stroke(rad, i, j, ref_image.data[m], ref_image.data[m+1], ref_image.data[m+2], ref_image.data[m+3]);
					strokes.push_back(s);
				}

		}//c

		//*******
		//Paint all strokes in random order onto canvas
		//*******
		random_shuffle ( strokes.begin(), strokes.end() );
		vector <Stroke>::iterator it;
		for (it = strokes.begin(); it != strokes.end(); it++) {
			canvas.Paint_Stroke(*it);
		}

		//Reset the reference image to the unchanged image data for the next smaller pass
		memcpy(ref_image.data, data, sizeof(unsigned char) * width * height * 4); 
	}//b	

	//Write the canvas data to the displayed image
	memcpy(data, canvas.data, sizeof(unsigned char) * width * height * 4);
	//Overwrite alpha values
	for(i=3; i<width*height*4; i+=4) {
		data[i] = 255;
	}

    return true;
}