Figure 3 - Diagram showing how the vectorial distance was measured.
As demonstrated above, because the number of dust detected between frames are not constant, using a simple closest dust match can not produce a reliable solution. To produce a reliable solution, we must minimize the total sum of the links. In order to achieve this, every combination of link sums must be calculated, either way, even with optimization, the time required in n!, where n is the number of dust. This will be too time consuming to program and to run. Because the frames had relatively few dusts, I solved the problem using an alternate method. Basically, it is similar to the closest dust matching method, but if the closest dust is already taken, then I would search for the next closest dust within a set radius. If the closest dust was found outside the set radius, then this dust will be ignored. Even though this will not achieve a 100% correct solution, but its error rate will be much lower than of the closest dust method, yet it will be much less computationally than the minimum link sum method.
Once all the dust were accounted for, the velocity was calculated, using v = d/t. Where d is the distance calculated earlier, and t is dependent. If the distance was calculated with the use of Adobe Photoshop, then t is the shutter opening time, which is 1/60s, else, it will be the time between 2 frames, which is 1/25s. All the calculations were performed by another Java program due to the repetitive nature of the task.
Because all measurements were in terms of pixels, I had to convert pixels into meaningful SI units. As the pin electrode is clearly visible in the frames, I measured its width in pixels, then measured its physical width. The result: 0.6mm -> 9pixels.
Java program for “Linking” dust particles
import java.io.*;
import java.util.*;
public class scivis
{
public static void main(String[] args) throws Exception
{
BufferedReader f_in1 = new BufferedReader(new FileReader("vortex
01.txt"));
BufferedReader f_in2 = new BufferedReader(new FileReader("vortex
02.txt"));
DataOutputStream f_out = new DataOutputStream(new
BufferedOutputStream(new FileOutputStream("finalres2.txt")));
String temp, s1, s2, s3;
Double X,Y,Z;
double x,y,z;
LinkedList store1;
LinkedList store2;
double filter = 20;
store1 = new LinkedList();
store2 = new LinkedList();
while ((temp = f_in1.readLine()) != null)
{
StringTokenizer tk = new StringTokenizer(temp, ":");
s1 = tk.nextToken();
s2 = tk.nextToken();
X = new Double(s1);
Y = new Double(s2);
x = X.doubleValue();
y = Y.doubleValue();
obj t1 = new obj(x, y);
store1.add(t1);
}
while ((temp = f_in2.readLine()) != null)
{
StringTokenizer tk = new StringTokenizer(temp, ":");
s1 = tk.nextToken();
s2 = tk.nextToken();
X = new Double(s1);
Y = new Double(s2);
x = X.doubleValue();
y = Y.doubleValue();
obj t2 = new obj(x, y);
store2.add(t2);
}
int i = 0;
while ( i < store1.size())
{
int j = 0;
obj temp1 = (obj)store1.get(i);
while (j < store2.size())
{
obj temp2 = (obj)store2.get(j);
if (temp2.used == true)
{
}
else
{
double dist = 0;
dist = Math.sqrt((temp1.x1
- temp2.x1)*
(temp1.x1 - temp2.x1) +
(temp1.y1 - temp2.y1)*(temp1.y1 - temp2.y1));
if (dist < filter)
{
if
((temp1.dist == 0) || (dist < temp1.dist))
{
temp1.dist = dist;
temp1.usable = true;
temp1.x2 = temp2.x1;
temp1.y2 = temp2.y1;
}
}
}
j++;
}
i++;
}
int k = 0;
while (k < store1.size())
{
obj temp3 = (obj)store1.get(k);
if (temp3.usable == true)
{
f_out.writeBytes(temp3.x1 + "\t" +
temp3.y1 +"\t" + temp3.dist + "\r\n");
}
k++;
}
f_out.close();
}
}
The tracking and velocity calculation program is not included due to their sizes. Neither is the obj class which was a simple data structure used in the Java program above.