program new;
procedure DrawCrosses(bmp:Integer; tpa: TPointArray; color: Integer);
var
i: Integer;
begin
for i := 0 to High(tpa) do
begin
FastSetPixel(bmp, tpa[i].x, tpa[i].y, color);
FastSetPixel(bmp, tpa[i].x+1, tpa[i].y, color);
FastSetPixel(bmp, tpa[i].x-1, tpa[i].y, color);
FastSetPixel(bmp, tpa[i].x, tpa[i].y+1, color);
FastSetPixel(bmp, tpa[i].x, tpa[i].y-1, color);
FastSetPixel(bmp, tpa[i].x+2, tpa[i].y, color);
FastSetPixel(bmp, tpa[i].x-2, tpa[i].y, color);
FastSetPixel(bmp, tpa[i].x, tpa[i].y+2, color);
FastSetPixel(bmp, tpa[i].x, tpa[i].y-2, color);
end;
end;
procedure DrawBoxes(bmp:Integer; tpa: TPointArray; w, h, color: Integer);
var
i, bmpW, bmpH: Integer;
boxPts: TPointArray;
begin
GetBitmapSize(bmp, bmpW, bmpH);
for i := 0 to High(tpa) do
begin
EdgeFromBoxWrap(IntToBox(tpa[i].x-w, tpa[i].y-h, tpa[i].x+w, tpa[i].y+h), boxPts);
FilterPointsBox(boxPts, 0, 0, bmpW-1, bmpH-1);
DrawTPABitmap(bmp, boxPts, color);
end;
end;
function getPoints(tpa: TPointArray): TPointArray;
var
ptsATPA: Array of TPointArray;
i: Integer;
begin
splitTPAExWrap(tpa, 3, 3, ptsATPA);
SetLength(Result, Length(ptsATPA));
for i := 0 to High(ptsATPA) do
begin
Result[i] := MiddleTPA(ptsATPA[i]);
end;
end;
var
initBmp, w, h: Integer;
basicBmp, iterator: Integer;
pts: TPointArray;
ptsSplitUp: Array of TPointArray;
begin
initBmp := LoadBitmap('D:\test.bmp');
GetBitmapSize(initBmp, w, h);
DisplayDebugImgWindow(w, h);
DrawBitmapDebugImg(initBmp);
SetTargetBitmap(initBmp);
FindColors(pts, 2367212, 0, 0, w-1, h-1);
pts := getPoints(pts);
basicBmp := CreateBitmap(w, h);
FastDrawClear(basicBmp, $FFFFFF);
DrawCrosses(basicBmp, pts, 0);
DrawBitmapDebugImg(basicBmp);
//From here on:
// pts -> the points we got
splitTPAExWrap(pts, 30, 30, ptsSplitUp); //<- this line
for iterator := 0 to High(ptsSplitUp) do
DrawBoxes(basicBmp, ptsSplitUp[iterator], 30, 30, RandomRange(0, $FFFFFF));
DrawBitmapDebugImg(basicBmp);
end.
Assuming test.bmp is saved on your D drive. One sec, will add explanation.
e:

This is the image I started with. Your image without the chars.

I changed it into a TPointArray and drawn crosses at the points. Kinda reduced the amount of points slightly.

Drawn a box around every point. If two points got each other in their boxes they are in the same group.
[INDENT]
splitTPAExWrap(inputTPA, 30, 30, outputATPA);[/INDENT]
30, 30 is the size of the boxes used to split them with. This is the function used to split them up.
You can then simply loop through it. Only picking hte ATPA[x] with a high enough length.
for i := 0 to High(outputATPA) do
if(Length(outputATPA[i]) > yourThreshHold) then
theGoodTPA := outputATPA[i];
e2:
You can also visual represent it by using boxes half the size:

If they touch each other squares, they are in the same group.
You can also use circles by sorting them in groups based on the distance. You have to use splitTPAWrap instead of splitTPAExWrap though.

If the circles touch each other they are in the same group. Note how 30 is no longer enough.