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
Stack Overflow Question 1
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
Can I implement this FFT class in my code.
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.
Related
With same instance of 'interpreter' score is getting increased for same image until it reaches at some saturation.
Interpreter tflite = new Interpreter(loadModelFile(context));
Create Instance for ImageClassifier and use the same instance to classify Frame and run inference for the same image.
ImageClassifier(Activity activity) throws IOException {
tflite = new Interpreter(loadModelFile(activity));
labelList = loadLabelList(activity);
imgData =
ByteBuffer.allocateDirect(
DIM_BATCH_SIZE
* getImageSizeX()
* getImageSizeY()
* DIM_PIXEL_SIZE
* getNumBytesPerChannel());
imgData.order(ByteOrder.nativeOrder());
filterLabelProbArray = new float[FILTER_STAGES][getNumLabels()];
Log.d(TAG, "Created a Tensorflow Lite Image Classifier.");
}
Classifies a frame for the same image. Same image can be picked up from the Sd card.
private void classifyImage() {
if (classifier == null || getActivity() == null || cameraDevice == null) {
showToast("Uninitialized Classifier or invalid context.");
return;
}
String imgPath = "/storage/emulated/0/DCIM/test.jpg";
Log.d("Image Path is %s", imgPath);
Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
Bitmap newbitmap = Bitmap.createScaledBitmap(bitmap, 299, 299, false);
String textToShow = classifier.classifyFrame(newbitmap);
bitmap.recycle();
showToast(textToShow);
}
classifyFrame() Method of ImageClassifier.java
String classifyFrame(Bitmap bitmap) {
if (tflite == null) {
Log.e(TAG, "Image classifier has not been initialized; Skipped.");
return "Uninitialized Classifier.";
}
convertBitmapToByteBuffer(bitmap);
// Here's where the magic happens!!!
long startTime = SystemClock.uptimeMillis();
runInference();
long endTime = SystemClock.uptimeMillis();
Log.d(TAG, "Timecost to run model inference: " + Long.toString(endTime - startTime));
// Smooth the results across frames.
applyFilter();
// Print the results.
String textToShow = printTopKLabels();
textToShow = Long.toString(endTime - startTime) + "ms" + textToShow;
return textToShow;
}
applyFilter() method of ImageClassifier.java
void applyFilter() {
int numLabels = getNumLabels();
// Low pass filter `labelProbArray` into the first stage of the filter.
for (int j = 0; j < numLabels; ++j) {
filterLabelProbArray[0][j] +=
FILTER_FACTOR * (getProbability(j) - filterLabelProbArray[0][j]);
}
// Low pass filter each stage into the next.
for (int i = 1; i < FILTER_STAGES; ++i) {
for (int j = 0; j < numLabels; ++j) {
filterLabelProbArray[i][j] +=
FILTER_FACTOR * (filterLabelProbArray[i - 1][j] - filterLabelProbArray[i][j]);
}
}
// Copy the last stage filter output back to `labelProbArray`.
for (int j = 0; j < numLabels; ++j) {
setProbability(j, filterLabelProbArray[FILTER_STAGES - 1][j]);
}
}
Prints top-K labels, to be shown in UI as the results.
private String printTopKLabels() {
for (int i = 0; i < getNumLabels(); ++i) {
sortedLabels.add(
new AbstractMap.SimpleEntry<>(labelList.get(i), getNormalizedProbability(i)));
if (sortedLabels.size() > RESULTS_TO_SHOW) {
sortedLabels.poll();
}
}
String textToShow = "";
final int size = sortedLabels.size();
for (int i = 0; i < size; ++i) {
Map.Entry<String, Float> label = sortedLabels.poll();
textToShow = String.format("\n%s: %4.2f", label.getKey(), label.getValue()) + textToShow;
}
return textToShow;
}
At the first time when application gets launched score the image classification is 0.06 and then again if we called classifyImage() on some event click score gets increased to 0.13 and with same process it keeps increasing until it reached to 0.86(saturation).
I am not sure why its happening but it happened for both type of TfLite models inceptionV3 and MobileNet.
The results are filtered by the applyFilter method. It is a simple low pass filter, so the scores gradually arrive at their medium-term average. Comment out the call to applyFilter and it should respond instantly, but maybe too jittery for some applications.
ArrayList<String> list1 = splitFileList;
for (int i = 0; i < list1.size(); i++) {
tempFileName = splitFileList.get(i);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + list1.get(i) + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
new TrimmVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)).execute();
}
}
below is my Asynktask which i am trying execute inside for loop
private class TrimmVideo extends AsyncTask<Void, Void, Void> {
private final String mediaPath;
private final double endTime;
private final int length;
private double startTime;
private ProgressDialog progressDialog;
private TrimmVideo(String mediaPath, int startTime, int length) {
this.mediaPath = mediaPath;
this.startTime = startTime;
this.length = length;
this.endTime = this.startTime + this.length;
}
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(VideoPlayActvity.this,
"Trimming videos", "Please wait...", true);
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
trimVideo();
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
btn_save_video.setVisibility(View.INVISIBLE);
super.onPostExecute(result);
}
private void trimVideo() {
try {
File file = new File(mediaPath);
FileInputStream fis = new FileInputStream(file);
FileChannel in = fis.getChannel();
Movie movie = MovieCreator.build(in);
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
boolean timeCorrected = false;
// Here we try to find a track that has sync samples. Since we can only start decoding
// at such a sample we SHOULD make sure that the start of the new fragment is exactly
// such a frame
for (Track track : tracks) {
if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
if (timeCorrected) {
// This exception here could be a false positive in case we have multiple tracks
// with sync samples at exactly the same positions. E.g. a single movie containing
// multiple qualities of the same video (Microsoft Smooth Streaming file)
//throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");
} else {
startTime = correctTimeToNextSyncSample(track, startTime);
timeCorrected = true;
}
}
}
for (Track track : tracks) {
long currentSample = 0;
double currentTime = 0;
long startSample = -1;
long endSample = -1;
for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
for (int j = 0; j < entry.getCount(); j++) {
// entry.getDelta() is the amount of time the current sample covers.
if (currentTime <= startTime) {
// current sample is still before the new starttime
startSample = currentSample;
} else if (currentTime <= endTime) {
// current sample is after the new start time and still before the new endtime
endSample = currentSample;
} else {
// current sample is after the end of the cropped video
break;
}
currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
}
movie.addTrack(new CroppedTrack(track, startSample, endSample));
}
IsoFile out = new DefaultMp4Builder().build(movie);
File storagePath = new File(getExternalFilesDir(null) + "/" + Constant.SPLIT_VIDEO + "/");
storagePath.mkdirs();
File myMovie = new File(storagePath, fileModel == null ? "/" + tempFileName + Constant.FILE_EXTENSION : fileModel.getfilename() + Constant.FILE_EXTENSION);
FileOutputStream fos = new FileOutputStream(myMovie);
FileChannel fc = fos.getChannel();
out.getBox(fc);
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
fc.close();
fos.close();
fis.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private double correctTimeToNextSyncSample(Track track, double cutHere) {
double[] timeOfSyncSamples = new double[track.getSyncSamples().length];
long currentSample = 0;
double currentTime = 0;
for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
for (int j = 0; j < entry.getCount(); j++) {
if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) {
// samples always start with 1 but we start with zero therefore +1
timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime;
}
currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
}
for (double timeOfSyncSample : timeOfSyncSamples) {
if (timeOfSyncSample > cutHere) {
return timeOfSyncSample;
}
}
return timeOfSyncSamples[timeOfSyncSamples.length - 1];
}
}
splitFileList list Contain 2 Size data a,b i want to execute synchronously one by one i.e loop start from 0 then it should complete asynk task for 0 then if loop will go one then it should complete please suggest me how to execute asynk task one by one in for loop .
You can't run synchronously by AsyncTask You must use thread some thing like this:
Thread t = new Thread(
new Runnable() {
public void run() {
try {
ArrayList<String> list1 = splitFileList;
for (int i = 0; i < list1.size(); i++) {
tempFileName = splitFileList.get(i);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + list1.get(i) + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
trimVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)); //here you can run synchronously work
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
try {
t.join();
.....
} catch (Exception e) {
e.printStackTrace();
}
private void trimVideo(String mediaPath, int startTime, int length) {
try {
File file = new File(mediaPath);
FileInputStream fis = new FileInputStream(file);
FileChannel in = fis.getChannel();
Movie movie = MovieCreator.build(in);
List<Track> tracks = movie.getTracks();
movie.setTracks(new LinkedList<Track>());
boolean timeCorrected = false;
// Here we try to find a track that has sync samples. Since we can only start decoding
// at such a sample we SHOULD make sure that the start of the new fragment is exactly
// such a frame
for (Track track : tracks) {
if (track.getSyncSamples() != null && track.getSyncSamples().length > 0) {
if (timeCorrected) {
// This exception here could be a false positive in case we have multiple tracks
// with sync samples at exactly the same positions. E.g. a single movie containing
// multiple qualities of the same video (Microsoft Smooth Streaming file)
//throw new RuntimeException("The startTime has already been corrected by another track with SyncSample. Not Supported.");
} else {
startTime = correctTimeToNextSyncSample(track, startTime);
timeCorrected = true;
}
}
}
for (Track track : tracks) {
long currentSample = 0;
double currentTime = 0;
long startSample = -1;
long endSample = -1;
for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
for (int j = 0; j < entry.getCount(); j++) {
// entry.getDelta() is the amount of time the current sample covers.
if (currentTime <= startTime) {
// current sample is still before the new starttime
startSample = currentSample;
} else if (currentTime <= endTime) {
// current sample is after the new start time and still before the new endtime
endSample = currentSample;
} else {
// current sample is after the end of the cropped video
break;
}
currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
}
movie.addTrack(new CroppedTrack(track, startSample, endSample));
}
IsoFile out = new DefaultMp4Builder().build(movie);
File storagePath = new File(getExternalFilesDir(null) + "/" + Constant.SPLIT_VIDEO + "/");
storagePath.mkdirs();
File myMovie = new File(storagePath, fileModel == null ? "/" + tempFileName + Constant.FILE_EXTENSION : fileModel.getfilename() + Constant.FILE_EXTENSION);
FileOutputStream fos = new FileOutputStream(myMovie);
FileChannel fc = fos.getChannel();
out.getBox(fc);
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
fc.close();
fos.close();
fis.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private double correctTimeToNextSyncSample(Track track, double cutHere) {
double[] timeOfSyncSamples = new double[track.getSyncSamples().length];
long currentSample = 0;
double currentTime = 0;
for (int i = 0; i < track.getDecodingTimeEntries().size(); i++) {
TimeToSampleBox.Entry entry = track.getDecodingTimeEntries().get(i);
for (int j = 0; j < entry.getCount(); j++) {
if (Arrays.binarySearch(track.getSyncSamples(), currentSample + 1) >= 0) {
// samples always start with 1 but we start with zero therefore +1
timeOfSyncSamples[Arrays.binarySearch(track.getSyncSamples(), currentSample + 1)] = currentTime;
}
currentTime += (double) entry.getDelta() / (double) track.getTrackMetaData().getTimescale();
currentSample++;
}
}
for (double timeOfSyncSample : timeOfSyncSamples) {
if (timeOfSyncSample > cutHere) {
return timeOfSyncSample;
}
}
return timeOfSyncSamples[timeOfSyncSamples.length - 1];
}
If you can't implement #Hazem answer you can go with another approach.
For this you need to maintain counter for each of your data and forget about for loop.
First you need to call asynctask for first position of your list.Something like this:
if(list1.size() > 0) {
fileCounter=0;
tempFileName = splitFileList.get(fileCounter);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + tempFileName + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
new TrimmVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)).execute();
}
}
Then in onPostExecute of your asyncTask
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
dbHandler.updateFlag(fileModel == null ? tempFileName : fileModel.getfilename());
btn_save_video.setVisibility(View.INVISIBLE);
super.onPostExecute(result);
// Update your counter here
fileCounter++;
// Check if your incremented counter doesn't exceed your list size
if(fileCounter < list1.size()) {
// Then call your asynctask again with updated counter data
empFileName = splitFileList.get(fileCounter);
String splitFileCheckinDirectory = splitVideofilepath + Constant.SPLIT_VIDEO + "/" + tempFileName + Constant.FILE_EXTENSION;
File myfile = new File(splitFileCheckinDirectory);
if (!myfile.exists()) {
new TrimmVideo(getExternalFilesDir(null) + "/" + getFileNameFromFilePath(mFilePath), mStartTImelist.get(i), mEndTimelist.get(i) - mStartTImelist.get(i)).execute();
}
}
}
Hope this will help you.
I would like to output a lot of data to my log on Android...but it's truncating the data.
How do I prevent it from truncating my logs?
Logcat truncates data after 4000 characters so you could write it out in chunks:
public static final int LOGCAT_MAX_LINE_LIMIT = 4000;
public static final String TAG = "log_tag";
private void showLog(String message) {
if (message.length() > LOGCAT_MAX_LINE_LIMIT) {
int chunkCount = message.length() / LOGCAT_MAX_LINE_LIMIT;
for (int i = 0; i <= chunkCount; i++) {
int max = LOGCAT_MAX_LINE_LIMIT * (i + 1);
if (max >= message.length()) {
Log.d(TAG, message.substring(LOGCAT_MAX_LINE_LIMIT * i));
} else {
Log.d(TAG, message.substring(LOGCAT_MAX_LINE_LIMIT * i, max));
}
}
} else {
Log.d(TAG, message);
}
}
I am intending to perform FSK demodulation and came across the Androino Project(https://code.google.com/p/androino/source/browse/wiki/AndroinoTerminal.wiki), which reads in data from the Adruino into the phone's audio jack, which is pretty darn cool.
I am trying to go through the code but I can't make sense of some impt values. :((
Why is the bit-high = 22 peaks, bit-low = 6 peaks, private static int HIGH_BIT_N_PEAKS = 12 and private static int LOW_BIT_N_PEAKS = 7?? And why is it 136 samples per encoded bit?
Am I also right to say that the FSK rate of the Adruino is set at 315Hz?
I have attached the hardware(softTerm) codes as well: https://code.google.com/p/androino/source/browse/trunk/arduino/SoftTerm/SoftModem/SoftModem.h and the cpp file is in there as well. Dun have enough reputation points to post both links.
/** Copyright (C) 2011 Androino authors
Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.androino.ttt;
import android.util.Log;
public class FSKModule {
// Experimental results
// Arduino sends "a" character (97) 1100001
// The generated message is 0110.0001
// 136 samples per encoded bit
// total message = 166 bits: 155(high)+1(low)+8bit+stop(high)+end(high)
private static int SAMPLING_FREQUENCY = 44100; //Hz
private static double SAMPLING_TIME = 1.0/SAMPLING_FREQUENCY; //ms
// reading zero+155(high)+1(low)+8bit+stop+end+zero
private static int FREQUENCY_HIGH = 3150;
private static int FREQUENCY_LOW = 1575;
//high: 7 samples/peak
//low : 14 samples/peak
// 1492 samples/message low+8bits+stop+end
// 136 samples/bit (=1492/11)
private static int SAMPLES_PER_BIT = 136;
private static int ENCODING_SAMPLES_PER_BIT = SAMPLES_PER_BIT/2; // 68
// bit-high = 22 peaks
// bit-low = 6 peaks
private static int HIGH_BIT_N_PEAKS = 12;
private static int LOW_BIT_N_PEAKS = 7;
private static int SLOTS_PER_BIT = 4; // 4 parts: determines the size of the part analyzed to count peaks
private static int N_POINTS = SAMPLES_PER_BIT/SLOTS_PER_BIT; // 34=136/4
private static double PEAK_AMPLITUDE_TRESHOLD = 60; // significant sample (not noise)
private static int NUMBER_SAMPLES_PEAK = 4; // minimum number of significant samples to be considered a peak
private static int MINUMUM_NPEAKS = 100; // if lower it means that there is no signal/message
private static final int BIT_HIGH_SYMBOL=2;
private static final int BIT_LOW_SYMBOL=1;
private static final int BIT_NONE_SYMBOL=0;
private static final int CARRIER_MIN_HIGH_BITS=12;
private static final int SOUND_AMPLITUDE = 31000;
private static final String TAG = "FSKModule";
private FSKModule(){
}
private static void debugInfo(String message){
//System.out.println(">>" + message);
Log.w(TAG, "FSKDEC:"+ message);
}
//-----------------------------------------
// DECODING FUNCTIONS
//-----------------------------------------
public static boolean signalAvailable(double[] sound){
FSKModule m = new FSKModule();
int nPoints = N_POINTS;
int nParts = sound.length / nPoints;
int nPeaks = 0;
int startIndex = 0;
int i = 0;
do {
int endIndex = startIndex + nPoints;
int n = m.countPeaks(sound, startIndex, endIndex);
nPeaks += n;
i++;
startIndex = endIndex;
if (nPeaks > MINUMUM_NPEAKS) return true;
} while (i<nParts);
if (nPeaks >3)
debugInfo("signalAvailable() nPeaks=" + nPeaks);
return false;
}
public static int decodeSound(double[] sound){
FSKModule m = new FSKModule();
// processing sound in parts and
//Log.w(TAG, "ENTRO EN processSound");
int[] nPeaks = m.processSound(sound);
if (nPeaks.length == 0) // exit: no signal detected
return -1;
//debugInfo("decodeSound nPeaks=" + nPeaks.length);
// transform number of peaks into bits
//Log.w(TAG, "ENTRO EN parseBits");
int[] bits = m.parseBits(nPeaks);//-------------------------> OK!!
//debugInfo("decodeSound nBits=" + bits.length);
// extract message from the bit array
int message = m.decodeUniqueMessage(bits, sound, nPeaks);
debugInfo("decodeSound(): message="+message + ":" + Integer.toBinaryString(message));
return message;
}
private int decodeUniqueMessageCorrected(int[] nPeaks, int startBit){
int message = 0;
// process nPeaks starting from the end
int index = (startBit+12)*SLOTS_PER_BIT;
// find zero -> non zero transition
for (int i = 0; i < index; i++) {
int i2 = nPeaks[index-i];
int i1 = nPeaks[index-i-1];
debugInfo("zero->nonzero index=" + (index-i) + ": i2=" + i2 + ":i1=" + i1);
if ( (i1-i2)>2) {
index = index-i-1;
break;
}
}
debugInfo("zero->nonzero index=" + index);
int[] bits = new int[2+8+1+2];
for (int i = 0; i < bits.length; i++) {
int peakCounter = 0;
for (int j = 0; j < 4; j++) {
peakCounter += nPeaks[index-j];
}
debugInfo("decode corrected: peakCounter="+i + ":" + peakCounter);
if (peakCounter > 7) { //LOW_BIT_N_PEAKS)
bits[i] = BIT_LOW_SYMBOL;
}
if (peakCounter > 12) { //LOW_BIT_N_PEAKS)
bits[i] = BIT_HIGH_SYMBOL;
message += Math.pow(2, i);
}
debugInfo("bit=" + bits[i] + ":" + message);
index = index -4;
}
debugInfo("decode corrected: message="+message + ":" + Integer.toBinaryString(message));
message = 0;
for (int i = 2; i < 10; i++) {
if ( bits[i] == BIT_HIGH_SYMBOL) {
message+= Math.pow(2, 7-(i-2));
}
}
return message;
}
private int decodeUniqueMessage(int[] bits, double[] sound, int[] nPeaks){
// start bit
int index = findStartBit(bits, 0);
debugInfo("decodeUniqueMessage():start bit=" + index);
if (index == -1) return -1; // no start-bit detected
if (index + 8 + 2 > bits.length)
throw new AndroinoException("Message cutted, start bit at " + index, AndroinoException.TYPE_FSK_DECODING_ERROR);
// debugging information
int number = 16; // n bits to debug
for (int i = index-5; i < index-5+number; i++) {
debugInfo("decodeUniqueMessage(): bits=" + i +":" + bits[i] );
}
for (int i = 0; i < number*SLOTS_PER_BIT; i++) {
int position = i + (index-5)*SLOTS_PER_BIT ;
debugInfo("decodeUniqueMessage(): npeaks=" + position+ ":" + nPeaks[position] );
}
// 8bits message
int value = 0;
for (int i = 0; i < 8; i++) {
int bit = bits[index+i];
if (bit==BIT_HIGH_SYMBOL) value+=Math.pow(2, i);
}
// stop bit: do nothing
// end bit: do nothing
debugInfo("MESSAGE =" + Integer.toBinaryString(value) + ":" + value);
*/
int correctedMessage = decodeUniqueMessageCorrected(nPeaks,index);
debugInfo("MESSAGE corrected=" + Integer.toBinaryString(correctedMessage) + ":" + correctedMessage);
return correctedMessage;
}
private int findStartBit(int[] bits, int startIndex){
// find carrier and start bit
int index = startIndex;
int highCounter = 0;
boolean startBitDetected = false;
do {
int bit = bits[index];
switch (bit) {
case BIT_HIGH_SYMBOL:
highCounter++; // carrier high bit
break;
case BIT_LOW_SYMBOL:
if (highCounter>CARRIER_MIN_HIGH_BITS) { // start-bit detected
startBitDetected = true;
}
else highCounter = 0; // reset carrier counter
break;
case BIT_NONE_SYMBOL:
highCounter = 0;// reset carrier counter
break;
}
index++;
if (index>=bits.length) return -1;
} while (!startBitDetected);
return index;
}
private int[] parseBits(int[] peaks){
// from the number of peaks array decode into an array of bits (2=bit-1, 1=bit-0, 0=no bit)
//
int i =0;
int lowCounter = 0;
int highCounter = 0;
int nBits = peaks.length /SLOTS_PER_BIT;
int[] bits = new int[nBits];
//i = findNextZero(peaks,i); // do not search for silence
i = findNextNonZero(peaks,i);
int nonZeroIndex = i;
if (i+ SLOTS_PER_BIT >= peaks.length) //non-zero not found
return bits;
do {
//int nPeaks = peaks[i]+peaks[i+1]+peaks[i+2]+peaks[i+3];
int nPeaks = 0;
for (int j = 0; j < SLOTS_PER_BIT; j++) {
nPeaks+= peaks[i+j];
}
int position = i/SLOTS_PER_BIT;
bits[position] = BIT_NONE_SYMBOL;
debugInfo("npeaks:i=" + i + ":pos=" + position+ ": nPeaks=" + nPeaks);
if (nPeaks>= LOW_BIT_N_PEAKS) {
//Log.w(TAG, "parseBits NPEAK=" + nPeaks);
bits[position] = BIT_LOW_SYMBOL;
lowCounter++;
}
if (nPeaks>=HIGH_BIT_N_PEAKS ) {
bits[position] = BIT_HIGH_SYMBOL;
highCounter++;
}
//if (nPeaks>5) bits[position] = 1;
//if (nPeaks>12) bits[position] = 2;
i=i+SLOTS_PER_BIT;
} while (SLOTS_PER_BIT+i<peaks.length);
lowCounter = lowCounter - highCounter;
debugInfo("parseBits nonZeroIndex=" + nonZeroIndex);
debugInfo("parseBits lows=" + lowCounter);
debugInfo("parseBits highs=" + highCounter);
return bits;
}
private int findNextNonZero(int[] peaks, int startIndex){
// returns the position of the next value != 0 starting form startIndex
int index = startIndex;
int value = 1;
do {
value = peaks[index];
index++;
} while (value==0 && index<peaks.length-1);
return index-1;
}
private int[] processSound(double[] sound){
// split the sound array into slots of N_POINTS and calculate the number of peaks
int nPoints = N_POINTS;
int nParts = sound.length / nPoints;
int[] nPeaks = new int[nParts];
int startIndex = 0;
int i = 0;
int peakCounter = 0;
do {
int endIndex = startIndex + nPoints;
int n = this.countPeaks(sound, startIndex, endIndex);
nPeaks[i] = n;
peakCounter += n;
i++;
startIndex = endIndex;
} while (i<nParts);
//} while (startIndex+nPoints<sound.length);
debugInfo("processSound() peaksCounter=" + peakCounter);
if (peakCounter < MINUMUM_NPEAKS) {
nPeaks = new int[0];
}
return nPeaks;
}
private int countPeaks(double[] sound, int startIndex, int endIndex){
// count the number of peaks in the selected interval
// peak identification criteria: sign changed and several significant samples (>PEAK_AMPLITUDE_TRESHOLD)
int index = startIndex;
int signChangeCounter = 0;
int numberSamplesGreaterThresdhold = 0;
int sign = 0; // initialized at the first significant value
do {
double value = sound[index];
if (Math.abs(value)>PEAK_AMPLITUDE_TRESHOLD)
numberSamplesGreaterThresdhold++; //significant value
// sign initialization: take the sign of the first significant value
if (sign==0 & numberSamplesGreaterThresdhold>0) sign = (int) (value / Math.abs(value));
boolean signChanged = false;
if (sign <0 & value >0) signChanged = true;
if (sign >0 & value <0) signChanged = true;
if (signChanged & numberSamplesGreaterThresdhold>NUMBER_SAMPLES_PEAK){
signChangeCounter++; // count peak
sign=-1*sign; //change sign
}
index++;
//debugInfo(">>>>>>>index=" + index + " sign=" + sign + " signChangeCounter=" + signChangeCounter + " value=" + value + " numberSamplesGreaterThresdhold=" + numberSamplesGreaterThresdhold);
} while (index<endIndex);
return signChangeCounter;
}
}
Now I am developing a reader. If the txt file is too big, it will spend a long time to read and no response. So I want to set a method like it can read the txt file in bathes.
I write the below code. It can turn the page back. But it can not page up continuous. How should I do?
Vector string;
int begin = 0;
public void readTxtByPage(String fileName) {
string.clear();
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(filePath + fileName);
br = new BufferedReader(fr);
br.skip(begin);
String content = "";
char ch;
int line = 0;
int w;
int len;
int start;
FontMetrics fm = paint.getFontMetrics();
fontHeight = (int) Math.ceil(fm.descent - fm.top) + 2;
pageLineNum = textHeight / fontHeight;
float[] widths = new float[1];
while ((content = br.readLine()) != null) {
len = content.length();
w = 0;
start = 0;
for (int i = 0; i < len; i++) {
ch = content.charAt(i);
paint.getTextWidths(String.valueOf(ch), widths);
w += Math.ceil(widths[0]);
if (w > textWidth) {
string.addElement(content.substring(start, i));
begin += (i - start);
start = i;
w = 0;
line++;
if (line >= pageLineNum) {
System.out.println("begin===>"+begin);
return;
}
}
}
string.addElement(content.substring(start));
begin += (len + 2 - start);
line++;
if (line >= pageLineNum) {
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return;
}
Thanks in advance!
Sounds like it would be best if you did this work in a background thread then, you can tell the reader to sleep, and then notify it when you want the thread to start reading again. That way it wont freeze your UI and it can read the bits in batches. Maybe have the thread be notified during an onTouchEvent.