3
$\begingroup$

I have such image: image description

It is a binary image, I mean the pixel value is 0 or 1, but now, I hope to replace every pixel value with its distance from self to the image edges(edge can be one of the top edge, bottom edge, left edge or right edge), but I don't care the distance is shortest or not. Such as the following red pixel, which have two or more paths to image edges. We can use any distance to replace its pixel value.

When the pixel have no any path to the image edge, I will replace the pixel value with -1. Is there any efficient method can implement this target? Sorry for no try but just a question. It seem it is hard to me. Can anyone give me some advice to do it?

$\endgroup$
3
$\begingroup$

You can use graph tools for this. Take a small part of your image for an example:

small = ImageTake[img, {500, 600}, {50, 100}]

enter image description here

extract white pixels:

whitepix = 
   Position[Round[ImageData[ColorConvert[small, "Grayscale"]]], 1];

find adjacent pixels:

near = Nearest[whitepix -> Range@Length@whitepix]
edges = DeleteCases[
   Union[Sort /@ 
      Flatten[Function[{i}, {{i, #} & /@ 
          near[whitepix[[i]], {9, 1}]}] /@  (*make {9,Sqrt[2]} to take diagonals*)
          Range[Length@whitepix] , 2]], {i_, i_}];

now make a graph:

g = Graph[Range[Length@whitepix], UndirectedEdge@@@ edges, 
   VertexCoordinates -> Reverse /@ whitepix, EdgeStyle -> Gray]

enter image description here

now we can find shortest paths point to point: (here i just manually identified an edge point 237 , and pick another point at random)

HighlightGraph[g, PathGraph[FindShortestPath[g, 400, 237]], 
 EdgeStyle -> {Thick, Red}]

enter image description here

the distance is simply: GraphDistance[g, 400, 237] (*64*)

works well on the whole image..

enter image description here

$\endgroup$
  • $\begingroup$ I cannot imagine it will cost how much time to replace all white pixel vlaue. $\endgroup$ – yode Jan 12 '18 at 19:16
  • $\begingroup$ @yode FindShortestPath is actually surprisingly fast. This will take some hours I suppose but its not intractable. $\endgroup$ – george2079 Jan 12 '18 at 19:41
1
$\begingroup$

I am not exactly sure what it mean by distance to image edges but here's the first step you can try.

bimg = Binarize[img];

g = GridGraph[ImageDimensions[bimg]];

sa = SparseArray[ImageData[bimg]];

dim = Dimensions[sa];

alist = sa["AdjacencyLists"];

vindex[i_, j_, h_] := (i - 1) h + j

vind = Flatten[
   Table[vindex[i, #, dim[[2]]] & /@ alist[[i]], {i, 1, 
     Length[alist]}]];

pixelgraph = 
  Subgraph[g, vind, VertexCoordinates -> GraphEmbedding[g][[vind]]];

This is a large graph so I just plot vertex coordinates to see it works:

Graphics[Point[GraphEmbedding[pixelgraph]]]

enter image description here

Now you can compute the distance using a pixelgraph and then mapping back vertex index (with distance) to position of ImageData matrix.

$\endgroup$
  • $\begingroup$ The four margins of image. $\endgroup$ – yode Jan 11 '18 at 19:10
  • $\begingroup$ Do you have any comments on this? Do you see any errors in the code? I tried to document it so people wouldn't have to rely on reading the code only. Do you see any simple ways to significantly improve performance? Currently, this function is suitable for interactive use, but it is not fast enough to put it in a loop. $\endgroup$ – Szabolcs Jan 17 '18 at 13:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.