I don't know if this is a corner case or the norm in your dataset but it is a relatively easy situation to deal with. It would be much more difficult to detect trees in an urban environment, for example, where you would probably be looking at more pattern-recognition type of solutions.
The basic idea behind this solution is surface fitting, whether to directly detect the trees or detect the "floating" level of the ground and through that information detect the trees.
The following is based on Octave and using the 1D data but generalisations to other platforms (and 2 dimensions) should be straightforward.
The first thing one can do here is kernel density estimation (KDE). In this case, you would be approximating the total available surface (both the ground and the trees) via a set of Gaussian curves. In the two dimensional case, this will give you either one Gaussian per tree or higher densities of Gaussians around the locations of trees. In one shot. No further processing required. In reality, you might find that this technique approximates your disparity image via kernel density and returns the data of a set of Gaussians that you can process further to determine where there are trees.
But, having had a quick look at the data, it contains sharp discontinuities and that might not be good for KDE convergence. While you could "blur" the disparity with a Gaussian low pass and then try to approximate it with KDE, this means that your original resolution is decreased and it might reduce your ability to discriminate between small and large trees. Anyway, this is an option too (first blur with a suitable FWHM Gaussian, then approximate with KDE).
Again, this seems a relatively easy case where you could even use simple thresholding to detect the trees. The problem there of course is that the ground height now modulates your threshold. A tree on flat ground could be anything above 25 meters but certainly not a 3 meter tall shed on top of a 22 meter hill.
So, we want to threshold but we want to take into account the ground contour. Ideally, you could fit a curve that is closer to what the ground really is (an ellipsoid) but maybe you can get away with simpler fitting schemes.
The main idea here is that we want to "undo" the modulation of the ground to then apply a simple threshold. If we flatten the ground, the 22 meter hill will disappear and then anything above 22 meters is more likely to really be a tree.
If you ignore the zeros (which I am assuming are "missing values" in your case (either high uncertainty or actually missing values)), the signal looks like this:
You can threshold this at $\approx 62$ but you can see that the second tree is lower than the first but further up the slope of what looks like a hill.
Let's flatten the hill. Flattening the hill here is basically equivalent to subtracting the slowly varying component (the hill) from the signal itself and possibly even controlling the amount of removal with a coefficient. Here, I will use simple polynomial fitting but anything that could approximate the slow varying component of the height field would do.
sv = polyval(polyfit(xrange,b,2),xrange); # Fit and evaluate a second order polynomial. You might want to go higher if you have ridges or depressions but not too high because we just want to approximate the slow varying ground changes.
plot(b);hold on;plot(sv,'r');grid on; # Plot everything
This now looks like this:
Obviously, we can simply subtract the red curve from the blue and get back the "flattened" version of the signal, but as you can see, the trees have "pulled the ground up" slightly and this is why if you do this blindingly, you will get this:
In terms of comparing between the trees, we are now definitely in a better condition because we have removed the ground and we can also tell that the second tree is lower than the first, but, we now have a dip from trying to remove the hill. To adjust for situations like this, you can introduce a coefficient by which to control how much subtraction you want to perform, for example:
Here, $m \in [0 . . 1.0]$ controls how much of the real signal and how much of its approximation we are taking into account. I determined
0.43 after trial and error and this results to:
Where basically, the trees start at almost the same height.
So, now you can threshold anything above
-8.2 and be more certain that you are selecting trees.
There is a way by which you can flatten the ground almost completely but it requires some knowledge about the size of the tree canopy.
This works on the same premise but approximates the ground using a different method.
Basically, you can use a median filter to "chop the peaks" that the trees are causing to the height field. Anything that remains after that is basically ground variation.
The median filter is applied in a "rolling window" way and substitutes a sample with the median value of $N$ values surrounding it.
Now, to apply this, you need to determine that $N$ which should be almost as wide as your widest tree canopy. I have determined this to be approximately 125 (pixels) in this example, so by doing:
plot(b-medfilt1(b,125)); grid on;
You get something like this:
Which is almost too good. At least the trees start at exactly the same point. Again, it is now the point of applying a simple threshold (anything above 1 (?)) to detect where the trees are.
This process will give you a binary mask which you can then shrink (or even simply cluster, with simple methods) to determine a centroid that you would then associate with the location of a tree. Obviously, processing the size of each "cluster" could probably also tell you how wide is the tree canopy.
In terms of generalising this, you can either fit a 2D polynomial or a 2D NURB or even simply apply a 2D median with
Hope this helps.