/* Last edited on 2013-03-25 20:03:36 by stolfilocal */ import java.lang.Math; import java.util.Arrays; import java.util.Random; import java.util.Scanner; import java.io.File; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.FileInputStream; import minetto.utils.WordCand; import minetto.utils.WordCandElem; import minetto.utils.CharGrouper; import minetto.utils.FloatImage; import minetto.utils.FloatImagePaint; public class TestCharGrouper { public static void main(String[] args) throws IOException { String in_dir = args[0]; String out_dir = args[1]; String image_name = args[2]; String fname_txt_in = in_dir + "/" + image_name + ".txt"; int[][][] bboxes = read_char_bboxes(fname_txt_in); int nx = max_coord_in_bboxes(bboxes, 0); int ny = max_coord_in_bboxes(bboxes, 1); CharGrouper grouper = new CharGrouper(); /* Parameters of the input distribution: */ grouper.wBtot = nx; /* Total image width (px). */ grouper.hBtot = ny; /* Total image height (px). */ grouper.avgWArea = 1.5e4; /* Expected number of image pixels per word. */ grouper.avgWLen = 6.0; /* Expected number of letters per word. */ grouper.prTrue0 = 0.05; /* A priori prob that a trial char box is a true initial letter. */ grouper.prTrueN = 0.50; /* A priori prob that a trial char box is a true non-initial letter. */ /* Parameters of the grouping algorithm proper: */ grouper.hmin = 7.0; /* Min char body height of a true letter for this scale (px). */ grouper.hmax = 56.0; /* Max char body height of a true letter for this scale (px). */ grouper.rmin = 0.125; /* Min char body aspect of a true letter letter {w/h}. */ grouper.rmax = 2.000; /* Max char body aspect of a true letter letter {w/h}. */ grouper.dxmax = 1.00; /* Max allowed char-char gap rel body height. */ grouper.dxmin = -0.30; /* Min allowed char-char gap (may be negative) rel body height. */ grouper.MLsmax = 0.30; /* Max slope of midline between chars. */ grouper.TBsmax = 0.25; /* Max slope of topline minus baseline. */ grouper.fdes = 0.50; /* Nominal ratio of descender depth to lowercase x-height. */ grouper.fasc = 0.50; /* Nominal ratio of ascender height to lowercase x-height. */ grouper.semin = Math.log(0.00); /* Min word cand score for extending a word cand. */ grouper.ssmin = Math.log(0.00); /* Min word cand score to consider an element grouped. */ grouper.skmin = Math.log(0.20); /* Min word cand score to keep a closed word cand. */ grouper.delExtended = false; /* If TRUE deletes candidates that have been successfully extended. */ FloatImage img_chs = show_char_cands(nx, ny, bboxes); String fname_png_chs = out_dir + "/" + image_name + "-chs.png"; img_chs.write_as_png(fname_png_chs, 0.0f, 1.0f, 1.000, true); WordCand[] wds = grouper.group(bboxes); System.err.printf("grouper returned %d word cands\n", wds.length); FloatImage img_wds = show_word_cands(nx, ny, wds); String fname_png_wds = out_dir + "/" + image_name + "-wds.png"; img_wds.write_as_png(fname_png_wds, 0.0f, 1.0f, 1.000, true); String fname_txt_out = out_dir + "/" + image_name + ".txt"; write_word_cands(fname_txt_out, wds); } /* ---------------------------------------------------------------------- Reads a list of character candidates (bboxes) from file {fname}. */ private static int[][][] read_char_bboxes(String fname) { int[][][] bboxes = new int[1000][][]; int nch = 0; try { System.err.printf("reading character boxes from file \"%s\"\n", fname); BufferedReader rd = new BufferedReader(new InputStreamReader(new FileInputStream(fname))); do { String line = ""; if ((line = rd.readLine()) == null) { break; } /* Parse the line: */ Scanner sc = new Scanner(line); String imgName = sc.next(); int level = sc.nextInt(); int cseq = sc.nextInt(); int wseq = sc.nextInt(); int ixmin = sc.nextInt(); int iymin = sc.nextInt(); int w = sc.nextInt(); int h = sc.nextInt(); double rmin = sc.nextDouble(); double rmax = sc.nextDouble(); String val = sc.next(); /* Check for garbage at end of line: */ assert (! sc.hasNext()); /* Make sure there is space in teh array: */ if (nch >= bboxes.length) { bboxes = java.util.Arrays.copyOf(bboxes, 2*bboxes.length + 1); } bboxes[nch] = new int[][]{{ixmin, ixmin+w-1}, {iymin, iymin+h-1}}; nch++; } while (true); System.err.printf("got %d charcters\n", nch); rd.close(); } catch(Exception e) { e.printStackTrace(); } /* Trim box list: */ return java.util.Arrays.copyOf(bboxes, nch); } /* ---------------------------------------------------------------------- Returns the largest coordinate in the list of bounding boxes {bboxes} along the given {axis} (0 or 1). Returns 0 if the list is empty. */ private static int max_coord_in_bboxes(int[][][] bboxes, int axis) { int cmax = 0; for (int ich = 0; ich < bboxes.length; ich++) { int c = bboxes[ich][axis][1]; if (c > cmax) { cmax = c; } } return cmax; } /* ---------------------------------------------------------------------- Creates an image showing the character cands {bboxes[0..bboxes.length-1]}. */ private static FloatImage show_char_cands(int nx, int ny, int[][][] bboxes) { FloatImage img = new FloatImage(3, nx, ny); img.set_all_samples(0f); for (int ich = 0; ich < bboxes.length; ich++) { int[][] box = bboxes[ich]; float colorB[] = pick_color(0.2, 0.6, ich); FloatImagePaint.paint_rectangle(img, box[0][0],box[0][1], box[1][0],box[1][1], 1, colorB); } return img; } /* ---------------------------------------------------------------------- Creates an image showing the word cands {wds[0..wds.length-1]}. */ private static FloatImage show_word_cands(int nx, int ny, WordCand[] wds) { FloatImage img = new FloatImage(3, nx, ny); img.set_all_samples(0f); for (int iwd = 0; iwd < wds.length; iwd++) { WordCand W = wds[iwd]; CharGrouper.dbgW(0,"showing word cand",iwd,W); int[][] box = W.bounding_box(); float colorW[] = pick_color(0.2, 0.6, iwd); float colorL[] = pick_color(0.4, 0.8, iwd); FloatImagePaint.paint_rectangle(img, box[0][0],box[0][1], box[1][0],box[1][1], 1, colorW); for (int iel = 0; iel < W.els.length; iel++) { WordCandElem L = W.els[iel]; FloatImagePaint.paint_rectangle(img, L.box[0][0],L.box[0][1], L.box[1][0],L.box[1][1], 1, colorL); double ybas = CharGrouper.yref(L,0); double ytop = CharGrouper.yref(L,1); FloatImagePaint.paint_dot(img, L.xctr, ybas, 1.00, 0.0, colorL); FloatImagePaint.paint_dot(img, L.xctr, ytop, 1.00, 0.0, colorL); } } return img; } /* ---------------------------------------------------------------------- Returns a pseudorandom RGB color for object number {i} with brightness in {[lo_hi]} */ private static float[] pick_color(double lo, double hi, int i) { double md = (lo + hi)/2; double rd = (hi - lo)/2; float color[] = new float[]{ (float)(md + rd*Math.cos(2*Math.PI/6*((i + 0) % 6))), (float)(md + rd*Math.cos(2*Math.PI/6*((i + 2) % 6))), (float)(md + rd*Math.cos(2*Math.PI/6*((i + 4) % 6))) }; return color; } private static void write_word_cands(String fname, WordCand[] wds) { for (int iwd = 0; iwd < wds.length; iwd++) { WordCand W = wds[iwd]; /* Should be a method of {WordCand} */ int[][] box = W.bounding_box(); int ixmin = box[0][0]; int iymin = box[1][0]; int w = box[0][1] - box[0][0] + 1; int h = box[1][1] - box[1][0] + 1; System.out.printf("FOO %5d %5d %5d %5d %5d\n", iwd, ixmin, iymin, w, h); } } }