As requested I include the code to detect and store irregular shaped areas of pixels of a particular colour. The image below shows the results of my testing.
The image on the left is the starting image and the one on the right shows the 7 blobs detected each in a different colour.
To detect irregular shaped blobs the code had to be more complex than that for simple rectangles, there is nothing I can do about that.
I suggest that you spend sometime studying and experimenting with the code.
The main class is Blob which has some useful methods that you could use in your own program for instance
nbrPixels returns how many pixels make up the Blob
contains(x,y) detects whether the position x,y is actually part of the Blob.
The methods showBlobs and listBlobs show how you can iterate through the ArrayList of Blobs.
Hope you find this useful.
Code:
PImage img;
// This will hold all the blobs
ArrayList blobs = new ArrayList();
public void setup() {
size(640, 480);
img = loadImage("test.png");
noLoop();
}
public void draw() {
img.filter(THRESHOLD, 0.82f);
image(img, 0, 0); // show image 1:1 scale
detectBlobs(img, color(255,255,255));
showBlobs();
listBlobs();
}
// This is the main method for detecting blob shapes
void detectBlobs(PImage img, int col){
int x = 0, y = 0;
int count = 0;
LineBlob lb;
for(y = 0; y < img.height; y++){
x = 0;
while(x < img.width){
if(img.pixels[count] == col){
lb = new LineBlob();
lb.y = y; //stores y row
lb.sx = x; //stores startPoint
x++;
count++;
while(x < img.width && img.pixels[count] == col){
x++;
count++;
}
lb.ex = x-1; //stores startPoint
addToAndMergeBlobs(lb);
}
else {
x++;
count++;
}
}// end x while
}//end y for
}
// Do not call this method directly
void addToAndMergeBlobs(LineBlob lb){
ArrayList blobsToMergeWith = new ArrayList();
for(int i = 0; i < blobs.size(); i++){
Blob b = ((Blob)blobs.get(i));
if(b.canMergeLineBlob(lb))
blobsToMergeWith.add(b);
}
if(blobsToMergeWith.size() == 0){
blobs.add(new Blob(lb));
}
else {
Blob b0 = ((Blob)blobsToMergeWith.get(0));
b0.mergeLineBlob(lb);
for(int i = 1; i < blobsToMergeWith.size(); i++){
Blob bmerge = ((Blob)blobsToMergeWith.get(i));
b0.mergeBlob(bmerge);
blobs.remove(bmerge);
}
}
}
public void showBlobs() {
int showCol = color(255,0,0);
for(int i = 0; i < blobs.size(); i++){
showCol = color(128 + random(128), 128 + random(128), 128 + random(128));
((Blob)blobs.get(i)).showBlob(showCol);
}
}
public void listBlobs() {
Blob b;
println("Detected "+ blobs.size() + " blobs");
for(int i = 0; i < blobs.size(); i++){
b = ((Blob)blobs.get(i));
println(" Blob "+ i + "\t has " + b.nbrPixels() + " pixels");
}
}
// This class represents a continuous area of a particular colour
class Blob {
ArrayList lineBlobs = new ArrayList();
public Blob(LineBlob lb){
lineBlobs.add(lb);
}
// Sees whether the position x,y is part of the blob
// by seeing if it
public boolean contains(int x, int y){
boolean result = false;
for(int i = 0; i < lineBlobs.size(); i++){
if(((LineBlob)lineBlobs.get(i)).contains(x, y)){
result = true;
}
}
return result;
}
// Sees whether a lineblob is adjacent to this blob but does
// NOT merge them
public boolean canMergeLineBlob(LineBlob lb){
boolean result = false;
for(int i = 0; i < lineBlobs.size(); i++){
if(((LineBlob)lineBlobs.get(i)).hasVertOverlap(lb)){
result = true;
}
}
return result;
}
// This merges a LineBlob to this Blob
public void mergeLineBlob(LineBlob lb){
lineBlobs.add(lb);
}
public void mergeBlob(Blob b){
lineBlobs.addAll(b.lineBlobs);
}
public void showBlob(int showCol){
stroke(showCol);
for(int i = 0; i < lineBlobs.size() ; i++){
((LineBlob)lineBlobs.get(i)).showLineBlob(showCol);
}
}
public int nbrPixels(){
int n = 0;
for(int i = 0; i < lineBlobs.size(); i++)
n += ((LineBlob)lineBlobs.get(i)).nbrPixels();
return n;
}
}
// Supporting class to Blob
class LineBlob {
public int y;
public int sx;
public int ex;
public LineBlob() {
}
public LineBlob(int y, int sx, int ex) {
super();
this.y = y;
this.sx = sx;
this.ex = ex;
}
public boolean contains(int px, int py){
if(py == y && px >= sx && px <= ex)
return true;
else
return false;
}
public boolean hasVertOverlap(LineBlob b){
if(Math.abs(b.y - y) == 1) {
if( (b.sx >= sx && b.sx <= ex) || (sx >= b.sx && sx <= b.ex) ){
return true;
}
}
return false;
}
public void showLineBlob(int showCol){
line(sx,y,ex,y);
}
public int nbrPixels(){
return ex - sx + 1;
}
}