// GUI calls this function when a user left-clicks on an image pixel while in "Region" mode
// The method computes a 'region' of pixels connected to 'seed'. The region is grown by adding
// to each pixel p (starting at 'seed') all neighbors q such that intensity difference is small,
// that is, |Ip-Iq|<T where T is some fixed threshold. Use Queue for active front. 
// HINT: to compute intensity difference Ip-Iq, use function dI(RGB,RGB) defined in "Image2D.h"   
void regionGrow(Point seed, double T)
{
	if (!image.pointIn(seed)) return;
	int counter = 0;                  
	Queue<Point> active;        
	active.enqueue(seed);
	
	// use BREADTH-FIRST_SEARCH (FIFO order) traversal - "Queue"
    //..
	while (!active.isEmpty())
	{
		Point p = active.dequeue();
		region[p]=1;  
		counter++;
		for (int i=0; i<4; i++)
		{   
			Point q = p + shift[i]; 
			if (image.pointIn(q) && region[q]==0 && dI(image[q], image[seed])>(T*-1) && dI(image[q], image[seed])<T) 
			{ 
				active.enqueue(q); 
				region[q]=2;  
			}                 
		}                     
		if (view && counter%60==0) {draw(); Pause(20);}
	}

	cout << "grown region of volume " << counter << " pixels    (threshold  " << T << ")" << endl;
}
Beispiel #2
0
void FeaturesGrid::reset(Table2D<RGB> & im, FEATURE_TYPE ft, float w) 
{
	cout << "resetting data... " << endl;
	int height = im.getHeight(), width =  im.getWidth();
	Point p;
	m_seeds.reset(width,height,NO_LABEL); 
	m_labeling.reset(width,height,NO_LABEL); // NOTE: width and height of m_labeling table 
	                                         // are used in functions to_index() and to_Point(), 

	m_dim=0;
	m_means.clear();
	m_features.clear();      // deleting old features
	m_features.resize(width*height); // creating a new array of feature vectors

	if (ft == color || ft == colorXY) {
		m_dim+=3;  // adding color features
		for (int y=0; y<height; y++) for (int x=0; x<width; x++) { 
			pix_id n = to_index(x,y);
			m_features[n].push_back((double) im[x][y].r);
			m_features[n].push_back((double) im[x][y].g);
			m_features[n].push_back((double) im[x][y].b);
		}
	}
	if (ft == colorXY) {
		m_dim+=2;  // adding location features (XY)
		for (int y=0; y<height; y++) for (int x=0; x<width; x++) { 
			pix_id n = to_index(x,y);
			m_features[n].push_back((double) w*x);
			m_features[n].push_back((double) w*y);
		}
	}

	cout << "done" << endl;
}
Beispiel #3
0
void FeaturesGrid::addFeature(Table2D<double> & im)
{
	m_dim++; // adding extra feature (increasing dimensionality of feature vectors
	int height = im.getHeight(), width =  im.getWidth();
	for (int y=0; y<height; y++) for (int x=0; x<width; x++) { 
		pix_id n = to_index(x,y);
		m_features[n].push_back(im[x][y]);
	}

}
Beispiel #4
0
// GUI calls this function when button "Clear" is pressed, or when new image is loaded
void reset_segm()
{
	cout << "resetting 'contour' and 'region'" << endl;
	// removing all region markings
	region.reset(im.getWidth(),im.getHeight(),0);

	// add your code below to remove all points from the "contour"
	while(!contour.isEmpty())
		contour.popBack();

	closedContour = false;
}
Beispiel #5
0
void TableFactory::ReadFileHonda(const char* fname, unsigned ny,Table2D& table){
    // printf("reading file %s (for Y[%d])\n",fname,ny);
    std::ifstream inf;
    inf.open(fname);
    if(!inf.good()) throw MRexception("Error opening file: \""+std::string(fname)+"\"");
    double p,mplus,mminus;
    for (auto nx:Axis::Bins(table.GetXaxis()))
    {
        inf>>p>>mplus>>mminus;
        if(inf.fail()){
            throw MRexception("Failed reading from file");
        }
        table.SetPoint(nx,ny,mplus+mminus);
    }
    inf.close();
}
Beispiel #6
0
// GUI calls this function when a user right-clicks on an image pixel while in "Region" mode.
// It marks in 'region' a set of same-color pixels adjacent to the 'seed'. The neighboring pixels 
// are traversed using DEPTH-FIRST-SEARCH starting at the 'seed'. 
// Unlike previous function "addSquare()", the shape of the added region depends on the image. 
void floodFill_DFS(Point seed)
{
	int counter = 0;                   
	Stack<Point> active_front;        
	active_front.push(seed);
	
	// "mark" all adjecent pixels of the same color in 2D table "region" while traversing them 
	// using DEPTH-FIRST_SEARCH (LIFO order) traversal - use "Stack"
	while (!active_front.isEmpty())
	{
		Point p = active_front.pop();
		region[p]=1;  // pixel p is extracted from the "active_front" and added to "region", but
		counter++;    // then, all "appropriate" neighbors of p are added to "active_front" (below)
		for (int i=0; i<4; i++) // goes over 4 neighbors of pixel p
		{   // uses overloaded operator "+" for Points (see Basics2D.h) and array of 'shifts' (see the top of file)
			Point q = p + shift[i]; // to compute a "neighbor" of pixel p
			if (im.pointIn(q) && region[q]==0 && im[q]==im[seed]) 
			{ // we checked if q is inside image range and that its "color" matches "seed"
			  // Why do we also need condition region[q]==0 ???? 
				active_front.push(q); 
				region[q]=2;  // "region" value 2 is used in "draw()" to visualise pixels that are 
			}                 // inside "active_front"; note that all pixels in "active front"
		}                     // are eventually extracted and their "region" value is set to 1. 
		if (view && counter%60==0) {draw(); Pause(20);} // visualization, skipped if checkbox "view" is off
	}
	cout << "flood filled region of size " << counter << " using DFS traversal (LIFO order, Stack)" << endl;
}
// This function is called at the end of "addToContourLast()". Function 
// "contourInterior()" returns volume of the closed contour's interior region 
// (including points on the contor itself), or -1 if contour is not closed yet.
// HINT: live-wire() adds to the contour "water-tight" paths of neighboring pixels 
int contourInterior()
{
	if (!closedContour || image.isEmpty()) return -1;
	int counter = 0;

	// write your code for computing correct mask (region)
	// which should have 3 for pixels OUTSIDE the contour and 0
	// for pixels INSIDE of the contour
	// HINT: "grow" the "exterior region" from a single exterior point (e.g. a corner of the image). 
	// Make sure that the region does not grow across the contour (points in list "contour")
	// ...
	Queue<Point> active;
	Point q(1,1);
	active.enqueue(q);
	region.reset(0);
	for (unsigned i=1; i<=contour.getLength(); i++)
		region[contour.retrieve(i)]=2;
	while (!active.isEmpty())
	{
		Point p = active.dequeue();
		region[p]=3;  
		counter++;
		for (int i=0; i<4; i++)
		{   
			Point j = p + shift[i]; 
			if (image.pointIn(j) && region[j]!=2 && region[j]!=3)
			{ 
				active.enqueue(j); 
				region[j]=3;  
			}                 
		}  
		if (view && counter%60==0) {draw(); Pause(20);}
	}
	for (unsigned i=1; i<=contour.getLength(); i++)
		region[contour.retrieve(i)]=0;

	return region.getWidth() * region.getHeight() - counter;
}
Beispiel #8
0
// GUI calls this function when a user middle-clicks on an image pixel while in "Region" mode
// It marks in 'region' a square-shaped subset of pixels adjecent to 'seed' (side=40)
void addSquare(Point seed)
{
	// The code below marks one pixel (seed.x,seed.y) as part of the "region."
	// (Note that draw() function in main.cpp displays all 'region=1' pixels in blue.)
    //
	// GOAL: Change the code below so that, instead of marking just one pixel,
	//       it marks pixels in a square around the seed.
	//       The square should have size 40x40 and be centered at (seed.x, seed.y).
	//
	region[seed]=1;  // seed is a Point; there are 2 overloaded operators[] in Table2D.h 
	                 // this line is equivalent to "region[seed.x][seed.y]=1;" 
	for(int i = -20; i<=20; i++)
		for(int j = -20; j<=20; j++)
			if(region.pointIn(seed.x +i, seed.y +j))
			{
				region[seed.x+i][seed.y+j]=2;
			}

	cout << "added a square region" << endl;
}
Beispiel #9
0
// GUI calls this function when a user left-clicks on an image pixel while in "Region" mode.
// It marks in 'region' a set of same-color pixels adjacent to the 'seed'. The neighboring pixels 
// are traversed using BREADTH-FIRST-SEARCH starting at the 'seed'. 
// This function differs from floodFill_DFS() only by the order of traversal of adjecent pixels.
void floodFill_BFS(Point seed)
{
    // INSTEAD OF CODE BELOW THAT MARKS ONLY ONE PIXEL IN "REGION"...

	// "mark" all adjecent pixels of the same color to 2D array "region" while traversing them 
	// using BREADTH-FIRST_SEARCH (FIFO order) - use "Queue" instead of "Stack"
    // ...

	int counter = 0;                   
	Queue<Point> active_front;        
	active_front.enqueue(seed);
	
	// "mark" all adjecent pixels of the same color in 2D table "region" while traversing them 
	// using DEPTH-FIRST_SEARCH (LIFO order) traversal - use "Stack"
	while (!active_front.isEmpty())
	{
		Point p = active_front.dequeue();
		region[p]=1;  // pixel p is extracted from the "active_front" and added to "region", but
		counter++;    // then, all "appropriate" neighbors of p are added to "active_front" (below)
		for (int i=0; i<4; i++) // goes over 4 neighbors of pixel p
		{   // uses overloaded operator "+" for Points (see Basics2D.h) and array of 'shifts' (see the top of file)
			Point q = p + shift[i]; // to compute a "neighbor" of pixel p
			if (im.pointIn(q) && region[q]==0 && im[q]==im[seed]) 
			{ // we checked if q is inside image range and that its "color" matches "seed"
			  // Why do we also need condition region[q]==0 ???? 
				active_front.enqueue(q); 
				region[q]=2;  // "region" value 2 is used in "draw()" to visualise pixels that are 
			}                 // inside "active_front"; note that all pixels in "active front"
		}                     // are eventually extracted and their "region" value is set to 1. 
		if (view && counter%60==0) {draw(); Pause(20);} // visualization, skipped if checkbox "view" is off
	}


	region[seed]=1; // equivalent to region[seed.x][seed.y]=1; (see Table2D.h)

	// replace the "cout" statement below to indicate the number of "marked" pixels added into "region" using BFS.
	cout << "added one pixel to region" << endl;
}
// GUI calls this function when button "Clear" is pressed, or when new image is loaded
// THIS FUNCTION IS FULLY IMPLEMENTED, YOU DO NOT NEED TO CHANGE THE CODE IN IT
void reset_segm()
{
	cout << "resetting 'contour' and 'region'" << endl;

	// removing all region markings
	region.reset(image.getWidth(),image.getHeight(),0);

	// remove all points from the "contour"
	while (!contour.isEmpty()) contour.popBack();
	closedContour=false;

	// resetting 2D tables "dist" and "toParent" (erazing paths) 
	dist.reset(image.getWidth(),image.getHeight(),INFTY);
	toParent.reset(image.getWidth(),image.getHeight(),NONE);

	// recomputing "penalties" from an estimate of image contrast at each pixel p=(x,y)
	if (image.isEmpty()) {penalty.resize(0,0); return;} 
	Table2D<double> contrast = grad2(image);  //(implicit conversion of RGB "image" to "Table2D<double>") 
	// NOTE: function grad2() (see Math2D.h) computes (at each pixel) expression  Ix*Ix+Iy*Iy  where Ix and Iy
	// are "horizontal" and "vertical" derivatives of image intensity I(x,y) - the average of RGB values.
	// This expression describes the "rate of change" of intensity, or local image "contrast". 
	penalty = convert(contrast,&fn); // "&fn" - address of function "fn" (defined at the top of this file) 
	// "convert" (see Math2D.h) sets penalty at each pixel according to formula "penalty[x][y] = fn (contrast[x][y])" 
}
///////////////////////////////////////////////////////////////////////////////////
// computePaths() is a function for "precomputing" live-wire (shortest) paths from 
// any image pixel to the given "seed". This method is called inside "addToContour" 
// for each new mouse click. Optimal path from any pixel to the "seed" should accumulate 
// the least amount of "penalties" along the path (each pixel p=(x,y) on a path contributes 
// penalty[p] precomputed in "reset_segm()"). In this function you should use 2D tables 
// "toParent" and "dist" that store for each pixel its "path-towards-seed" direction and, 
// correspondingly, the sum of penalties on that path (a.k.a. "distance" to the seed). 
// The function iteratively improves paths by traversing pixels from the seed until 
// all nodes have direction "toParent" giving the shortest (cheapest) path to the "seed".
void computePaths(Point seed)
{
	if (!image.pointIn(seed)) return;
	region.reset(0); // resets 2D table "region" for visualization

	// Reset 2D arrays "dist" and "toParent"  (erazing all current paths)
	dist.reset(INFTY);
	toParent.reset(NONE);
	dist[seed] = 0;
	int counter = 0; // just for info printed at the bottom of the function
	
	// THE CODE BELOW GENERATES 2d TABLE toParent WITH PATHS BASED ON           !!!!!!!!
	// BASIC BREDTH-FIRST_SEARCH TRAVERSAL FROM THE SEED. REPLACE THIS CODE     !!!!!!!!
	// SO THAT toParent CONTAINS PATHS FOLLOWING HIGH CONSTAST IMAGE BOUNDARIES !!!!!!!!
	// 
	// Create a queue (or priority_queue) for "active" points/pixels and 
	// traverse pixels to improve paths stored in "toParent" (and "dist") 
	// .....
	Queue<Point> active;         
	active.enqueue(seed);        
	while(!active.isEmpty()) 
	{
		Point p = active.dequeue();
		region[p]=1; 
		counter++;
		for (int i=0; i<4; i++) 
		{
			Point q = p+shift[i]; //using overloaded operator+ for Points (see "Basic2D.h")
			double t = dist[p] + penalty[p];
			if (image.pointIn(q) && t<dist[q])
			{  
				dist[q]=t;
                toParent[q]=Reverse[i]; 
				region[q]=2; // to visualize pixels added to the queue
				active.enqueue(q); 
			}
		}
		if (view && counter%60==0) {draw(); Pause(20);}  // visualization, skipped if checkbox "view" is off
	}
//	MY PRIORITY QUEUE METHOD WORKS IN THE SAME FASHION AS THE DEMO
//	IT IS SLOWER THAN MY QUEUE METHOD, BUT I AM UNSURE IF THIS IS
//	AN ISSUE WITH RELEASE MODE COMPARED TO DEBUG MODE
//	COMMENT OUT THE ABOVE QUEUE METHOD AND UNCOMMENT THE BELOW METHOD
//	TO TEST FUNCTIONALITY OF PRIORITY QUEUE METHOD
	/*priority_queue<MyPoint> active;
	MyPoint j(seed, dist[seed]);
	active.push(j);        
	while(!active.empty()) 
	{
		Point p = active.top();
		active.pop();
		region[p]=1;
		counter++;
		for (int i=0; i<4; i++) 
		{
			Point q = p+shift[i]; //using overloaded operator+ for Points (see "Basic2D.h")
			double t = dist[p] + penalty[p];
			if (image.pointIn(q) && t<dist[q])
			{  
				dist[q]=t;
                toParent[q]=Reverse[i]; 
				region[q]=2; // to visualize pixels added to the queue
				MyPoint b(q, dist[q]);
				active.push(b); 
			}
		}
		if (view && counter%60==0) {draw(); Pause(20);}  // visualization, skipped if checkbox "view" is off
	}*/

	// you can print out the number of times a point was removed from the queue
	cout << "paths computed,  number of 'pops' = " << counter 
		 <<  ",  number of pixels = " << (region.getWidth()*region.getHeight()) << endl; 
}