2 - Procedure for Data Extraction

In order to break the video footage recorded by the CCD camera into frames, I first converted the footage into mpeg format with the use of a Studio10Plus capture card. Then with the use of Adobe Premier, I exported this mpeg file into a sequence of grayscale bitmap files. As circled above, there are regions where the dusts are not recognizable (i.e. blurred). This blurring arises from the finite shutter rate of the CCD camera, it indicates the dusts travel a significant distance within the opening and the closing of the shutter, thus a trail was exposed to the camera. In order to account for dusts in these region, Adobe Photoshop was use manually to identify the each length of such lines. This process with work intensive, but necessary. The remainder of the dusts was identified with the use of a particle tracking program. The tracking program simply outputs the coordinates of each dust. The program was written in C, and it essentially scans through the bitmap file and identify regions of a defined size limit, then calculates and outputs the centre of the region. In order to calculate the distance traveled by a specific dust, the dust must be identified in different frames. This had to be done outside the tracking program, as it only produce coordinates, regardless. In order to match every particle to each other between frames, I wrote a java program to overcome such (see figure 3).
 


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.