Another starting point, where the objects being more or less fixed size disks is used ad hoc to measure their centroids as components after some mangling, and those which are close enough to each other are connected in the graph if out of sample of four hundred points along the edge at most four are not "white."
Image is in the variable img
and plenty of magic constants are employed. (If it's not otherwise obvious, I have to make it explicit: having such hand-picked constants as 0.9
, 40
, 55
, 300
, 0.0025
or even 0.25
or 5
is definitely a weakness, not a strong point of a solution.)
(* Perform image manipulation steps, feeding from one to another. *)
(* You can replace a "//" with "// Echo //" to see an intermediate value. *)
MorphologicalBinarize[img, 0.9] // Blur[#, 40] & //
Binarize[#, 0.9] & // HitMissTransform[#, DiskMatrix[55]] & //
(* Measure component centroids on the manipulated image. *)
ComponentMeasurements[#, "Centroid"][[All, 2]] & //
Function[v,
(* Select valid edges from all pairs of components:
- those whose edge length is less than 300, and
- at most 4 values of 400 sampled along the edge have a value < 0.25 *)
Select[Subsets[v, {2}],
EuclideanDistance @@ # < 300 &&
Count[Table[Min@PixelValue[img, {t, 1 - t}.#], {t, 0, 1, 0.0025}],
_?(# < 0.25 &)] < 5 &] //
(* Overlay the graph on top of the original image. *)
Show[img,
(* Construct a graph object with vertices on component centroids,
and edges as filtered by the Select expression. *)
Graph[v, UndirectedEdge @@@ #, VertexCoordinates -> v,
VertexStyle -> Red, VertexSize -> 1/2], ImageSize -> Medium] &]
Following variant just generates the graph g
:
g = (MorphologicalBinarize[img, 0.9] // Blur[#, 40] & //
Binarize[#, 0.9] & // HitMissTransform[#, DiskMatrix[55]] & //
ComponentMeasurements[#, "Centroid"][[All, 2]] & //
Function[v,
Select[Subsets[v, {2}],
EuclideanDistance @@ # < 300 &&
Count[Table[Min@PixelValue[img, {t, 1 - t}.#], {t, 0, 1, 0.0025}],
_?(# < 0.25 &)] < 5 &] //
Graph[v, UndirectedEdge @@@ #, VertexCoordinates -> v] &])
... on which you can perform graph operations:
CommunityGraphPlot[g]
img = ColorConvert[Import["https://i.sstatic.net/78BBP.png"], "Grayscale"]; dt = ImageAdjust@DistanceTransform@MedianFilter[Binarize[img], 3]
. It's easy to get the disk centres fromdt
withMaxDetect
. I do not have the time to play with this and will not post an answer. $\endgroup$