# How to place curve path lines on an image

This is a further question of this post.I just make the path be curve by Photoshop.

I note Mr. C.E.'s method seem to not work anymore.Any method can repair it?

Since I posted the original question, I believe I should provide the curved path image as well. So, here goes an original image with the suggested curved path. Unfortunately, in this case, the sugarcane is still in its infancy. Aparently it should be easier if the sugarcane were more developed. However, this image represents a very real case which should be dealt with. Thanks. FACamargo.

• @C.E. Well,you meet a hard problem eventually. :) – yode Sep 23 '16 at 15:47
• The answer is forthcoming :) – C. E. Sep 23 '16 at 15:47
• I'm wondering whether one could use the same Fourier transform approach used by @C.E. in the straight lines case, but instead of selecting only the ft max frequencies, one would accept a range of higher frequencies, something like 95% or higher, maybe parameterizing the possible choices with Manipulate in order to verify the results. Well... let's try it... – FACamargo Sep 23 '16 at 15:51
• @FACamargo I posted my attempt now, this is as far as I've been able to take it. – C. E. Sep 23 '16 at 16:04

## 2 Answers

I'll work with FACamargo's photo, since this question has also been asked in the original Q&A.

We begin like for that other photo:

img = Import["http://i.stack.imgur.com/RMQ6U.jpg"];
gray = ColorConvert[RemoveAlphaChannel[img], "Grayscale"];
data = ImageData[gray];

ft = Fourier[data];
ft = RotateLeft[ft, Floor[Dimensions[ft]/2]];

scaled = ft // Abs // Log // Rescale // Image


We see that in this case the information is contained in many different frequencies instead of just a few frequencies. It is therefore much more difficult to extract the interesting signal, but by no means impossible. The method isn't broken; just more difficult to apply.

Like in the other answer we need to filter out the really short frequencies because those frequencies only correspond to the background intensity. They don't correspond to features in the image.

We can see that most of the features in the image can be described by six sets of frequencies, mirrored about the center. An appropriate filter might be this:

mask[r1_, r2_] := With[{d = ImageDimensions[img]},
Graphics[{
White,
Disk[d/2, r2, {Pi/2, Pi/2 + Pi/4}],
Disk[d/2, r2, {Pi + Pi/2, Pi + Pi/2 + Pi/4}],
Black, Disk[d/2, r1]
},
PlotRange -> {{0, First[d]}, {0, Last[d]}},
ImageSize -> ImageDimensions[img],
Background -> Black
]
]
filtered = ImageMultiply[mask[50, 70], scaled]


Picking out the 20 most high intensity frequencies in this filtered Fourier spectrum, we get

norm = Map[Norm, ImageData[filtered], {2}];
pos = Flatten[Position[norm, #] & /@ TakeLargest[Flatten[norm], 20], 1];

invft = InverseFourier[SparseArray[pos -> 1, Dimensions[ft]] ft];
invimg = invft // Abs // Rescale // Image;
ImageMultiply[img, invimg]


Well... that's not nearly as good as in for the other photo, but some information about the lines is still there.

The main problems are:

1. The pattern is weaker in this image, it doesn't stand out as the only significant pattern.
2. The information about the pattern is spread out among many different frequencies, not just two frequencies like in the other image. That makes it more difficult to extract the right frequencies.

I don't know at the moment how to find the right frequencies, but this shows that the approach isn't completely invalidated. It's just more difficult to apply it to this photo.

The Fourier transform of Yode's image looks like it might be even more difficult to extract the right frequencies from.

• Kudos @C.E.. You've done it again! I will explore your techniques further down, and try to generalize it with other pictures that I have, in order to minimize the shadows over the recovered image. The lines are there, so now we only need to extract them. Good job! – FACamargo Sep 23 '16 at 16:13

I have to say the method derive from C.E. totally.I just give a record for reading about how to deal with that picture I have uploaded.

img =Import["http://i.stack.imgur.com/nxMqb.png"];
gray = ColorConvert[RemoveAlphaChannel[img], "Grayscale"];
data = ImageData[gray];

ft = Fourier[data*PadRight[{{}}, Dimensions[data], {{1, -1}, {-1, 1}}]];

scaled = ImagePeriodogram[gray]


Then I get a mask image by Image-Tool.

This is what I make,you can run mask=Normal[Databin["fWADf47A",{1}]][[1,1]] to get it exactly.

Select the frequency that we need.

select = MaxDetect[ImageMultiply[scaled, ColorNegate[mask]], .1]


Almost.

pos = SparseArray[ImageData[select]]["NonzeroPositions"];
invft = InverseFourier[SparseArray[pos -> 1, Dimensions[ft]] ft];
{invimg = invft // Abs // Rescale // Image,
ImageMultiply[invimg, img]}


But there are some dissatisfaction in this result about that shadows.I will glad to see anyone can improve it still.

Update(little improvements):

{bin = Binarize[TopHatTransform[invimg, 1] // ImageAdjust, .1],
HighlightImage[img, bin]}


Update 2(As the comment from Silvia): The LocalAdaptiveBinarize will give a better result indeed.

Thinning@LocalAdaptiveBinarize[invimg, 6]


• I like the way you compute select and pos, nice. +1 – C. E. Sep 23 '16 at 23:04
• @C.E. It's my honour to get you such comment. :) – yode Sep 23 '16 at 23:06
• The next question, to both of you, will be "how to extract the actual lines geometry from the inverse transformed image?". I believe that it will not be too difficult to just "follow the black pixels" after some thinning and prunning, but I will first mix and match both approaches in a kind of tool that allows one to "play" with parameters for picking the right frequencies in a more visual way... I promise to publish it here within the coming week. For the moment I must say that I am impressed! – FACamargo Sep 23 '16 at 23:45
• @C.E. How about this little new change?Hope to help. – yode Sep 24 '16 at 0:04
• LocalAdaptiveBinarize on your invimg might give a better result. – Silvia Oct 1 '16 at 11:15