ConnComp.java
import java.util.*; import java.awt.image.*; import java.io.*; public class ConnComp { int nobjs; public BufferedImage label2rgb(BufferedImage img) { int w1 = img.getWidth(); int h1 = img.getHeight(); int type = BufferedImage.TYPE_INT_RGB; BufferedImage out = new BufferedImage(w1, h1, type);// new image int v, c; int value[] = new int[w1]; int zero = 0xFF000000; int [] colormap = {0xFFFF00FF,0xFFFF0000,0xFF00FF00,0xFF0000FF,0xFFFFFF00,0xFF00FFFF}; int clen = colormap.length; for (int j = 0; j < h1; j++) { img.getRGB(0, j, w1, 1, value, 0, w1); // read and store pixel value for (int i = 0; i < w1; i++) { v = value[i]&0xFFFFFF; if (v>0) value[i] = colormap[v%clen]; } out.setRGB(0, j, w1, 1, value, 0, w1); } return out; } public BufferedImage connect(BufferedImage img) { int w1 = img.getWidth(); int h1 = img.getHeight(); int type = BufferedImage.TYPE_INT_RGB; BufferedImage out = new BufferedImage(w1, h1, type);// new image int v, r, g, b, c; int value[] = new int[w1]; ArrayList<Run> A = new ArrayList<Run>(); ArrayList<Run> B = new ArrayList<Run>(); Run rn=null; boolean active = false; int count = 0; ArrayList<Merge> mlist = new ArrayList<Merge>(); for (int j = 0; j < h1; j++) { img.getRGB(0, j, w1, 1, value, 0, w1); // read and store pixel value for (int i = 0; i <= w1; i++) { try { v = value[i]; } catch(ArrayIndexOutOfBoundsException e) { v=0; } v = v & 0xFFFFFF; if (active && v==0) { rn.nlast = i-1; active = false; for (Run ra: A) { int n = Run.compare(rn,ra); // n==0 means runs overlap if (n==0) { if (rn.nlabel==0) rn.nlabel = ra.nlabel; else if (rn.nlabel != ra.nlabel) { Merge m = new Merge(ra,rn); boolean isdup = false; for (Merge mt: mlist) { if (m.equals(mt)) isdup = true; } if (!isdup) mlist.add(m); } } if (n<0) break; } if (rn.nlabel==0) rn.nlabel = ++count; } else if (!active && v>0) { active = true; rn = new Run(i); B.add(rn); } } for (Run rb: B) { for (int i=rb.nfirst; i<=rb.nlast; i++) value[i] = rb.nlabel; } out.setRGB(0, j, w1, 1, value, 0, w1); // exchange lists ArrayList<Run> swp = A; A = B; B = swp; B.clear(); } nobjs = count; if (mlist.isEmpty()) return out; int [] lookup = new int[count+1]; for (int i=0; i<=count; i++) lookup[i] = i; for (Merge m: mlist) m.doMerge(lookup); renumber(lookup); nobjs = 0; for (int k: lookup) nobjs = k>nobjs? k: nobjs; for (int j = 0; j < h1; j++) { out.getRGB(0, j, w1, 1, value, 0, w1); for (int i = 0; i < w1; i++) { v = value[i]&0xFFFFFF; try { value[i] = lookup[v]; } catch(ArrayIndexOutOfBoundsException e) { value[i] = 0; } } out.setRGB(0, j, w1, 1, value, 0, w1); } return out; } void showtable(int [] table,String title) { System.out.println(title); for (int i=1; i<table.length; i++) { System.out.format("%3d ",table[i]); if ((i%12)==0) System.out.println(); } System.out.println(); } void renumber(int [] table) { for (int i=1; i<table.length; i++) { if (missing(table, i)) { int nt = nextfound(table,i); for (int k=1; k<table.length; k++) { if (table[k]==nt) table[k] = i; } } } } int nextfound(int [] table, int nq) { for (int n: table) { if (n>nq) return n; } return -1; } boolean missing(int [] table, int nq) { for (int n: table) if (n==nq) return false; return true; } } class Run { int nfirst, nlast, nlabel; Run(int nstart) { nfirst = nstart; } public String toString() { return nlabel + " " + nfirst + " : "+nlast; } public static int compare(Run A, Run B) { if (A.nlast <B.nfirst-1) return -1; // A is left of B if (A.nfirst>B.nlast+1) return 1; // A is right of B return 0; // overlap } } class Merge { int na, nb; Merge(Run A, Run B) { na = A.nlabel; nb = B.nlabel; } public String toString() { return "merge " + na + " with " + nb; } public boolean equals(Merge t) { if (na==t.na && nb==t.nb) return true; if (na==t.nb && nb==t.na) return true; return false; } public void doMerge(int [] lookup) { int nt = lookup[na]; for (int i=0; i<lookup.length; i++) { if (lookup[i]==nt) lookup[i]=lookup[nb]; } } }
Maintained by John Loomis, updated Sat Mar 17 11:15:06 2018