15
$\begingroup$

I have as example a set of 30 gray scale images (8bit, 568*478 pixels, they are avalable here: https://drive.google.com/open?id=0B9wKP6yNcpyfMm0ycGZHMjJrRlE) where bright objects on dark background move from image to image mainly horizontally with different velocities (at the upper and lower edge to the left, in the center to right).

This is how the animated gif (5fps) of the images looks like:

enter image description here

My aim is to measure what the mean velocity of the objects is and in which direction they are in average moving.

For that it would be sufficient to subdivide each image in e.g. 10 times 10 rectangles (and determine in each the mean velocity and direction.) I do not want to track the individual single objects coordinates (since this is often not possible when they overlap in an image).

To get a qualitative impression about the overall movement I tried two methods:

a. Superposition of maximum brightness in all images.

enter image description here

We have here a qualitative measure for the velocities but not their direction.

b. Consecutive superposition of images whereby the objects were color coded from blue over green, yellow to red.

enter image description here

In here one can see even in a single image that the objects have different velocities (faster at edges), approximately the positions where they start and end, and in which direction they are streaming (at vertical edges toward left, in the center towards right and in some parts they don't move much).

To solve my problem I thought ImageFeatureTrack or ImageDisplacements could be appropriate. Unfortunately I have not much experience with these functions and was not successful to come to a result.

ImageDisplacements produces something like that (here only 12 images are used, not to exceed 2MB):

enter image description here

This quick result is not as good as the upper superposition and I don't know how to improve it.

To test ImageFeatureTrack I did the following:

ChoiceDialog[{FileNameSetter[Dynamic[imageDir], "Directory"], 
   Dynamic[imageDir]}];
SetDirectory[imageDir];
fNames = FileNames["*.png"];
numFiles = Length[fNames];

images = Table[Import[fNames[[i]], "PNG"], {i, 1, numFiles}];

{w, h} = ImageDimensions[images[[1]]];
res = ImageFeatureTrack[images, 
   Flatten[Table[{x, y}, {x, .5, w - .5, 56}, {y, .5, h - .5, 47}], 
    1]];

Graphics[{Blue, 
  If[FreeQ[#, _Missing], {Arrowheads[0.025], Arrow[{#}]}] & /@ 
   Transpose[res]}, ImageSize -> {568, 478}]

The result shows in which direction the mean flow is oriented.

How can I extract from this the mean velocity in the different sectors?

enter image description here

I am also thinking about the Particle image velocimetry (https://en.wikipedia.org/wiki/Particle_image_velocimetry), but if something would be possible with functions implemented in Mathematica that would be great.

$\endgroup$
17
$\begingroup$

You can extract the mean velocity from the feature positions returned by ImageFeatureTrack, the main difficulty is to handle the Missing[] data.

In the example below:

  • spots is a list of spot positions in the first image
  • res is the result of feature tracking those spots
  • vel is the spot velocity obtained from the mean Differences of the spot positions in res (excluding those cases where one spot position is Missing[])
  • data is the list of {position, velocity} for each spot, excluding those cases where no velocity could be found

Finally I combine a density plot of the velocity magnitude with a stream plot to show the direction. The legend shows the spot velocity in pixels per frame.

images = Import /@ FileNames[];

spots = ComponentMeasurements[Binarize@images[[1]], "Centroid"][[All, 2]];

res = ImageFeatureTrack[images, spots];

vel = Mean[Cases[Differences[#], {_Real, _Real}]] & /@ Transpose[res]

data = DeleteCases[Transpose[{spots, vel}], {_, Mean[{}]}];

Show[
 ListDensityPlot[data /. {{x_, y_}, vel_} :> {x, y, Norm[vel]}, 
  PlotLegends -> Automatic, ColorFunction -> "DarkRainbow", AspectRatio -> Automatic],
 ListStreamPlot[data, StreamStyle -> LightGray]]

enter image description here

Update: As mrz points out, there is a built-in function for combining the density and stream plots: ListStreamDensityPlot

ListStreamDensityPlot[data /. {pos_, vel_} :> {pos, {vel, Norm[vel]}},
  PlotLegends -> Automatic, ColorFunction -> "DarkRainbow", 
 StreamStyle -> LightGray, AspectRatio -> Automatic]

enter image description here

$\endgroup$
  • $\begingroup$ Is the color table displaying the absolute velocity in (pixels/1) calculated from image to image? When I know the pixel size (14.2x14.3 $\mu m$) how can I adjust the code to consider that? I made a test with another set of 10 similar images (1600*1200 pixels, zip-file: 4.3MB, tinyurl.com/j78b5jm). Here I get the following resulting plot: tinyurl.com/zpgaxca. What could be the reason that at the lower part no density plot is shown although stream lines are visible? $\endgroup$ – mrz Nov 6 '16 at 10:59
  • 1
    $\begingroup$ @mrz, it looks like there is a spurious point in the data. Try data = Select[data, #[[1, 2]] > 400 &]; to remove it. I guess ListStreamPlot is extrapolating streamlines at the lower part of the plot, there is no data there. $\endgroup$ – Simon Woods Nov 6 '16 at 21:17
  • 1
    $\begingroup$ A selection helps - thank you. I found the routine ListStreamDensityPlot. Can that replace your ListDensityPlot and ListStreamPlot? How would it be called? $\endgroup$ – mrz Nov 7 '16 at 12:31
  • 1
    $\begingroup$ @mrz something like ListStreamDensityPlot[data /. {pos_, vel_} :> {pos, {vel, Norm[vel]}}] $\endgroup$ – Simon Woods Nov 7 '16 at 19:54

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.