UPDATE
In this particular case it is quite sufficient just to apply Pruning with 1 as the second argument:
i = Import["https://i.stack.imgur.com/K8dm3.png"];
ep = MorphologicalTransform[Pruning[Thinning@Binarize@i, 1], "EndPoints"];
PixelValuePositions[%, White]
{{271, 546}, {190, 471}, {694, 382}, {899, 366}}
The purpose of Pruning is to remove just one pixel which causes additional end point caught by "EndPoints":
PixelValuePositions[
ImageDifference[Thinning@Binarize@i, Pruning[Thinning@Binarize@i, 1]], White]
{{357, 341}}
Original answer
One approach is to apply Pruning and then take "SkeletonEndPoints":
i = Import["https://i.stack.imgur.com/K8dm3.png"];
ep1 = MorphologicalTransform[Pruning[Thinning@Binarize@i, 150], "SkeletonEndPoints"]

PixelValuePositions[%, White]
{{271, 546}, {190, 471}, {694, 382}, {899, 366}}
In this particular case we can make Pruning much more efficient if we apply FillingTransform before Thinning:
ep2 = MorphologicalTransform[
Pruning[Thinning@Binarize@FillingTransform@i, 4], "SkeletonEndPoints"];
ep1 == ep2
True
Now we can ensure that we actually have found end points of the thinned image:
ppos = ImageValuePositions[ep2, White]
{{270.5, 545.5}, {189.5, 470.5}, {693.5, 381.5}, {898.5, 365.5}}
pic = Thinning@Binarize@i;
Show[ImageTrim[pic, {#}, 1], GridLines -> {Range[10], Range[10]}, ImageSize -> 100,
Method -> {"GridLinesInFront" -> True}] & /@ ppos

We can check what these pixels correspond to in the original image:
Show[ImageTrim[ReplaceImageValue[i, # -> Red], {#}, 5],
GridLines -> {Range[10], Range[10]}, ImageSize -> 100,
Method -> {"GridLinesInFront" -> True}] & /@ ppos

Pruningdo.But it will lead to a right result. Can you give a explaination? – yode Mar 21 '16 at 15:45Pruning[image,n]removes branches that are at most n pixels long." In the other words, it computes lengths of branches of the skeleton an then "eats up" all branches with length no longer than n pixels. There is no explicit definition for the "length" but the principle seems to be clear. – Alexey Popkov Mar 21 '16 at 15:50Pruning. – yode Mar 21 '16 at 16:05ep1 = MorphologicalTransform[Pruning[Thinning@Binarize@i, 150], "SkeletonEndPoints"].In the second solution its behavior in our expectation. – yode Mar 21 '16 at 16:12Pruninghere removes a tiny branch (which is the source of the trouble). In the case ofep1this "branch" is of length one pixel as you can see withImageDifference[Thinning@Binarize@i, Pruning[Thinning@Binarize@i, 150]], but withoutPruningwe get this pixel as one of the end points even with"SkeletonEndPoints"(checkMorphologicalTransform[Thinning@Binarize@i, "SkeletonEndPoints"]). – Alexey Popkov Mar 21 '16 at 17:12MorphologicalTransform[Pruning[Thinning@Binarize@i, 1], "EndPoints"]is actually quite sufficient. I'll update the answer with this (much more efficient) solution. – Alexey Popkov Mar 21 '16 at 17:22ImageDifference.If not,I have to find a high magnification.:) – yode Mar 21 '16 at 17:37