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