// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
//    This library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Lesser General Public
//    License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//    Lesser General Public License for more details.
//
//    You should have received a copy of the GNU Lesser General Public
//    License along with this library; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//

package Catalano.Imaging.Tools;

import Catalano.Core.IntPoint;
import Catalano.Imaging.FastBitmap;
import Catalano.Imaging.Shapes.IntRectangle;
import Catalano.Math.Geometry.PointsCloud;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Detects blobs.
 * @author Diego Catalano
 */
public class BlobDetection {
    
    public static enum Algorithm{ FourWay, EightWay };
    
    private Algorithm algorithm = Algorithm.FourWay;
    private int width;
    private int height;
    private FastBitmap copy;
    private int size; //All blobs
    private int rR = 0,rG = 0,rB = 0;
    private List blobs;
    private Blob blob; //Blob object
    private int id = 0; //ID blob
    private boolean filterBlob = false;
    private int minArea = 1,maxArea; //filter blobs;
    private int idBigBlob; //Biggest blob
    private int areaBig = 0; //Biggest area

    public BlobDetection() {}
    
    public BlobDetection(Algorithm algorithm){
        this.algorithm = algorithm;
    }

    public int size() {
        return this.size;
    }
    
    public boolean isFilterBlob(){
        return this.filterBlob;
    }
    
    public void setFilterBlob(boolean bool){
        this.filterBlob = bool;
    }

    public int getMaxArea() {
        return maxArea;
    }

    public void setMaxArea(int maxArea) {
        this.maxArea = maxArea;
    }

    public int getMinArea() {
        return minArea;
    }

    public void setMinArea(int minArea) {
        this.minArea = minArea;
    }
    
    public int getIdBiggestBlob(){
        return this.idBigBlob;
    }

    public List ProcessImage(FastBitmap fastBitmap) {
        
        if(fastBitmap.isGrayscale()){
            width = fastBitmap.getWidth();
            height = fastBitmap.getHeight();

            if (maxArea == 0) {
                maxArea = width*height;
            }

            //Create another FastBitmap
            copy  = new FastBitmap(fastBitmap);
            copy.toRGB();
            blobs = new ArrayList();

            for (int x = 0; x < height; x++) {
                for (int y = 0; y < width; y++) {

                    // Can be any channel
                    if (copy.getRed(x, y) == 255) {
                        ShuffleColor();
                        TagBlob(x,y,rR,rG,rB);
                    }
                }
            }
            return blobs;
        }
        else{
            throw new IllegalArgumentException("Blob detection only works in grayscale images.");
        }
    }
    
    /**
     * Tag blob with any color.
     */
    private void ShuffleColor(){
        if (rB == 255) {
            if (rG == 255) {
                if (rR == 255) {
                    rR = rG = rB = 0;
                }
                rR++;
                rG = 0;
            }
            else{
                rG++;
                rB = 0;
            }
        }
        else{
            rB++;
        }
    }
    
    private void TagBlob(int x,int y, int r, int g, int b){
        ArrayList blobPoints = new ArrayList();
        LinkedList examList = new LinkedList();
        
        int xc = 0,yc = 0; //Centroid
        int blobArea = 0; //Area total
        
        int iR = copy.getRed(x, y);
        int iG = copy.getGreen(x, y);
        int iB = copy.getBlue(x, y);
        int iRGB = iR << 16 | iG << 8 | iB;
        
        int _r,_g,_b;
        examList.addFirst(new IntPoint(x,y));
        
        switch(algorithm){
            case FourWay:
                while (examList.size() > 0) {
                    IntPoint p = examList.removeLast();
                    _r = copy.getRed(p.x, p.y);
                    _g = copy.getGreen(p.x, p.y);
                    _b = copy.getBlue(p.x, p.y);
                    int _RGB = _r << 16 | _g << 8 | _b;

                    if (_RGB == iRGB) {
                        x = p.x;
                        y = p.y;

                        copy.setRGB(x, y, r, g, b);
                        blobArea++;
                        blobPoints.add(new IntPoint(x, y));
                        xc += p.x;
                        yc += p.y;

                        if (x-1 >= 0) {
                            examList.addFirst(new IntPoint(x-1,y));        // check west neighbor
                        }
                        if (x+1 < height) {
                            examList.addFirst(new IntPoint(x+1,y));        // check east neighbor
                        }
                        if (y-1 >= 0) {
                            examList.addFirst(new IntPoint(x,y-1));        // check north neighbor
                        }
                        if (y+1 < width) {
                            examList.addFirst(new IntPoint(x,y+1));        // check south neighbor
                        }
                    }
                }
            break;
            case EightWay:
                while (examList.size() > 0) {
                    IntPoint p = examList.removeLast();
                    _r = copy.getRed(p.x, p.y);
                    _g = copy.getGreen(p.x, p.y);
                    _b = copy.getBlue(p.x, p.y);
                    int _RGB = _r << 16 | _g << 8 | _b;

                    if (_RGB == iRGB) {
                        x = p.x;
                        y = p.y;

                        copy.setRGB(x, y, r, g, b);
                        blobArea++;
                        blobPoints.add(new IntPoint(x, y));
                        xc += p.x;
                        yc += p.y;

                        if (x-1 >= 0 && y-1 >= 0) {
                            examList.addFirst(new IntPoint(x-1,y-1));        // check west-north neighbor
                        }
                        if (x-1 >= 0) {
                            examList.addFirst(new IntPoint(x-1,y));        // check north neighbor
                        }
                        if (x-1 >= 0 && y+1 < width) {
                            examList.addFirst(new IntPoint(x-1,y+1));        // check east-north neighbor
                        }
                        if (y-1 >= 0) {
                            examList.addFirst(new IntPoint(x,y-1));        // check west neighbor
                        }
                        if (y+1 < width) {
                            examList.addFirst(new IntPoint(x,y+1));        // check east neighbor
                        }
                        if (x+1 < height && y-1 >= 0) {
                            examList.addFirst(new IntPoint(x+1,y-1));        // check south-west neighbor
                        }
                        if (x+1 < height) {
                            examList.addFirst(new IntPoint(x+1,y));        // check south neighbor
                        }
                        if (x+1 < height && y+1 < width) {
                            examList.addFirst(new IntPoint(x+1,y+1));        // check south-east neighbor
                        }
                    }
                }
            break;
        }
        
        if (filterBlob == true) {
            if ((blobArea > minArea ) && (blobArea < maxArea)) {
                    
                    if (blobArea > areaBig) {
                        areaBig = blobArea;
                        idBigBlob = id;
                    }
                    
                    //Discover width, height and bounding box using Point Cloud
                    List lst = PointsCloud.GetBoundingRectangle(blobPoints);
                    int h = Math.abs(lst.get(0).x - lst.get(1).x);
                    int w = Math.abs(lst.get(0).y - lst.get(1).y);
                
                    blob = new Blob(id, blobArea, new IntPoint(xc/blobArea, yc/blobArea),blobPoints, new IntRectangle(lst.get(0).x, lst.get(0).y, w, h));
                    blobs.add(blob);
                    size++;
                    id++;
            }
        }else{
            if (blobArea > areaBig) {
                areaBig = blobArea;
                idBigBlob = id;
            }
            
            //Discover width, height and bounding box using Point Cloud
            List lst = PointsCloud.GetBoundingRectangle(blobPoints);
            int h = Math.abs(lst.get(0).x - lst.get(1).x);
            int w = Math.abs(lst.get(0).y - lst.get(1).y);
            
            blob = new Blob(id, blobArea, new IntPoint(xc/blobArea, yc/blobArea),blobPoints, new IntRectangle(lst.get(0).x, lst.get(0).y, w, h));
            blobs.add(blob);
            size++;
            id++;
        }
    }
}
 

Ads help maintain this website.