                        if (map != null) {
                                //int sstep = (int)(Math.pow(2, pyramid_levels - level - 2));
                                int sstep = (int)(Math.pow(2, pyramid_levels - level - 1));
                                int ws = pyr[level + 1].nx;							
                                int hs = pyr[level + 1].ny;
                                if (verify_neighbors (cx, cy, img.nx, img.ny, ws, hs, sstep, threshold, map)) {
                                        for (int x = cx - bstep/2; x <= cx + bstep/2; x += bstep/2) {
                                                for (int y = cy - bstep/2; y <= cy + bstep/2; y += bstep/2) {
                                                        if ((x - mx > 0) && (y - my > 0) && (x + mx - 1 < img.nx) && (y + my - 1 < img.ny)) {
                                                                FloatImage region = FloatImage.get_sub_image (img, x - mx, y - my, x + mx - 1, y + my - 1);
                                                                float val = (float)thog.score (region, trained_cls, hog_parameters, false);
                                                                res.set_pixel(x, y, val);	
                                                                if (val > threshold) {
                                                                        queue.add(new struct_grow (x, y, nlabels++));
                                                                }
                                                        }
                                                }
                                        }
                                }
                        }


    public static boolean verify_neighbors (int i, int j, int wb, int hb, int ws, int hs, int step, double threshold, double[] map) {
		Point p = image_functions.image_map_point_to_smaller_image (new Point(i,j), 1, 2, wb, hb);	
		for (int x = p.x - step/2; x <= p.x + step/2; x++) {
			for (int y = p.y - step/2; y <= p.y + step/2; y++) {
				int pos = y * ws + x;
				if ( (pos >= 0) && (pos < ws*hs) && (map[pos] > threshold) ) {					
					return true;
				}
			}
		}
		return false;
	}
	
	/* Find the number of levels {nlevels}: */
	public static int get_pyramid_levels (int reductionFactor, int width, int height, int window_x, int window_y)
	{
		int nlevels = 0;
		while ((height >= window_y) && (width >= window_x)) {
			nlevels++;
			height /= reductionFactor; width /= reductionFactor;
		}
		if (nlevels == 0) {
			System.err.printf("initial image is too small (%d x %d)\n", width, height);
			assert(false);
		}
		return nlevels;
	}
	
	public static void grow_candidate_text_regions (
			FloatImage vimage,
			int nlabels,
			int level,
			String output_image_file_name,			
			FloatImage image, 
			FloatImage wimage,
			int w, int h, 
			int hwindow_x, int hwindow_y, 
			double threshold,
			int labels[],
			Queue<struct_grow> queue,
			ArrayList<String> hog_parameters,
			Classifier<double[]> trained_cls ) {
		
		thog_desc thog = new thog_desc ();
		
		boolean[][] status = new boolean[w][h];
		
		for (int i = 0, n = 0; i < w; i++) {
			for (int j = 0; j < h; j++, n++) {
				status[i][j] = false;
				labels[n] = -1;
			}
		}
		
	public static FloatImage image_segmentation (
			FloatImage vimage,
			FloatImage wimage,
			int hwindow_x, int hwindow_y, 
			double threshold, int level, 
			FloatImage image, String output_image_file_name,
			int inv) {		

		int w = image.nx;		
		int h = image.ny;

		niblack filter = new niblack ();

		/*copy text regions candidates*/
		boolean ROI[] = new boolean[w*h];
		
		for (int k = 0; k < (w*h); k++) { ROI[k] = false; }
		
		for (int yy = 0; yy < h; yy++){
			for (int xx = 0; xx < w; xx++){
				int i = yy*w + xx;
				if (wimage.get_sample(0,xx,yy) > threshold) {
					for (int x = xx - hwindow_x; x < (xx + hwindow_x); x++) {
						for (int y = yy - hwindow_y; y < (yy + hwindow_y); y++) {
							int pos = y * w + x;
							if ((x > 0) && (y > 0) && (x < w) && (y < h)) {
								ROI[pos] = true;
							}
						}
					}
				}
			}
		}

		/*Niblack*/
		
		int option = 1;
		
		/* !!! No need for toggle mapping now !!! */
		FloatImage bin = null;
		if (option == 0) {
		    bin = new FloatImage(1, w, h);
		    FloatImage.fill(bin, (float)0.0);
	    }
		else{
			bin = Toggle.toggle (vimage, 20, 20, level);
		}
		
		for (int yy = 0; yy < h; yy++){
			for (int xx = 0; xx < w; xx++){
				int i = yy*w + xx;
				if (option == 0){
					  if (ROI[i]) { bin.set_pixel(xx, yy, filter.filter (vimage, xx, yy, true)); }
				} else {
					if (!ROI[i]) { bin.set_pixel(xx, yy, (float)0.0); }
				}
			}
		}
		
		FloatImage.write_as_pgm (bin, output_image_file_name + "_" + inv + "_bin" + level, (float)0.0, (float)1.0, FloatImage.DEFAULT_GAMMA);
		
		return bin;
	}
	
	
	/**/
	public static LinkedList<struct_label> filtering_large_region_overlap (LinkedList<struct_label> l, BufferedImage image, String output_image_file_name, int level, int inv) {

		int size = l.size();		

		/*initializing structures*/
		int id[] = new int[size]; 
		int cp[] = new int[size];
		LinkedList<struct_label> list = new LinkedList<struct_label>();		
		
		for (int k = 0; k < size; k++) { 
			l.get(k).id = k;
		}
		
		for (int k = 0; k < size; k++) { 
			list.add(struct_label.copy(l.get(k)));
			id[k] = list.get(k).id;
			cp[k] = list.get(k).id;
			//System.err.printf("B: id[%d] = %d\n", k, id[k]);
		}
		
		BufferedImage tmp = image_functions.copy_image(image);
		for (int i = 0; i < list.size(); i++) {
		    struct_label region = list.get(i);
			image_functions.draw_rectangle_and_label (tmp, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1, Integer.toString(region.id));			
		}	
		try {
			ImageIO.write(tmp, "png", new File(output_image_file_name + "_" + inv + "_over1_l" + level +".png"));			
		}
		catch (Exception e) { 
		}
		
		/*veryfing and relabeling similar candidate regions*/
		for (int i = 0; i < list.size() - 1; i++) {			
			struct_label ri = list.get(i);			
			for (int j = i+1; j < list.size(); j++) {				
				struct_label rj = list.get(j);
				//System.err.printf("Comparando: ri: %d e rj: %d (%d,%d,%d,%d) e (%d,%d,%d,%d)\n", ri.id, rj.id, ri.xmin, ri.ymin, ri.xmax, ri.ymax, rj.xmin, rj.ymin, rj.xmax, rj.ymax);
				
				if (struct_label.overlap(ri, rj)) {
					//System.err.printf("Tem overlap: ri: %d e rj: %d são compatíveis (%d,%d,%d,%d) e (%d,%d,%d,%d)\n", ri.id, rj.id, ri.xmin, ri.ymin, ri.xmax, ri.ymax, rj.xmin, rj.ymin, rj.xmax, rj.ymax);
					int ref = id[j];
					for (int k = 0; k < list.size(); k++) {					
						if (id[k] == ref) {
							//System.err.printf("id_k[%d] = %d,  id_j[%d] = %d, id_i[%d] = %d\n", k, id[k], j, id[j], i, id[i]);
							id[k] = id[i];
						}
					}
				}
			}
		}
		
		/*for (int k = 0; k < size; k++) {
			System.err.printf("A: id[%d] = %d\n", k, id[k]);
		}*/

		/*merging neighboring regions*/
		boolean in;
		do {
			in = false;
		for (int i = 0; i < size - 1; i++) {		
			for (int j = i + 1; j < size; j++) {
				if (id[i] == id[j]) {
					int p = -1;
					struct_label ri = null, rj = null;
					for (int k = 0; k < list.size(); k++) {
						if (cp[i] == list.get(k).id) {
							ri = list.get(k);
						}
						if (cp[j] == list.get(k).id) {
							rj = list.get(k);
							p = k;
						}
					}
					if ((ri != null) && (rj != null)) {
						struct_label.merge(ri, rj, list, false);
						list.remove(p);
						in = true;
					}					
				}
			}
		}
		} while (in);
		
		BufferedImage tmp2 = image_functions.copy_image(image);
		for (int i = 0; i < list.size(); i++) {
		    struct_label region = list.get(i);
			image_functions.draw_rectangle_and_label (tmp2, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1, Integer.toString(region.id));			
		}	
		try {
			ImageIO.write(tmp2, "png", new File(output_image_file_name + "_" + inv + "_over2_l" + level +".png"));			
		}
		catch (Exception e) { 
		}	
		
		/*BufferedImage tmp2 = image_functions.copy_image(image);
		for (int i = 0; i < l.get_label_list().size(); i++) {
		    struct_label region = l.get_label_list().get(i);
			image_functions.draw_rectangle (tmp2, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1);			
		}	
		try {
			ImageIO.write(tmp2, "png", new File(output_image_file_name + "_Rect_l" + level +".png"));			
		}
		catch (Exception e) { 
		}*/
		return list;
	}
	
	/**/
	public static LinkedList<struct_label> kruskal_chain_grouping (LinkedList<struct_label> list, BufferedImage image, String output_image_file_name, int level, int inv) {
		
		BufferedImage tmp = image_functions.copy_image(image);
		for (int i = 0; i < list.size(); i++) {
			struct_label region = list.get(i);
			image_functions.draw_rectangle_and_label (tmp, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1, Integer.toString(region.id));			
		}	
		try {
			ImageIO.write(tmp, "png", new File(output_image_file_name + "_" + inv + "_carac_l" + level +".png"));			
		}
		catch (Exception e) { 
		}
		
		int maximumVertices = list.size();		

    	/*initializing structures*/
		int id[] = new int[maximumVertices]; 
		
		for (int i = 0; i < maximumVertices; i++) {
			//struct_label ri = list.get(i);
			id[i] = i;//ri.id; 
		}
    	
    	Graph g = new Graph (maximumVertices);
    	for(int i = 0; i < maximumVertices; i++){
    		g.addVertex(i);
    	}		
    	
    	double min = 0.5;
    	
    	for (int i = 0; i < maximumVertices - 1; i++) {			
			struct_label ri = list.get(i);		
			for (int j = i+1; j < maximumVertices; j++) {				
				struct_label rj = list.get(j);
				double[] candidate = struct_label.similarity_metrics (ri, rj);
				double imin = struct_label.compute_euclidean_similarity (candidate);				
				if ((min > imin) && struct_label.similar(ri,rj,level)) {
					g.addBidirectionalEdge(i, j, imin);
				}
				else {
					g.addBidirectionalEdge(i, j, Double.MAX_VALUE);
				}
			}
    	}
    	
    	for (int i = 0; i < maximumVertices; i++) {			
			struct_label ri = list.get(i);		
    		System.err.printf("id[%d]: %d\n", i, ri.id);
    	}
    	
    	Kruskal k = new Kruskal(g);
    	List<Edge> mst = k.getMSTEdges();
    	java.util.ListIterator it = mst.listIterator();
    	while(it.hasNext()){
    		Edge e = (Edge)it.next();
    		System.err.println ("v" + e.getFrom().getVertexNo() + " --- v" + e.getTo().getVertexNo());
    		/*veryfing and relabeling similar candidate regions*/    	
    		int ref = id[e.getTo().getVertexNo()];
			for (int i = 0; i < maximumVertices; i++) {					
				if (id[i] == ref) {
					id[i] = id[e.getFrom().getVertexNo()];
				}
			}
			for (int i = 0; i < maximumVertices; i++) {						
	    		System.err.printf("id[%d]: %d\n", i, id[i]);
	    	}
    	}
		

    	LinkedList<LinkedList<struct_label>> lists = new  LinkedList<LinkedList<struct_label>>();
    	for (int i = 0; i < maximumVertices; i++) {	
    		LinkedList<struct_label> li = new LinkedList<struct_label>();
    		lists.add(li);
    	}
    	
    	for (int i = 0; i < maximumVertices; i++) {	
    		struct_label region = list.get(i);
    		lists.get(id[i]).add(region);
			System.err.printf("add na lista %d a regiao %d : id: %d\n", id[i], i, region.id);			
		}    	
    	
    	BufferedImage tmp4 = image_functions.copy_image(image);
    	for (int i = 0; i < lists.size(); i++) {
    		struct_label merge = null;
    		for (int j = 0; j < lists.get(i).size(); j++) {
    			struct_label region = lists.get(i).get(j);
    			merge = struct_label.Merge(merge, region);
    		}
    		if (merge != null) {			
    			image_functions.draw_rectangle_and_label (tmp4, merge.xmin, merge.ymin, merge.xmax - merge.xmin + 1, merge.ymax - merge.ymin + 1, Integer.toString(merge.id));
    		}	
    	}	
    	try {
    		ImageIO.write(tmp4, "png", new File(output_image_file_name + "_" + inv + "_rectA_l" + level +".png"));			
    	}
    	catch (Exception e) { 
    	}
    	
    	for (int i = 0; i < lists.size(); i++) {
    		LinkedList<struct_label> li = lists.get(i);
    		if (li.size() > 3) {
    			remove_chain_discrepancies (li);
    		}
    	}	

    	
    	BufferedImage tmp3 = image_functions.copy_image(image);
    	LinkedList<struct_label> final_list = new LinkedList<struct_label>();
    	for (int i = 0; i < lists.size(); i++) {
    		struct_label merge = null;
    		for (int j = 0; j < lists.get(i).size(); j++) {
    			struct_label region = lists.get(i).get(j);
    			merge = struct_label.Merge(merge, region);
    		}
    		if (merge != null) {
    			final_list.add(merge);				
    			image_functions.draw_rectangle_and_label (tmp3, merge.xmin, merge.ymin, merge.xmax - merge.xmin + 1, merge.ymax - merge.ymin + 1, Integer.toString(merge.id));
    		}	
    	}	
    	try {
    		ImageIO.write(tmp3, "png", new File(output_image_file_name + "_" + inv + "_rect_l" + level +".png"));			
    	}
    	catch (Exception e) { 
    	}

    	return final_list;
	}
	
	public static struct_label find_the_closest (int pr, struct_label r, LinkedList<struct_label> list)
	{		
		int p = -1;
		int size = list.size();
		double min = Double.MAX_VALUE;

		for (int i = 0; i < size; i++) {
			if (i != pr) {
				struct_label ri = list.get(i);
				double[] v = struct_label.similarity_metrics (ri, r);
				double imin = struct_label.compute_euclidean_similarity (v);				
				if (imin < min) {
					min = imin;
					p = i;
				}
			}
		}
		
		assert (p != -1);		
		return list.get(p);
	}
	
	
	public static void remove_chain_discrepancies (LinkedList<struct_label> list) {
		
		double[] std = new double[4];
		double[] mean = new double[4];
		
		
		assert (mean.length == std.length);
		
		int fsize = mean.length;	
		
		System.err.printf("Lista size: %d\n", list.size());
			
		boolean iter;
		do {
			iter = false;
			analyze_chain (list, mean, std);
			for (int i = 0; i < list.size(); i++) {			
				struct_label ri = list.get(i);			
				struct_label rc = find_the_closest (i, ri, list);		
				System.err.printf("id: %d,%d\n", ri.id, rc.id);
				double[] v = struct_label.similarity_metrics (ri, rc);
				boolean in = false;
				for (int f = 0; f < fsize/2; f++) {
					System.err.printf("v[%d]: %f, mean: %f, std: %f, id: %d,%d\n", f, v[f], mean[f], std[f], ri.id, rc.id);
					if (v[f] > mean[f] + 2*std[f]) {
						System.err.printf("Remova: %d\n", i);
						in = true;
						iter = true;
					}
				}
				if (in) { list.remove(i--); }
			}	
		} while (iter);
	}
	
	public static void analyze_chain (LinkedList<struct_label> list, double[] mean, double[] std) {
		
		assert(mean.length == std.length);
		
		int fsize = mean.length;
		
		int lsize = list.size();	
		
		for (int f = 0; f < fsize; f++) {
			mean[f] = std[f] = 0.0;
		}
		
		/*sort the rectangles by the x-axis [x-y plane]*/
		//Collections.sort(list, new comparator());		
		
		/*chain region mean*/
		for (int l = 0; l < lsize; l++) {
			struct_label rl = list.get(l);	
			struct_label rc = find_the_closest (l, rl, list);
			double[] dist = struct_label.similarity_metrics (rl, rc);
			for (int f = 0; f < fsize; f++) {
				mean[f] += dist[f];
			}
		}
		
		for (int f = 0; f < fsize; f++) {
			if (lsize > 0) {
				mean[f] /= lsize;
			}
		}

		/*chain standard deviation*/
		for (int l = 0; l < lsize; l++) {
			struct_label rl = list.get(l);	
			struct_label rc = find_the_closest (l, rl, list);
			double[] dist = struct_label.similarity_metrics (rl, rc);
			for (int f = 0; f < fsize; f++) {
				std[f] += (dist[f]-mean[f])*(dist[f]-mean[f]);
			}
		}

		for (int f = 0; f < fsize; f++) {
			if (lsize > 1) {
				std[f] = Math.sqrt(std[f]/(lsize - 1));
			}
		}

		boolean debug = false;
		if (debug) {			
			for (int l = 0; l < list.size(); l++) {
				struct_label r = list.get(l);
				System.err.printf("(%d,%d,%d,%d)\n", r.xmin, r.ymin, r.xmax, r.ymax);
			}
			
			for (int f = 0; f < fsize; f++) {
				System.err.printf("mean[%d]: %f, std[%d]: %f\n", f, mean[f], f, std[f]);
			}
		}		
	}	
	
	public static void thog_filtering (
			BufferedImage image,
			LinkedList<struct_label> list, 
			Classifier<double[]> cls,
			ArrayList<String> thog_params_list)
	{
		thog_desc thog = new thog_desc ();
		for (int i = 0; i < list.size(); i++) {
			struct_label r = list.get(i);
			BufferedImage candidate = thog.get_thog_sub_image (image, r.xmin, r.ymin, r.xmax - r.xmin + 1, r.ymax - r.ymin + 1);
			double score = thog.score (candidate, cls, thog_params_list, false);
			if (score < 0.0) {
				list.remove(i--);
			}
		}
	}
	
	public static void region_scaling (LinkedList<struct_label> list,  int level)
	{
		/*arrumar colocar o factor como parte da formula*/
		for (int i = 0; i < list.size(); i++) {
			struct_label r = list.get(i);
			r.xmin = (int)(r.xmin*Math.pow(2.0,level));
			r.ymin = (int)(r.ymin*Math.pow(2.0,level));
			r.xmax = (int)(r.xmax*Math.pow(2.0,level));
			r.ymax = (int)(r.ymax*Math.pow(2.0,level));
			r.level = level;
		}
	}	
	
	public static LinkedList<struct_label> region_filtering (int ibinary[], int width, int height, int level, String output_image_file_name, int inv, BufferedImage image) {

		labels l = new labels (ibinary, width, height);		
		
		int nlabels = l.get_nlabels();
		
		int[] ilabels = l.get_image_label();
		
		LinkedList<struct_label> list = l.get_label_list();
		
		image_functions.write_int_array_as_pgm (ilabels, width, height, 0, nlabels, output_image_file_name + "_" + inv + "_labels_before_l" + level);
	
		/*icdar min filtering parameters*/
		int min_width = 2;
		int min_height = 3;
		int min_surf = min_width * min_height;
		
		/*icdar max filtering parameters*/
		int max_width = 300;
		int max_height = 300;
		int max_surf = max_width * max_height; 

		/*verifying regions dimensions*/
		for (int i = 1; i < nlabels; i++) {
			
			struct_label s = list.get(i);
			
			double w = s.xmax - s.xmin + 1;			
			double h = s.ymax - s.ymin + 1;
			
			if ((s.surf < min_surf) || (s.surf > max_surf)) {
				s.active = false;
			}
			else if ((w < min_width) || (w > max_width)) {
				s.active = false;
			}
			else if ((h < min_height) || (h > max_height)) {
				s.active = false;
			}
			else if ((Math.min(w/h,h/w) < 0.1) && (Math.max(w/h,h/w) > 10.0)) {
				s.active = false;
			}
		}		

		/*verifying regions neighbors*/
		boolean[] neighbor = new boolean[nlabels];
		
		for (int k = 0; k < nlabels; k++) { neighbor[k] = false; }

		for (int i = 1; i < nlabels - 1; i++) {
			
			struct_label si = list.get(i);
			
			for (int j = i + 1; j < nlabels; j++) {
				
				struct_label sj = list.get(j);
				
				/*if the region has a similar neighbor it will be kept*/
				if (struct_label.similar(sj, si,1) && si.active && sj.active) {
					neighbor[i] = neighbor[j] = true;
				}
			}
		}
		
		for (int k = 0; k < nlabels; k++) { 
			if (!neighbor[k]) { list.get(k).active = false; } 
		} 
		
		/*cleaning inactive labels*/
		l.clean();
		
		BufferedImage tmp = image_functions.copy_image(image);
		for (int i = 0; i < l.get_label_list().size(); i++) {
		    struct_label region = list.get(i);
			image_functions.draw_rectangle (tmp, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1);			
		}	
		try {
			ImageIO.write(tmp, "png", new File(output_image_file_name + "_" + inv + "_letters_l" + level +".png"));			
		}
		catch (Exception e) { 
		}
		
		return l.get_label_list();
	}	
	
	public static void print_detection (
		double[] wimage,
		int hwindow_x, int hwindow_y, 
		double threshold, int level, 
		BufferedImage image, String output_image_file_name ) {		

		int w = image.getWidth();
		int h = image.getHeight();
		int n = w * h;

		BufferedImage temp = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		BufferedImage temp2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

		/*filling with the black color*/
		int black=0x000000;
		int white=0xffffff;
		for (int i = 0; i < n; i++) {
			int x = i % w;
			int y = i / w;
			temp.setRGB (x, y, black);
			temp2.setRGB (x, y, black);
		}
		
		/*copy text regions candidates*/
		for (int i = 0; i < (w * h); i++) {
			if (wimage[i] > threshold) {
				int xx = i % w;
				int yy = i / w;
				for (int x = xx - hwindow_x; x < (xx + hwindow_x); x++) {
					for (int y = yy - hwindow_y; y < (yy + hwindow_y); y++) {
						if ((x > 0) && (y > 0) && (x < w) && (y < h)) {
							temp.setRGB(x, y, image.getRGB(x, y));
							temp2.setRGB(x, y, white);
						}
					}
				}
			}
		}

		try {
			ImageIO.write(temp, "png", new File(output_image_file_name + "_l" + level + ".png"));
			ImageIO.write(temp2, "png", new File(output_image_file_name + "_mask_l" + level + ".png"));
		}
		catch (Exception e) { 
			System.err.printf("cannot write image\n");
		}
	}
		/*TO-DO resolver quando dois labels se juntam*/
		while (!queue.isEmpty()) {
			struct_grow pixel = queue.poll();
			status[pixel.x][pixel.y] = true;
			if ((pixel.x > 0) && (pixel.x < w - 1) && (pixel.y > 0) && (pixel.y < h - 1)) {
				/*verify the 8-neighbors to found text candidate pixels*/
				labels[pixel.y * w + pixel.x] = pixel.label;
				for (int i = -1; i <= +1; i++) {
					for (int j = -1; j <= +1; j++) {
						int xx = pixel.x + i; 
						int yy = pixel.y + j;
						if (!status[xx][yy]) {
							FloatImage region = FloatImage.get_sub_image (image, xx - hwindow_x, yy - hwindow_y, xx + hwindow_x, yy + hwindow_y);
							float score = (float)thog.score (region, trained_cls, hog_parameters, false);
							if (score > threshold) {
								queue.add(new struct_grow (xx, yy, pixel.label));
								int pos = yy * w + xx;
								wimage.set_pixel(xx,yy,score);
							}
							status[xx][yy] = true;
						}
					}
				}
			}				
		}
	}
	



// LinkedList<struct_label> candidates = new LinkedList<struct_label>();
		
			/*double[] vimage = image_functions.get_grey_image_normal (pyr[level]);
			
			grow_candidate_text_regions (vimage, nlabels, level, output_image_file_name, pyr[level], image, wb, hb, hwindow_x, hwindow_y, threshold, labels, queue, hog_parameters, trained_cls);

			range = file_functions.process (image, wb, hb);
			
			image_functions.write_pgm (image, wb, hb, range[0], range[1], output_image_file_name + "_grow_l" + level);
			
			print_detection (image, hwindow_x, hwindow_y, threshold, level, pyr[level], output_image_file_name); 	
						
			image_functions.write_pgm (vimage, wb, hb, 0, 255, output_image_file_name + "_grey_l" + level);			
			
			double[] inv = image_functions.image_inversion (vimage, wb, hb);
			
			int[] seg_n = image_segmentation (vimage, image, hwindow_x, hwindow_y, threshold, level, pyr[level], output_image_file_name, 1);			
			int[] seg_i = image_segmentation (inv, image, hwindow_x, hwindow_y, threshold, level, pyr[level], output_image_file_name, 0);	
				
			LinkedList<struct_label> l1 = region_filtering (seg_n, wb, hb, level, output_image_file_name, 0, pyr[level]);
			LinkedList<struct_label> l2 = region_filtering (seg_i, wb, hb, level, output_image_file_name, 1, pyr[level]);
			
			region_scaling (l1,  level);
			region_scaling (l2,  level);
			
			BufferedImage tmpA = image_functions.copy_image(in_image);
			for (int i = 0; i < l1.size(); i++) {
			    struct_label region = l1.get(i);
				image_functions.draw_rectangle (tmpA, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1);			
			}	
			try {
				ImageIO.write(tmpA, "png", new File(output_image_file_name + "_l1_" + level + "_.png"));			
			}
			catch (Exception e) { 
			}
			
			BufferedImage tmpB = image_functions.copy_image(in_image);
			for (int i = 0; i < l2.size(); i++) {
			    struct_label region = l2.get(i);
				image_functions.draw_rectangle (tmpB, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1);			
			}	
			try {
				ImageIO.write(tmpB, "png", new File(output_image_file_name + "_l2_" + level + "_.png"));			
			}
			catch (Exception e) { 
			}
			
			for (int kk = 0; kk < l1.size(); kk++) {
				candidates.add(l1.get(kk));
			}
			for (int kk = 0; kk < l2.size(); kk++) {
				candidates.add(l2.get(kk));
			}	*/		
		}
		
		/*candidates = filtering_large_region_overlap (candidates, in_image, output_image_file_name, 0, 0);
		
		candidates = kruskal_chain_grouping (candidates, in_image, output_image_file_name, 0, 0);
		
		//thog_filtering (in_image, candidates, trained_cls2, hog_parameters);
				
		BufferedImage tmp = image_functions.copy_image(in_image);
		for (int i = 0; i < candidates.size(); i++) {
		    struct_label region = candidates.get(i);
			image_functions.draw_rectangle (tmp, region.xmin, region.ymin, region.xmax - region.xmin + 1, region.ymax - region.ymin + 1);			
		}	
		try {
			ImageIO.write(tmp, "png", new File(output_image_file_name + "_final.png"));			
		}
		catch (Exception e) { 
		}
		
		
		FileOutputStream xml_out_file = null;		
		try {
			xml_out_file = new FileOutputStream(output_image_file_name + ".xml");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		PrintStream xml_out = new PrintStream(xml_out_file);		
		register.write_to_file (candidates, xml_out, args[0], in_image.getWidth(), in_image.getHeight());
		xml_out.close();
		
		System.err.printf("\nWriting results in: %s\n", output_image_file_name); */

	/*Sobel*/
	public void gradient_sobel (double[] image, int width, int height, int x, int y, double[] grad) {

		int position = y * width + x;

		double vmo = image[position - 1];
		double vpo = image[position + 1];
		double vom = image[position - width];
		double vop = image[position + width];

		double vmm = image[position - 1 - width];
		double vmp = image[position - 1 + width];
		double vpm = image[position + 1 - width];
		double vpp = image[position + 1 + width];

		grad[0] = (vpm + 2*vpo + vpp - vmm - 2*vmo - vmp)/8.0;
		grad[1] = (vmm + 2*vom + vpm - vmp - 2*vop - vpp)/8.0;
	}

	/*Get a normalized image from a grey level image.*/
	public double[] normalize_grey_image (FloatImage grey, double[] x_weight, int x_rwt, double[] y_weight, int y_rwt, double noise) {

		FloatImage gry = new double[w*h];
		
		double AVG, DEV;

		for (int y = 0; y < h; y++) {
			for (int x = 0; x < w; x++) {				
				int position = y * w + x;	
				AVG = get_grey_avg (grey, w, h, x, y, x_weight, x_rwt, y_weight, y_rwt);
				DEV = get_grey_dev (grey, w, h, x, y, x_weight, x_rwt, y_weight, y_rwt, AVG, noise);
				gry.get_sample(0,x,y) = (grey.get_sample(0,x,y) - AVG)/(3*DEV)+0.5;
				if (gry.get_sample(0,x,y) < 0) { gry.get_sample(0,x,y) = 0.0; }
				else if (gry.get_sample(0,x,y) > 1) { gry.get_sample(0,x,y) = 1.0; }
			}
		}
		return gry;
	}

	/*Get the averaged pixel value weighted by normalizing window*/
	public double get_grey_avg (FloatImage grey, int x, int y, double[] x_weight, int x_rwt, double[] y_weight, int y_rwt) {
		double sum_vwt = 0.0, sum_wt = 0.0;
		for (int dy = -y_rwt; dy <= y_rwt; dy++) {
			for (int dx = -x_rwt; dx <= x_rwt; dx++) {
				int x1 = x + dx;
				int y1 = y + dy;
				if ( (x1 >= 0) && (x1 < w) && (y1 >= 0) && (y1 < h)) {
					int position = y1 * w + x1; 
					double v = grey.get_sample(0,x,y);
					double wt = x_weight[x_rwt+dx]*y_weight[y_rwt+dy];
					sum_vwt += v * wt;
					sum_wt += wt; 
				}
			}
		}
		return sum_vwt/sum_wt;
	}

	/*get the deviation of a pixel given a normalizing window*/
	public double get_grey_dev (FloatImage grey, int x, int y, double[] x_weight, int x_rwt, double[] y_weight, int y_rwt, double AVG, double noise) {
		double sum_v2wt = 0.0, sum_wt = 0.0;
		for (int dy = -y_rwt; dy <= y_rwt; dy++) {
			for (int dx = -x_rwt; dx <= x_rwt; dx++) {
				int x1 = x + dx;
				int y1 = y + dy;
				if ( (x1 >= 0) && (x1 < w) && (y1 >= 0) && (y1 < h)) {
					int position = y1 * w + x1; 
					double v = grey.get_sample(0,x,y)-AVG;
					double wt = x_weight[x_rwt+dx]*y_weight[y_rwt+dy];
					sum_v2wt += v * v * wt;
					sum_wt += wt; 
				}

			}
		}
		return Math.sqrt(sum_v2wt/sum_wt + noise*noise);
	}
