2

I am developing an application which does image processing in real time to get the y-sum and time between each frame. They are stored in 2 double arrays and for further implementations i need to run Fast Fourier Transformation on these values.

I have seen several fft algorithms in other questions such as

  1. Stack Overflow Question 1

  2. Stack Overflow Question 2

I have also read topics where they suggesting using JTransform library

However, Since I have very very limited knowledge about FFT, I am not sure how to implement it into my code.

My MainActivity is this

public class MainActivity extends AppCompatActivity implements CameraView.PreviewReadyCallback {
private static Camera camera = null;
private CameraView image = null;
Button fftButton;

private LineChart bp_graph;
private int img_Y_Avg, img_U_Avg, img_V_Avg;
private long end = 0, begin = 0;
Handler handler;
private int readingRemaining = 1200;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    bp_graph = (LineChart)findViewById(R.id.graph);
    fftButton = (Button)findViewById(R.id.runFFT);

    graph_features();

    //open camera
    try {
        camera = Camera.open();

        handler = new Handler();
        final Runnable runnable = new Runnable() {
            @Override
            public void run() {
                camera.stopPreview();
                camera.release();
                fftButton.setVisibility(View.VISIBLE);
            }
        };
        handler.postDelayed(runnable, 30000);

    } catch (Exception e) {
        Log.d("ERROR", "Failed to get camera: " + e.getMessage());
    }

    if (camera != null) {
        image = new CameraView(this, camera);
        FrameLayout camera_view = (FrameLayout) findViewById(R.id.camera_view);
        camera_view.addView(image);
        image.setOnPreviewReady(this);
    }
}


@Override
protected void onResume(){
    super.onResume();
}

@Override
protected void onPause() {
    super.onPause();
}

@Override
public void onPreviewFrame(long startTime, int ySum, int uSum, int vSum, long endTime) {
    begin = startTime;
    img_Y_Avg = ySum;
    img_U_Avg = uSum;
    img_V_Avg = vSum;
    end = endTime;

   showResults(begin, img_Y_Avg, img_U_Avg, img_V_Avg, end);
}

private void showResults(long startTime, int ySum, int uSum, int vSum, long endTime){

    //set value of Y on the text view
    TextView valueOfY = (TextView)findViewById(R.id.valueY);
    //valueY = img_Y_Avg;
    valueOfY.setText(String.valueOf(img_Y_Avg));

    //start time in milliseconds
    long StartDurationInMs = TimeUnit.MILLISECONDS.convert(begin, TimeUnit.MILLISECONDS);
    ArrayList<Long> startOfTime = new ArrayList<>();
    startOfTime.add(StartDurationInMs);

    //store value to array list
    ArrayList<Integer> yAverage = new ArrayList<>();
    yAverage.add(img_Y_Avg);

    ArrayList<Long> getValues = new ArrayList<>();

    for(int i = 0; i < yAverage.size(); i++) {
        getValues.add(startOfTime.get(i));
        getValues.add((long)(yAverage.get(i)));
    }

    storeCsv(yAverage, getValues);
    Log.d("MyEntryData", String.valueOf(getValues));

}

/**
 * method to store raw time and y-sum data into CSV file**/
public void storeCsv(ArrayList<Integer>yAverage, ArrayList<Long>getValues){

    String filename = "temporary.csv";

    //File directoryDownload = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/bpReader";
    //File logDir = new File (directoryDownload, "bpReader"); //Creates a new folder in DOWNLOAD directory
    File logDir = new File(path);
    logDir.mkdirs();
    File file = new File(logDir, filename);


    FileOutputStream outputStream = null;
       try {
           file.createNewFile();
           outputStream = new FileOutputStream(file, true);
           //outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
           for (int i = 0; i < yAverage.size(); i += 2) {
               outputStream.write((getValues.get(i) + ",").getBytes());
               outputStream.write((getValues.get(i + 1) + "\n").getBytes());
               //outputStream.write((getValues.get(i + 2) + ",").getBytes());
               //outputStream.write((getValues.get(i + 3) + "\n").getBytes());
           }
           outputStream.flush();
           outputStream.close();
       } catch (Exception e) {
           e.printStackTrace();
       }

}

//Method for button which appears after the reading is done and the data is saved into csv file
public void readFile(View view){
    readCsv();
}
//Method to read the data from the csv and get the time and y-sum value
public void readCsv(){
    String getPath = Environment.getExternalStorageDirectory() + "/bpReader";
    String csvFile = "temporary.csv";
    String path = getPath+ "/" + csvFile;


    int length = 500;
    double[] xCoords = new double[length];
    double[] yCoords = new double[length];
    double[] newXcord = new double[length];

    CSVReader reader;

    try {
        File myFile = new File (path);
        reader = new CSVReader(new FileReader(myFile));
        String[] line;
        int i;
        for (i = 0; i < xCoords.length; i ++){
            if ((line = reader.readNext()) != null){
                xCoords[i] = Double.parseDouble(line[0]);
                yCoords[i] = Double.parseDouble(line[1]);
            }
        }

        for (i = 0; i < xCoords.length ; i++){
            if (xCoords[i]!=0) {
                newXcord[i] = xCoords[i] - xCoords[0];

                Log.d("read:: ", "Time: " + String.valueOf(newXcord[i]) + " Y-Sum " + String.valueOf(yCoords[i]));
            }
        }
        myFile.delete();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
}
}

After I have read the CSV file in readCsv() method, i get data like this

10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 0.0 Y-Sum 570194.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 50.0 Y-Sum 405504.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 118.0 Y-Sum 405504.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 168.0 Y-Sum 405504.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 234.0 Y-Sum 429242.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 301.0 Y-Sum 1217635.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 368.0 Y-Sum 1516666.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 418.0 Y-Sum 1495037.0
10-15 16:37:50.127 16912-16912/redlight55.com.bpreader D/read::: Time: 486.0 Y-Sum 1514453.0
10-15 16:37:50.128 16912-16912/redlight55.com.bpreader D/read::: Time: 553.0 Y-Sum 1507075.0
10-15 16:37:50.128 16912-16912/redlight55.com.bpreader D/read::: Time: 625.0 Y-Sum 1511241.0
10-15 16:37:50.128 16912-16912/redlight55.com.bpreader D/read::: Time: 678.0 Y-Sum 1476090.0
10-15 16:37:50.128 16912-16912/redlight55.com.bpreader D/read::: Time: 749.0 Y-Sum 1476961.0
10-15 16:37:50.128 16912-16912/redlight55.com.bpreader D/read::: Time: 815.0 Y-Sum 1470232.0

My FFT class is this which i got from some of the suggestions in other stack overflow questions.

public class FFT {

/**
 * The Fast Fourier Transform (generic version, with NO optimizations).
 *
 * @param inputReal
 *            an array of length n, the real part
 * @param inputImag
 *            an array of length n, the imaginary part
 * @param DIRECT
 *            TRUE = direct transform, FALSE = inverse transform
 * @return a new array of length 2n
 */
public static double[] fft(final double[] inputReal, double[] inputImag,
                           boolean DIRECT) {
    // - n is the dimension of the problem
    // - nu is its logarithm in base e
    int n = inputReal.length;

    // If n is a power of 2, then ld is an integer (_without_ decimals)
    double ld = Math.log(n) / Math.log(2.0);

    // Here I check if n is a power of 2. If exist decimals in ld, I quit
    // from the function returning null.
    if (((int) ld) - ld != 0) {
        System.out.println("The number of elements is not a power of 2.");
        return null;
    }

    // Declaration and initialization of the variables
    // ld should be an integer, actually, so I don't lose any information in
    // the cast
    int nu = (int) ld;
    int n2 = n / 2;
    int nu1 = nu - 1;
    double[] xReal = new double[n];
    double[] xImag = new double[n];
    double tReal, tImag, p, arg, c, s;

    // Here I check if I'm going to do the direct transform or the inverse
    // transform.
    double constant;
    if (DIRECT)
        constant = -2 * Math.PI;
    else
        constant = 2 * Math.PI;

    // I don't want to overwrite the input arrays, so here I copy them. This
    // choice adds \Theta(2n) to the complexity.
    for (int i = 0; i < n; i++) {
        xReal[i] = inputReal[i];
        xImag[i] = inputImag[i];
    }

    // First phase - calculation
    int k = 0;
    for (int l = 1; l <= nu; l++) {
        while (k < n) {
            for (int i = 1; i <= n2; i++) {
                p = bitReverseReference(k >> nu1, nu);
                // direct FFT or inverse FFT
                arg = constant * p / n;
                c = Math.cos(arg);
                s = Math.sin(arg);
                tReal = xReal[k + n2] * c + xImag[k + n2] * s;
                tImag = xImag[k + n2] * c - xReal[k + n2] * s;
                xReal[k + n2] = xReal[k] - tReal;
                xImag[k + n2] = xImag[k] - tImag;
                xReal[k] += tReal;
                xImag[k] += tImag;
                k++;
            }
            k += n2;
        }
        k = 0;
        nu1--;
        n2 /= 2;
    }

    // Second phase - recombination
    k = 0;
    int r;
    while (k < n) {
        r = bitReverseReference(k, nu);
        if (r > k) {
            tReal = xReal[k];
            tImag = xImag[k];
            xReal[k] = xReal[r];
            xImag[k] = xImag[r];
            xReal[r] = tReal;
            xImag[r] = tImag;
        }
        k++;
    }

    // Here I have to mix xReal and xImag to have an array (yes, it should
    // be possible to do this stuff in the earlier parts of the code, but
    // it's here to readibility).
    double[] newArray = new double[xReal.length * 2];
    double radice = 1 / Math.sqrt(n);
    for (int i = 0; i < newArray.length; i += 2) {
        int i2 = i / 2;
        // I used Stephen Wolfram's Mathematica as a reference so I'm going
        // to normalize the output while I'm copying the elements.
        newArray[i] = xReal[i2] * radice;
        newArray[i + 1] = xImag[i2] * radice;
    }
    return newArray;
}

/**
 * The reference bitreverse function.
 */
private static int bitReverseReference(int j, int nu) {
    int j2;
    int j1 = j;
    int k = 0;
    for (int i = 1; i <= nu; i++) {
        j2 = j1 / 2;
        k = 2 * k + j1 - 2 * j2;
        j1 = j2;
    }
    return k;
}
}

My Question is

  1. Can I implement this FFT class in my code.
  2. If, yes can anyone direct me on how to do it? I guess i have to perform the fft inside the readCsv method and use the values as input once have read all the values.
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Mill3r
  • 544
  • 1
  • 10
  • 31

0 Answers0