Exemplo n.º 1
0
void testWaterfall()
{
	cout << "[main]: " << __func__ << "()" << endl;
	PNG in;
	in.readFromFile("in_05.png");

	List<RGBAPixel> list = imageToList(in);
	list.waterfall();

	PNG out = listToImage(list, in.width(), in.height());
	out.writeToFile("waterfall_01.png");

	checkSoln(__func__, out, "soln_waterfall_01.png");

	in.readFromFile("in_06.png");
	list = imageToList(in);
	list.waterfall();
	out = listToImage(list, in.width(), in.height());
	out.writeToFile("waterfall_02.png");

	checkSoln(__func__, out, "soln_waterfall_02.png");
}
Exemplo n.º 2
0
/**
 * This function blends, or averages, two PNGs together. That is, each pixel in
 * the returned image consists of the averaged components (red, green, blue) of
 * the two input images.
 *
 * @param firstImage  The first of the two PNGs to be averaged together.
 * @param secondImage The second of the two PNGs to be averaged together.
 *
 * @return The averaged image.
 */
PNG blendImages(PNG firstImage, PNG secondImage)
{
 for (size_t yi = 0; yi < firstImage.height(); yi++)
    {
        for (size_t xi = 0; xi < firstImage.width(); xi++)
        {
    	firstImage(xi, yi)->green =(firstImage(xi, yi)->green+secondImage(xi, yi)->green)/2;
	firstImage(xi, yi)->red =(firstImage(xi, yi)->red+secondImage(xi, yi)->red)/2;
	firstImage(xi, yi)->blue =(firstImage(xi, yi)->blue+secondImage(xi, yi)->blue)/2;
	}
}
    return firstImage;
}
Exemplo n.º 3
0
int main()
{
	// Load in.png
	PNG * original = new PNG;

	original -> readFromFile("in.png");
	int width  = original->width();
	int height = original->height();

	cout << "width=" << width << " height=" << height << endl;

	// Create out.png
	PNG * output;
	output = setupOutput(width, height);	

	// Loud our favorite color to color the outline
	RGBAPixel * myPixel = myFavoriteColor(192);
	// Go over the whole image, and if a pixel differs from that to its upper
	// left, color it my favorite color in the output
	for (int y = 1; y < height; y++)
	{
		for (int x = 1; x < width; x++)
		{
			// Calculate the pixel difference
			RGBAPixel * prev = (*original)(x - 1, y - 1);
			RGBAPixel * curr = (*original)(x, y);
			int diff = abs(curr->red   - prev->red  ) +
					   abs(curr->green - prev->green) +
					   abs(curr->blue  - prev->blue );

			// If the pixel is an edge pixel,
			// color the output pixel with my favorite color
			RGBAPixel * currOutPixel = (*output)(x,y);
			if (diff > 100) {
				currOutPixel->blue = myPixel->blue;
				currOutPixel->red = myPixel->red;
				currOutPixel->green = myPixel->green;
			}
		}
	}
	
	// Save the output file
	output->writeToFile("out.png");

	// Clean up memory
	delete myPixel;
	delete output;
	delete original;
	return 0;
}
Exemplo n.º 4
0
void testReverse()
{
	cout << "[main]: " << __func__ << "()" << endl;
	PNG in;
	in.readFromFile("in_02.png");

	List<RGBAPixel> list = imageToList(in);
	list.reverse();

	PNG out = listToImage(list, in.width(), in.height());
	out.writeToFile("reverse.png");

	checkSoln(__func__, out, "soln_reverse.png");
}
Exemplo n.º 5
0
/**
 * This function brightens a rectangle of a PNG, increasing the components
 * (red, green, blue) of each pixel by the given amount. You must account
 * for potential overflow issues (color components can only store numbers
 * between 0 and 255). If you attempt to store a value greater than 255
 * into a color component, the result will wrap around (and you won't be
 * able to check if it was greater than 255).
 *
 * @param original A PNG object which holds the image data to be modified.
 * @param amount The integer amount by which to increase each pixel's
 * components.
 *
 * @return The brightened image.
 */
PNG brighten(PNG original, int amount)
{
    /// You can assume amount is positive.
    for (size_t yi = 0; yi < original.height(); yi++)
    {
        for (size_t xi = 0; xi < original.width(); xi++)
        {
            /// Your code here!
            //original(xi,yi)->red = 0;
	    //original(xi,yi)->blue = 0;
	}
    }
    return original;
}
Exemplo n.º 6
0
 PNG rotate(PNG original, PNG result)
{ //this function rotate the original file 180 degree and return the result
  size_t height = original.height();
  size_t width = original.width();
  for (size_t yi = 0; yi < height; yi++)
    {
        for (size_t xi = 0; xi < width; xi++)
        {   result(width-xi-1,height-yi-1)->red = original(xi,yi)->red;
            result(width-xi-1,height-yi-1)->green = original(xi,yi)->green;
            result(width-xi-1,height-yi-1)->blue = original(xi,yi)->blue;
            result(width-xi-1,height-yi-1)->alpha = original(xi,yi)->alpha;
         }
     }
    return result;
}
Exemplo n.º 7
0
List<RGBAPixel> imageToList(PNG const & img, bool reverse = false)
{
	List<RGBAPixel> list;
	for (int i = 0; i < img.width(); i++)
	{
		for (int j = 0; j < img.height(); j++)
		{
			if (reverse)
				list.insertFront(*img(i,j));
			else
				list.insertBack(*img(i,j));
		}
	}
	return list;
}
Exemplo n.º 8
0
/**
 * Flips an image around a horizontal axis in-place.
 * @param image - the image to flip
 */
void Flipper::flipSerial(PNG & image)
{
    RGBAPixel temp;
    int height = image.height(); 
    int width = image.width();
    
    for(int i = 0; i < width; ++i)
    {
        for(int j = 0; j < height / 2; ++j)
        {
            temp = *image(i, j);
            *image(i, j) = *image(i, height - 1 - j);
            *image(i, height - 1 - j) = temp;
        }
    }
}
Exemplo n.º 9
0
/**
 * Flips an image around a horizontal axis in-place.
 * @param image - the image to flip
 */
void Flipper::flipParallel(PNG & image)
{
    // TODO: parallelize the code below

    //RGBAPixel temp;
    int height = image.height(); 
    int width = image.width();
    
    #pragma omp parallel for 
    for(int i = 0; i < width; ++i)
    {
        for(int j = 0; j < height / 2; ++j)
        {
            RGBAPixel temp = *image(i, j);
            *image(i, j) = *image(i, height - 1 - j);
            *image(i, height - 1 - j) = temp;
        }
    }
}
Exemplo n.º 10
0
/**
 * Flips the source image into a new PNG.
 * THIS FUNCTION IS GRADED.
 * @todo - parallelize verticalFlip()
 * @param source - the original PNG
 * @return - a copy of the parameter that has been flipped
 *  over the vertical axis
 */
PNG ImageTools::verticalFlip(const PNG & source)
{	
    int width = source.width();
    int height = source.height();
    PNG output(width, height);
    #pragma omp parallel for
    for(int i = 0; i < width; ++i)
    {
	
        for(int j = 0; j < height; ++j)
        {
            // flip! 
		output(i,j)->red=source(width-i-1,j)->red;
		output(i,j)->green=source(width-i-1,j)->green;
		output(i,j)->blue=source(width-i-1,j)->blue;
        }
    }

    return output;
}
Exemplo n.º 11
0
/**
 * This function brightens a rectangle of a PNG, increasing the components
 * (red, green, blue) of each pixel by the given amount. You must account
 * for potential overflow issues (color components can only store numbers
 * between 0 and 255). If you attempt to store a value greater than 255
 * into a color component, the result will wrap around (and you won't be
 * able to check if it was greater than 255).
 *
 * @param original A PNG object which holds the image data to be modified.
 * @param amount The integer amount by which to increase each pixel's
 * components.
 *
 * @return The brightened image.
 */
PNG brighten(PNG original, int amount)
{
    /// You can assume amount is positive.
    for (size_t yi = 0; yi < original.height(); yi++)
    {
        for (size_t xi = 0; xi < original.width(); xi++)
        {
            if(original(xi, yi)->red+amount<=255){
	original(xi, yi)->red = original(xi, yi)->red+amount;}
	else original(xi, yi)->red = 255;
	if(original(xi, yi)->green+amount<=255){
	original(xi, yi)->green = original(xi, yi)->green+amount;}
	else original(xi, yi)->green = 255;
	if(original(xi, yi)->blue+amount<=255){
	original(xi, yi)->blue = original(xi, yi)->blue+amount;}
	else original(xi, yi)->blue = 255;
	    
        }
    }
    return original;
}
Exemplo n.º 12
0
Arquivo: main.cpp Projeto: Yankkk/C-
/**
 * This function blends, or averages, two PNGs together. That is, each pixel in
 * the returned image consists of the averaged components (red, green, blue) of
 * the two input images.
 *
 * @param firstImage  The first of the two PNGs to be averaged together.
 * @param secondImage The second of the two PNGs to be averaged together.
 *
 * @return The averaged image.
 */
PNG blendImages(PNG firstImage, PNG secondImage)
{
    for(size_t x = 0; x < firstImage.width(); x++){
	for(size_t y = 0; y < firstImage.height(); y++){
		size_t r1 = firstImage(x, y) ->red;
		size_t r2 = secondImage(x, y) ->red;
		size_t g1 = firstImage(x, y) ->green;
		size_t g2 = secondImage(x, y) ->green;
		size_t b1 = firstImage(x, y) ->blue;
		size_t b2 = secondImage(x, y) ->blue;
		size_t r = (r1 + r2)/2;
		size_t g = (g1 + g2)/2;
		size_t b = (b1 + b2)/2;
		firstImage(x,y) ->red = r;
		firstImage(x,y) ->green = g;
		firstImage(x,y) ->blue = b;
	}
    }    
	/// Your code here!
    return firstImage;
}
Exemplo n.º 13
0
/**
 * This function blends, or averages, two PNGs together. That is, each pixel in
 * the returned image consists of the averaged components (red, green, blue) of
 * the two input images.
 *
 * @param firstImage  The first of the two PNGs to be averaged together.
 * @param secondImage The second of the two PNGs to be averaged together.
 *
 * @return The averaged image.
 */
PNG blendImages(PNG firstImage, PNG secondImage)
{
    /// Your code here!
	  for (size_t yi = 0; yi < firstImage.height(); yi++)
    		{
       		 for (size_t xi = 0; xi < firstImage.width(); xi++)
        		{
				int c1 = firstImage(xi, yi)->red;
		                int c2 = secondImage(xi, yi)->red;
				int c3=(c1+c2)/2;
				firstImage(xi,yi)->red= c3;
				 c1 = firstImage(xi, yi)->blue;
		                 c2 = secondImage(xi, yi)->blue;
				 c3=(c1+c2)/2;
				firstImage(xi,yi)->blue= c3;	
				c1 = firstImage(xi, yi)->green;
		                 c2 = secondImage(xi, yi)->green;
				 c3=(c1+c2)/2;
				firstImage(xi,yi)->green= c3;

			}
		}
    return firstImage;
}
Exemplo n.º 14
0
animation filler::fill( PNG & img, int x, int y,
        colorPicker & fillColor, int tolerance, int frameFreq ) 
{
	OrderingStructure<RGBAPixel> sq; //pixel structure
	OrderingStructure<int> sqX; //Xcoord structure
	OrderingStructure<int> sqY; //Ycoord structure
	int** marks = new int *[img.width()]; //array of pointers with size width 0 1 2 3
	for(int i = 0; i < img.width(); i++) //array of pointers to arrays of size height x = 0->y = 0 1
	{
		marks[i] = new int[img.height()];
		for(int j = 0; j < img.height(); j++) //set coordinates to mark values e.g 0,1 = 0
			marks[i][j] = 0;
	}

	int count = 0; //count when to add new frame
	animation fillAnimation; //animation to return

	RGBAPixel origin = (*img(x,y));
	sq.add(origin);
	sqX.add(x);
	sqY.add(y);

	while(!sq.isEmpty())
	{
		RGBAPixel pixel = sq.remove();
		int xCoord = sqX.remove();
		int yCoord = sqY.remove();

		int originRed = origin.red, pixelRed = pixel.red, 
			originBlue = origin.blue, pixelBlue = pixel.blue,
			originGreen = origin.green, pixelGreen = pixel.green; 

		int toleranceValue = pow((originRed - pixelRed), 2) + 
			pow((originBlue - pixelBlue), 2) + 
			pow((originGreen - pixelGreen), 2);

		if(marks[xCoord][yCoord] == 0 && toleranceValue <= tolerance)
		{	

			marks[xCoord][yCoord] = 1;
			count++;
			*img(xCoord,yCoord) = fillColor(xCoord,yCoord);

			if(count == frameFreq)
			{
				fillAnimation.addFrame(img);
				count = 0;
			}
		
		
			if(xCoord < img.width() - 1)
			{
				sqX.add(xCoord + 1);
				sqY.add(yCoord);
				sq.add(*img(xCoord+1,yCoord));
			}

			if(yCoord < img.height() - 1)
			{
				sqX.add(xCoord);
				sqY.add(yCoord+1);
				sq.add(*img(xCoord,yCoord+1));
			}

			if(xCoord - 1 >= 0)
			{
				sqX.add(xCoord-1);
				sqY.add(yCoord);
				sq.add(*img(xCoord-1,yCoord));
			}

			if(yCoord - 1 >= 0)	
			{
				sqX.add(xCoord);
				sqY.add(yCoord-1);
				sq.add(*img(xCoord,yCoord-1));
			}
		}
	}
    return fillAnimation;
}
Exemplo n.º 15
0
animation filler::fill( PNG & img, int x, int y,
        colorPicker & fillColor, int tolerance, int frameFreq ) {
    /**
     * @todo You need to implement this function!
     *
     * This is the basic description of a flood-fill algorithm: Every fill
     * algorithm requires an ordering structure, which is passed to this
     * function via its template parameter. For a breadth-first-search
     * fill, that structure is a Queue, for a depth-first-search, that
     * structure is a Stack. To begin the algorithm, you simply place the
     * given point in the ordering structure. Then, until the structure is
     * empty, you do the following: 
     *
     * 1.     Remove a point from the ordering structure. 
     *
     *        If it has not been processed before and if its color is
     *        within the tolerance distance (up to and **including**
     *        tolerance away in square-RGB-space-distance) to the original
     *        point's pixel color [that is, \f$(currentRed - OriginalRed)^2 +
              (currentGreen - OriginalGreen)^2 + (currentBlue -
              OriginalBlue)^2 \leq tolerance\f$], then: 
     *        1.    indicate somehow that it has been processed (do not mark it
     *              "processed" anywhere else in your code) 
     *        2.    change its color in the image using the appropriate
     *              colorPicker
     *        3.    add all of its neighbors to the ordering structure, and 
     *        4.    if it is the appropriate frame, send the current PNG to the
     *              animation (as described below).
     * 2.     When implementing your breadth-first-search and
     *        depth-first-search fills, you will need to explore neighboring
     *        pixels in some order.
     *
     *        While the order in which you examine neighbors does not matter
     *        for a proper fill, you must use the same order as we do for
     *        your animations to come out like ours! The order you should put
     *        neighboring pixels **ONTO** the queue or stack is as follows:
     *        **RIGHT(+x), DOWN(+y), LEFT(-x), UP(-y). IMPORTANT NOTE: *UP*
     *        here means towards the top of the image, so since an image has
     *        smaller y coordinates at the top, this is in the *negative y*
     *        direction. Similarly, *DOWN* means in the *positive y*
     *        direction.** To reiterate, when you are exploring (filling out)
     *        from a given pixel, you must first try to fill the pixel to
     *        it's RIGHT, then the one DOWN from it, then to the LEFT and
     *        finally UP. If you do them in a different order, your fill may
     *        still work correctly, but your animations will be different
     *        from the grading scripts!
     * 3.     For every k pixels filled, **starting at the kth pixel**, you
     *        must add a frame to the animation, where k = frameFreq. 
     *
     *        For example, if frameFreq is 4, then after the 4th pixel has
     *        been filled you should add a frame to the animation, then again
     *        after the 8th pixel, etc.  You must only add frames for the
     *        number of pixels that have been filled, not the number that
     *        have been checked. So if frameFreq is set to 1, a pixel should
     *        be filled every frame.
     */
    
    animation mainframe;
    
    
    
    int row = img.height();
    int col = img.width(); 
    
    int xcord = x;
    int ycord = y;
        
    int counter = 0;
    
    //Every fill algorithm requires an ordering structure
    OrderingStructure <int> tempx;
    OrderingStructure <int> tempy;
    
    //making arrays for checking if pixel is processed already
    bool ** processed = new bool* [col];
    for(int i = 0; i < col; i++){
    	processed[i] = new bool[row];
    	for(int j = 0; j < row; j++){
    		processed[i][j] = false;
    	}
    }
    
  
    // you simply place the given point in the ordering structure
    tempx.add(xcord);
    tempy.add(ycord);
    
    
    
    RGBAPixel origin = *img(x,y);
    
    
	//Then, until the structure is empty, you do the following
    while(tempx.isEmpty() == false && tempy.isEmpty() == false){
    	
       	//Remove a point from the ordering structure.
    	xcord = tempx.peek();
    	ycord = tempy.peek();
        	
        
		tempx.remove();
		tempy.remove();	
    	
    	
    	int redval = img(xcord,ycord)->red-origin.red;
    	int greenval = img(xcord,ycord)->green-origin.green;
    	int blueval = img(xcord,ycord)->blue-origin.blue;
    	
    	
    	//If it has not been processed before and if its color is within the tolerance distance
    	if(!processed[xcord][ycord] ){
    		//indicate somehow that it has been processedprocessed[xcord][ycord] = true
    		processed[xcord][ycord] = true;
     		if (redval*redval + greenval*greenval + blueval*blueval <= tolerance){
				//change its color in the image using the appropriate colorPicker
				*img(xcord,ycord) = fillColor(xcord,ycord);
				
				
				//add all of its neighbors to the ordering structure
				if(xcord+1 < row && ycord < col ) {
					tempx.add(xcord+1);
					tempy.add(ycord);
					}
				if(xcord < row  && ycord + 1 < col ) {
					tempx.add(xcord);
					tempy.add(ycord+1);
					}
				if(xcord-1 >= 0 && xcord-1 < row && ycord < col ) {
					tempx.add(xcord-1);
					tempy.add(ycord);
					}
				if(xcord < row && ycord-1 < col && ycord -1 >= 0 ) {
					tempx.add(xcord);
					tempy.add(ycord-1);
					}
				
			
			//if it is the appropriate frame, send the current PNG to the animation 
				counter++;
				if(counter % frameFreq == 0){
					counter = 0;
					mainframe.addFrame(img);
				} 
			}
			
		}
		
		
    }
       
   	for(int i = 0; i < col; i++){
    	delete [] processed[i];
    } 
    
    delete [] processed;
       
    return mainframe;

}
Exemplo n.º 16
0
animation filler::fill( PNG & img, int x, int y,
        colorPicker & fillColor, int tolerance, int frameFreq ) {
    /**
     * @todo You need to implement this function!
     *
     * This is the basic description of a flood-fill algorithm: Every fill
     * algorithm requires an ordering structure, which is passed to this
     * function via its template parameter. For a breadth-first-search
     * fill, that structure is a Queue, for a depth-first-search, that
     * structure is a Stack. To begin the algorithm, you simply place the
     * given point in the ordering structure. Then, until the structure is
     * empty, you do the following:
     *
     * 1.     Remove a point from the ordering structure. 
     *
     *        If it has not been processed before and if its color is
     *        within the tolerance distance (up to and **including**
     *        tolerance away in square-RGB-space-distance) to the original
     *        point's pixel color [that is, \f$(currentRed - OriginalRed)^2 +
              (currentGreen - OriginalGreen)^2 + (currentBlue -
              OriginalBlue)^2 \leq tolerance\f$], then: 
     *        1.    indicate somehow that it has been processed (do not mark it
     *              "processed" anywhere else in your code) 
     *        2.    change its color in the image using the appropriate
     *              colorPicker
     *        3.    add all of its neighbors to the ordering structure, and 
     *        4.    if it is the appropriate frame, send the current PNG to the
     *              animation (as described below).
     * 2.     When implementing your breadth-first-search and
     *        depth-first-search fills, you will need to explore neighboring
     *        pixels in some order.
     *
     *        While the order in which you examine neighbors does not matter
     *        for a proper fill, you must use the same order as we do for
     *        your animations to come out like ours! The order you should put
     *        neighboring pixels **ONTO** the queue or stack is as follows:
     *        **RIGHT(+x), DOWN(+y), LEFT(-x), UP(-y). IMPORTANT NOTE: *UP*
     *        here means towards the top of the image, so since an image has
     *        smaller y coordinates at the top, this is in the *negative y*
     *        direction. Similarly, *DOWN* means in the *positive y*
     *        direction.** To reiterate, when you are exploring (filling out)
     *        from a given pixel, you must first try to fill the pixel to
     *        it's RIGHT, then the one DOWN from it, then to the LEFT and
     *        finally UP. If you do them in a different order, your fill may
     *        still work correctly, but your animations will be different
     *        from the grading scripts!
     * 3.     For every k pixels filled, **starting at the kth pixel**, you
     *        must add a frame to the animation, where k = frameFreq. 
     *
     *        For example, if frameFreq is 4, then after the 4th pixel has
     *        been filled you should add a frame to the animation, then again
     *        after the 8th pixel, etc.  You must only add frames for the
     *        number of pixels that have been filled, not the number that
     *        have been checked. So if frameFreq is set to 1, a pixel should
     *        be filled every frame.
     */
	OrderingStructure<RGBAPixel> pixels; //structure to return
    	OrderingStructure<int> cx;		//x axis
    	OrderingStructure<int> cy;		//y axis
    	bool process[img.width()][img.height()];
    for (int i = 0; i < img.width(); i++)
    {
        for (int j = 0; j <img.height(); j++)
        {
            process[i][j] = false;
        }
    }
	 animation anim;		//output
    int frame = 0;

    RGBAPixel origPixel = *(img(x,y));	//one pix to input
    int origRed = origPixel.red;
    int origGreen = origPixel.green;
    int origBlue = origPixel.blue;
	pixels.add(*img(x,y));//put into
    	cx.add(x);
    	cy.add(y);

    while (!pixels.isEmpty())
    {
        //remove one point in the structure
        RGBAPixel currPixel = pixels.remove();

        int currRed = currPixel.red;
        int currGreen = currPixel.green;
        int currBlue = currPixel.blue;
        int currX = cx.remove();
        int currY = cy.remove();
	 int min = pow(origRed-currRed,2)+pow(origGreen-currGreen,2)+pow(origBlue-currBlue,2);
	if ((min <= tolerance) && !process[currX][currY])
        {
	process[currX][currY] = true;//mark
         frame++;
	*(img(currX,currY)) = fillColor(currX,currY);
	  if (currX+1 <img.width())
            {
            //RIGHT
            pixels.add(*(img(currX+1,currY)));
            cx.add(currX+1);
            cy.add(currY);
            }
            
            if (currY+1 <img.height())
            {
            //DOWN
            pixels.add(*(img(currX,currY+1)));
            cx.add(currX);
            cy.add(currY+1);
            }

            if (currX-1>= 0)
            {
            //LEFT
            pixels.add(*(img(currX-1,currY)));
            cx.add(currX-1);
            cy.add(currY);
            }

            if (currY-1>= 0)
            {
            //DOWN
            pixels.add(*(img(currX,currY-1)));
            cx.add(currX);
            cy.add(currY-1);
            }
		 if (frame % frameFreq == 0)
            {
                //add the current image to the animation
                anim.addFrame(img);
            }
     }
    }
    return anim;
}
Exemplo n.º 17
0
animation filler::fill( PNG & img, int x, int y,
        colorPicker & fillColor, int tolerance, int frameFreq ) {
    /**
     * @todo You need to implement this function!
     *
     * This is the basic description of a flood-fill algorithm: Every fill
     * algorithm requires an ordering structure, which is passed to this
     * function via its template parameter. For a breadth-first-search
     * fill, that structure is a Queue, for a depth-first-search, that
     * structure is a Stack. To begin the algorithm, you simply place the
     * given point in the ordering structure. Then, until the structure is
     * empty, you do the following:
     *
     * 1.     Remove a point from the ordering structure. 
     *
     *        If it has not been processed before and if its color is
     *        within the tolerance distance (up to and **including**
     *        tolerance away in square-RGB-space-distance) to the original
     *        point's pixel color [that is, \f$(currentRed - OriginalRed)^2 +
              (currentGreen - OriginalGreen)^2 + (currentBlue -
              OriginalBlue)^2 \leq tolerance\f$], then: 
     *        1.    indicate somehow that it has been processed (do not mark it
     *              "processed" anywhere else in your code) 
     *        2.    change its color in the image using the appropriate
     *              colorPicker
     *        3.    add all of its neighbors to the ordering structure, and 
     *        4.    if it is the appropriate frame, send the current PNG to the
     *              animation (as described below).
     * 2.     When implementing your breadth-first-search and
     *        depth-first-search fills, you will need to explore neighboring
     *        pixels in some order.
     *
     *        While the order in which you examine neighbors does not matter
     *        for a proper fill, you must use the same order as we do for
     *        your animations to come out like ours! The order you should put
     *        neighboring pixels **ONTO** the queue or stack is as follows:
     *        **RIGHT(+x), DOWN(+y), LEFT(-x), UP(-y). IMPORTANT NOTE: *UP*
     *        here means towards the top of the image, so since an image has
     *        smaller y coordinates at the top, this is in the *negative y*
     *        direction. Similarly, *DOWN* means in the *positive y*
     *        direction.** To reiterate, when you are exploring (filling out)
     *        from a given pixel, you must first try to fill the pixel to
     *        it's RIGHT, then the one DOWN from it, then to the LEFT and
     *        finally UP. If you do them in a different order, your fill may
     *        still work correctly, but your animations will be different
     *        from the grading scripts!
     * 3.     For every k pixels filled, **starting at the kth pixel**, you
     *        must add a frame to the animation, where k = frameFreq. 
     *
     *        For example, if frameFreq is 4, then after the 4th pixel has
     *        been filled you should add a frame to the animation, then again
     *        after the 8th pixel, etc.  You must only add frames for the
     *        number of pixels that have been filled, not the number that
     *        have been checked. So if frameFreq is set to 1, a pixel should
     *        be filled every frame.
     */
	OrderingStructure <int> xCoordinates;
	OrderingStructure <int> yCoordinates;
	animation myAnimation;
	int frameCount = 0;
	std::vector <bool> checkArray(img.height()*img.width());
	for (size_t i = 0; i < img.height(); i++)
	{
		for(size_t j = 0; j < img.width(); j++)
		{
			checkArray[i*img.width()+j] = false;
		}
	}
	xCoordinates.add(x);
	yCoordinates.add(y);
	int origin_r = img(x,y)->red;
 	int origin_g = img(x,y)->green;
        int origin_b = img(x,y)->blue;

	while(!xCoordinates.isEmpty())
	{
		int currX = xCoordinates.remove();
		int currY = yCoordinates.remove();
		RGBAPixel currPixel = *img(currX,currY);
		int colorDistance = pow(currPixel.red-origin_r,2) + pow(currPixel.green-origin_g,2) + pow(currPixel.blue -origin_b,2);	
		if((!checkArray[currY*img.width()+currX])&& colorDistance <= tolerance)
		{
			checkArray[currY*img.width()+currX] = true;
			RGBAPixel tempPixel = fillColor(currX,currY);
			img(currX,currY)->red = tempPixel.red;
			img(currX,currY)->green = tempPixel.green;
			img(currX,currY)->blue = tempPixel.blue;
			//right
			if(currX + 1 < int(img.height()))
			{
				xCoordinates.add(currX+1);
				yCoordinates.add(currY);
			}
			//down
			if(currY + 1 < int(img.height()))
			{
				xCoordinates.add(currX);
				yCoordinates.add(currY+1);
			}
			//left
			if(currX - 1 >= 0)
			{
				xCoordinates.add(currX-1);
				yCoordinates.add(currY);
			}
			//up
			if(currY - 1 >= 0)
			{
				xCoordinates.add(currX);
				yCoordinates.add(currY-1);
			}			
			if((++frameCount) % frameFreq == 0) 
				myAnimation.addFrame(img);

		}	
	
	}
		
    	return myAnimation;	
}
Exemplo n.º 18
0
animation filler::fill(PNG& img, int x, int y, colorPicker& fillColor,
                       int tolerance, int frameFreq)
{
    /**
     * @todo You need to implement this function!
     *
     * This is the basic description of a flood-fill algorithm: Every fill
     * algorithm requires an ordering structure, which is passed to this
     * function via its template parameter. For a breadth-first-search
     * fill, that structure is a Queue, for a depth-first-search, that
     * structure is a Stack. To begin the algorithm, you simply place the
     * given point in the ordering structure. Then, until the structure is
     * empty, you do the following:
     *
     * 1.     Remove a point from the ordering structure.
     *
     *        If it has not been processed before and if its color is
     *        within the tolerance distance (up to and **including**
     *        tolerance away in square-RGB-space-distance) to the original
     *        point's pixel color [that is, \f$(currentRed - OriginalRed)^2 +
              (currentGreen - OriginalGreen)^2 + (currentBlue -
              OriginalBlue)^2 \leq tolerance\f$], then:
     *        1.    indicate somehow that it has been processed (do not mark it
     *              "processed" anywhere else in your code)
     *        2.    change its color in the image using the appropriate
     *              colorPicker
     *        3.    add all of its neighbors to the ordering structure, and
     *        4.    if it is the appropriate frame, send the current PNG to the
     *              animation (as described below).
     * 2.     When implementing your breadth-first-search and
     *        depth-first-search fills, you will need to explore neighboring
     *        pixels in some order.
     *
     *        While the order in which you examine neighbors does not matter
     *        for a proper fill, you must use the same order as we do for
     *        your animations to come out like ours! The order you should put
     *        neighboring pixels **ONTO** the queue or stack is as follows:
     *        **RIGHT(+x), DOWN(+y), LEFT(-x), UP(-y). IMPORTANT NOTE: *UP*
     *        here means towards the top of the image, so since an image has
     *        smaller y coordinates at the top, this is in the *negative y*
     *        direction. Similarly, *DOWN* means in the *positive y*
     *        direction.** To reiterate, when you are exploring (filling out)
     *        from a given pixel, you must first try to fill the pixel to
     *        it's RIGHT, then the one DOWN from it, then to the LEFT and
     *        finally UP. If you do them in a different order, your fill may
     *        still work correctly, but your animations will be different
     *        from the grading scripts!
     * 3.     For every k pixels filled, **starting at the kth pixel**, you
     *        must add a frame to the animation, where k = frameFreq.
     *
     *        For example, if frameFreq is 4, then after the 4th pixel has
     *        been filled you should add a frame to the animation, then again
     *        after the 8th pixel, etc.  You must only add frames for the
     *        number of pixels that have been filled, not the number that
     *        have been checked. So if frameFreq is set to 1, a pixel should
     *        be filled every frame.
     */
    OrderingStructure<int> xcoord;
    OrderingStructure<int> ycoord;
    xcoord.add(x);
    ycoord.add(y);

    animation a;
    int counter = 0;
    
    int h = img.height();
    int w = img.width();
    bool** processed = new bool*[h];
    for (int i = 0; i < h; i++){
	processed[i] = new bool[w];
	for (int j = 0; j < w; j++){
	    processed[i][j] = false;
	}
    }

    int oriRed = img(x,y) -> red;
    int oriGreen = img(x,y) -> green;
    int oriBlue = img(x,y) -> blue;

    while (!xcoord.isEmpty() && !ycoord.isEmpty()){
	x = xcoord.remove();
	y = ycoord.remove();
	
	int curRed = img(x,y) -> red;
	int curGreen = img(x,y) -> green;
	int curBlue = img(x,y) -> blue;

	int colorDist = (curRed - oriRed)*(curRed - oriRed) + (curGreen - oriGreen)*(curGreen - oriGreen) + (curBlue - oriBlue)*(curBlue - oriBlue);
	if (!processed[y][x] && colorDist <= tolerance){
	    processed[y][x] = true;

   	    img(x,y) -> red = fillColor(x,y).red;
	    img(x,y) -> green = fillColor(x,y).green;
	    img(x,y) -> blue = fillColor(x,y).blue;	

	    if (x + 1 < w && !processed[y][x+1]){
		xcoord.add(x + 1); 
		ycoord.add(y);
	    }

	    if (y + 1 < h && !processed[y+1][x]){
		xcoord.add(x);
		ycoord.add(y + 1);
	    }

	    if (x - 1 >= 0 && !processed[y][x-1]){
		xcoord.add(x - 1);
		ycoord.add(y);
	    }
	
	    if (y - 1 >= 0 && !processed[y-1][x]){
		xcoord.add(x);
		ycoord.add(y - 1);
	    }

	    counter++;
	    if (counter % frameFreq == 0)
		a.addFrame(img);
	}
    }
 
    for (int i = 0; i < h; i++)
	delete [] processed[i];
    delete [] processed;

    return a;
}
Exemplo n.º 19
0
animation DFSfill(PNG& img, int x, int y, colorPicker & fillColor, int tolerance, int frameFreq)
{
  animation anim;
  int count = 0;
  if( x > img.width()-1 || y > img.height()-1)
	return anim;

  
  bool done[img.width()][img.height()];
  for(int i=0;i < img.width();i++)
	for(int j=0;j < img.height();j++)
  {
	 done[i][j] = false;
  }

  int origred = img(x,y)->red;
  int origgreen = img(x,y)->green;
  int origblue = img(x,y)->blue;
  int redsqr = 0;
  int grnsqr = 0;
  int blusqr = 0;

  int tolcheck = 0;

  Stack<int> rackx;
  Stack<int> racky;
  int a = 0;
  int b = 0;

  rackx.push(x);
  racky.push(y);
  //done[x][y]= true;
		
  while(!(rackx.isEmpty()))
  {
    a = rackx.pop();
	b = racky.pop();

	redsqr = (img(a,b)->red-origred) * (img(a,b)->red-origred);
	grnsqr = (img(a,b)->green-origgreen) * (img(a,b)->green-origgreen);
  	blusqr = (img(a,b)->blue-origblue) * (img(a,b)->blue-origblue);
   
    tolcheck = redsqr + grnsqr + blusqr;
	if((tolcheck <= tolerance && !done[a][b]))
	{
		*img(a,b) = fillColor(a,b); 
		count++;
	

	//done[a][b] = true;	

    	if(a+1 < img.width())
		{		
    		if(!done[a+1][b])
			{
				rackx.push(a+1);
				racky.push(b);
			//done(right[0],right[1]) = tru
			}
		}
		if(b+1 < img.height())
		{
			if(!done[a][b+1])
			{
				rackx.push(a);
				racky.push(b+1);
			}
		}

		if(a-1 > 0)
		{
			if(!done[a-1][b])
			{
				rackx.push(a-1);
				racky.push(b);
			}
		}
		if(b-1 > 0)
		{
			if(!done[a][b-1])
			{
				rackx.push(a);
				racky.push(b-1);
			}
		}
	}
	done[a][b] = true;
	
	if(frameFreq == count )
	{
		anim.addFrame(img);
		count = 0;
	}
  }
  return anim;
}