Connected Component Labeling

Hi , I am trying to separate the shapes from an binary image (the white pixels) using connected component labeling algorithm,however I can’t seem to figure out what is going wrong. Any help is appreciated.


Image link :

Before:https://drive.google.com/file/d/1YHHt7uGM0Nz2LIiDDy-rPQ4pMaxFeSuB/view
After:https://drive.google.com/file/d/1wwU-xajrIKoYUW6107rR3rfECstKpS36/view


Before.jpg

After.jpg

//first pass does the labeling
public static Texture2D FirstPass(Texture2D source)
    {

        //1-D array of color from source
        Color[] color = source.GetPixels(0);
       
        int width = source.width;
        Texture2D result = new Texture2D(source.width, source.height);
        //current label number
        int currRegion = 0;

        Dictionary<int, NodeLabel> labels = new Dictionary<int, NodeLabel>();

        Color top = Color.green, left = Color.green;

        //neighbouring top,left and current label respectively 
        NodeLabel t_A = new NodeLabel(), l_B = new NodeLabel(), currLabel = new NodeLabel();
        //index of neighbour in color array
        int topIndex = 0, leftIndex = 0;

        for (int i = 0; i < color.Length; i++)
        {
            //current pixel is white
            if (color *== Color.white)*

{
topIndex = i - width;

top = i >= width ? color[topIndex] : Color.green;

leftIndex = i - 1;

if ( ((leftIndex + 1) % width) == 0 || i == 0)
left = Color.green;
else
left = color[leftIndex];

if (top == Color.black && left == Color.black)
{
currRegion++;
currLabel = new NodeLabel(currRegion, i);
labels.Add(i, currLabel);
}
else
{

t_A = top == Color.white ? labels[topIndex] : null;
l_B = left == Color.white ? labels[leftIndex] : null;
currLabel = new NodeLabel(currRegion, i);
labels.Add(i, currLabel);

if (t_A != null && l_B != null)
{

NodeLabel lowestRegion;
lowestRegion = t_A.region < l_B.region ? t_A : l_B;

currLabel.region = lowestRegion.region;
if (t_A.region != l_B.region)
{
Debug.Log(“set parents”);
t_A.MergeRoot(l_B);
}

labels[currLabel.colorIndex] = currLabel;
labels[t_A.colorIndex] = t_A;
labels[l_B.colorIndex] = l_B;
}
else if (t_A != null)
{

currLabel.region = t_A.region;
labels[currLabel.colorIndex] = currLabel;
}
else if (l_B != null)
{

currLabel.region = l_B.region;
labels[currLabel.colorIndex] = currLabel;
}
else
{
currRegion++;
currLabel = new NodeLabel(currRegion, i);
labels[currLabel.colorIndex] = currLabel;
}
}

}
}

color = SecondPass(labels, color);

result.SetPixels(color);

return result;
}
//second pass sorts the labels and color each label uniquely
public static Color[] SecondPass(Dictionary<int, NodeLabel> labels, Color[] c)
{

Color color = Color.cyan;

Dictionary<int, Color> regionKeys = new Dictionary<int, Color>();

foreach (NodeLabel item in labels.Values)
{

item.region = item.GetRootParent().region;

if (regionKeys.ContainsKey(item.region))
color = regionKeys[item.region];
else
{

while(regionKeys.ContainsValue(color))
{
color = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, 1);
}
regionKeys.Add(item.region, color);
}

c[item.colorIndex] = color;

}

foreach (var item in regionKeys.Keys)
{
Debug.Log(“region value:” + item.ToString());
}

Debug.Log(“Region count:” + regionKeys.Keys.Count.ToString());

return c;
}
----------
//here is the node label class

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NodeLabel
{
public int region = 0;

public NodeLabel parent;

public int colorIndex;

public Color color = Color.white;

public NodeLabel() { }

public NodeLabel(int region, int colorIndex )
{
this.region = region;
this.colorIndex = colorIndex;
parent = this;
}

public void MergeRoot(NodeLabel label)
{

  • NodeLabel myRoot = GetRootParent();*
  •  label = label.GetRootParent();*
    
  •  if(myRoot.region < label.region)	*
    
  •      label.parent = myRoot;*
    
  •  else*
    
  •      myRoot.parent = label;*
    

}
public NodeLabel GetRootParent()
{
NodeLabel curr = this;
NodeLabel root = this.parent;
while(curr != root)
{
curr = parent;
root = this.parent;
}

  •  parent = curr;*
    

return curr;
}
public void MergeToRoot()
{
NodeLabel root = GetRootParent();
NodeLabel curr = this;
while (curr != this.parent)
{
curr.region = root.region;
curr = parent;
}
}

}

Update : alright I cleaned up the code and rewrote the algorithm from 4 direction connectivity to 8 direction (including the diagonals) connection and it worked much better though there is still some bugs
Update.jpg