First, let's get the scale bar out of the image. There are a few ways to do this (MorphologicalBinarize
and friends), but I went with the more eye-bally approach of using ColorReplace
. Here, we're replacing black pixels with white, and all other pixels with black, to get a mask. Note that ColorReplace has a third argument d
, which you could use to fine-tune what it sees as "black".
i = Import["https://i.sstatic.net/yR6UY.gif"]
c = ColorReplace[i, {Black -> White, _ -> Black}]
Compare with a simple MorphologicalBinarize
- the choice is yours:
Now we can get the bounding box of our rectangle, and simply take the difference:
box = ComponentMeasurements[c, "BoundingBox"][[1, 2]]
Differences /@ Transpose@box
box = ComponentMeasurements[c, "BoundingBox"][[1, 2]]
Differences /@ Transpose@box
{{38.}, {5.}}
So the longest dimension of our bounding box is 38 pixels long, and the short side is 5 pixels long.
Just to check, I counted the pixels another way, using SequenceCases
on our replaced image, and each line of 1
s, the pixels of the scale bar, had a length of 38.
SequenceCases[
Flatten@MorphologicalComponents[c], {p : Repeated[1]} :> Length@{p}]
{38, 38, 38, 38, 38}
Either way, we get about 38 pixels, so now we know the length of the bar, and thus we can get the size of a pixel (assuming pixels are square here).
pixelLength = Quantity[3, "Microns"] / 38
Quantity[0.0789474, "Microns"]
and now if we get the Euclidean distance between your points and multiply it by our pixel length, we get the distance in microns.
EuclideanDistance[{5.5, 39.5}, {13.9828, 37.5345}] * pixelLength
Quantity[0.687437, "Microns"]
This answer will not hold up well if the bar is not always aligned perfectly to the image border, as it is in your test image. You could consider ComponentMeasurements[c, "Length"]
or "CaliperLength"
to get the length of the bar instead in that case. However, it may take the distances between opposite corners of the bar, which may not be what you want.