Skip to content

Commit

Permalink
csv file merging for scalable exercise and debugging yoga pose implem…
Browse files Browse the repository at this point in the history
…entation
  • Loading branch information
SurajKRB committed Dec 1, 2023
1 parent 9c031d9 commit 3022355
Show file tree
Hide file tree
Showing 13 changed files with 1,612 additions and 68 deletions.
197 changes: 197 additions & 0 deletions app/src/main/assets/pose/lunges.csv

Large diffs are not rendered by default.

139 changes: 139 additions & 0 deletions app/src/main/assets/pose/neutral_standing.csv

Large diffs are not rendered by default.

398 changes: 398 additions & 0 deletions app/src/main/assets/pose/pushups.csv

Large diffs are not rendered by default.

340 changes: 340 additions & 0 deletions app/src/main/assets/pose/situps.csv

Large diffs are not rendered by default.

226 changes: 226 additions & 0 deletions app/src/main/assets/pose/squats.csv

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions app/src/main/assets/pose/treeyoga.csv

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions app/src/main/assets/pose/warrioryoga.csv

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package com.example.poseexercise.posedetector
import android.content.Context
import android.util.Log
import com.example.poseexercise.data.PostureResult
import com.example.poseexercise.data.plan.Plan
import com.example.poseexercise.posedetector.classification.PoseClassifierProcessor
import com.example.poseexercise.util.VisionProcessorBase
import com.example.poseexercise.viewmodels.CameraXViewModel
Expand All @@ -43,13 +44,15 @@ class PoseDetectorProcessor(
private val rescaleZForVisualization: Boolean,
private val runClassification: Boolean,
private val isStreamMode: Boolean,
private var cameraXViewModel: CameraXViewModel? = null
private var cameraXViewModel: CameraXViewModel? = null,
private val notCompletedExercise: List<Plan>
) : VisionProcessorBase<PoseDetectorProcessor.PoseWithClassification>(context) {

private val detector: PoseDetector
private val classificationExecutor: Executor

private var poseClassifierProcessor: PoseClassifierProcessor? = null
private var exercisesToDetect: List<String>? = null

/** Internal class to hold Pose and classification results. */
inner class PoseWithClassification(val pose: Pose, classificationResult: Map<String, PostureResult>) {
Expand All @@ -65,6 +68,9 @@ class PoseDetectorProcessor(
init {
detector = PoseDetection.getClient(options)
classificationExecutor = Executors.newSingleThreadExecutor()
if(notCompletedExercise.isNotEmpty()) {
exercisesToDetect = notCompletedExercise.map {plan -> plan.exercise}
}
}


Expand All @@ -87,7 +93,8 @@ class PoseDetectorProcessor(
poseClassifierProcessor =
PoseClassifierProcessor(
context,
isStreamMode
isStreamMode,
exercisesToDetect
)
}
classificationResult = poseClassifierProcessor!!.getPoseResult(pose)
Expand All @@ -110,7 +117,8 @@ class PoseDetectorProcessor(
poseClassifierProcessor =
PoseClassifierProcessor(
context,
isStreamMode
isStreamMode,
exercisesToDetect
)
}
classificationResult = poseClassifierProcessor!!.getPoseResult(pose)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,70 +29,174 @@
import com.google.mlkit.vision.pose.Pose;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
* Accepts a stream of {@link Pose} for classification and Rep counting.
*/
public class PoseClassifierProcessor {
private static final String TAG = "PoseClassifierProcessor";

private static final String POSE_SAMPLES_FILE = "pose/fitness_four_exercise_two_yoga_v04.csv";
// File names of all exercise
private static final String SQUAT_FILE = "pose/squats.csv";
private static final String PUSH_UP_FILE = "pose/pushups.csv";
private static final String LUNGE_FILE = "pose/lunges.csv";
private static final String NEUTRAL_STANDING_FILE = "pose/neutral_standing.csv";
private static final String SIT_UP_FILE = "pose/situps.csv";
private static final String TREE_YOGA_FILE = "pose/treeyoga.csv";
private static final String WARRIOR_YOGA_FILE = "pose/warrioryoga.csv";
//private static final String POSE_SAMPLES_FILE = "pose/fitness_four_exercise_two_yoga_v04.csv";

// The class name for the pushups
public static final String PUSHUPS_CLASS = "pushups_down";


// The class name for squat
// The class name for all the exercise
public static final String PUSHUPS_CLASS = "pushups_down";
public static final String SQUATS_CLASS = "squats";

//class name for lunges
public static final String LUNGES_CLASS = "lunges";

// The class name for the situp
public static final String SITUP_UP_CLASS = "situp_up";

// The class name for the yoga pose
public static final String WARRIOR_CLASS = "warrior";

// The class name for the yoga tree pose
public static final String YOGA_TREE_CLASS = "tree_pose";

public static final String[] POSE_CLASSES = {
PUSHUPS_CLASS, SQUATS_CLASS, LUNGES_CLASS, SITUP_UP_CLASS, WARRIOR_CLASS, YOGA_TREE_CLASS

};

private final boolean isStreamMode;

private EMASmoothing emaSmoothing;
private List<RepetitionCounter> repCounters;
private PoseClassifier poseClassifier;

private final Map<String, PostureResult> postureResults = new HashMap<>();


@WorkerThread
public PoseClassifierProcessor(Context context, boolean isStreamMode) {
public PoseClassifierProcessor(Context context, boolean isStreamMode, List<String> plan) {

Preconditions.checkState(Looper.myLooper() != Looper.getMainLooper());
this.isStreamMode = isStreamMode;
if (isStreamMode) {
emaSmoothing = new EMASmoothing();
repCounters = new ArrayList<>();
}
loadPoseSamples(context);

if(plan != null){
Log.d("pose_classifier_processor: ", plan.toString());
Log.d("pose_classifier_processor: ", mapExercisesToFiles(plan).toString());
}

//loadPoseSamples(context);
combineAndLoadPoseSamples(context, mapExercisesToFiles(plan));
}

private void combineAndLoadPoseSamples(Context context, List<String> mappedPlan) {
// Ensure the combined file exists in internal storage
String combinedFilePath = context.getFilesDir().getPath() + File.separator + "combined_poses.csv";

createNewFileReplacingPrevious(combinedFilePath);

// Combine separate CSV files into a new combined file
combineCSVFiles(context, combinedFilePath, mappedPlan);

// Now, load pose samples from the combined file
loadPoseSamples(context, combinedFilePath);
}

private void createNewFileReplacingPrevious(String filePath) {
try {
File file = new File(filePath);
if (file.exists() && !file.isDirectory()) {
file.delete();
}
file.createNewFile();
} catch (IOException e) {
Log.e(TAG, "Error creating file: " + filePath + "\n" + e);
}
}

private void combineCSVFiles(Context context, String outputPath, List<String> inputFiles) {
try (PrintWriter writer = new PrintWriter(new FileWriter(outputPath))) {
for (String inputFile : inputFiles) {
BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(inputFile)));
String csvLine = reader.readLine();
while (csvLine != null) {
writer.println(csvLine);
csvLine = reader.readLine();
}
// Add an empty line between files
writer.println();

reader.close();
}
} catch (IOException e) {
Log.e(TAG, "Error when combining CSV files.\n" + e);
}
}


private static List<String> mapExercisesToFiles(List<String> exercises) {
List<String> files = new ArrayList<>();
Set<String> uniqueFileNames = new HashSet<>();

if(exercises != null){
for (String exercise : exercises) {
switch (exercise) {
case "Squat":
addUniqueFile(files, uniqueFileNames, SQUAT_FILE);
addUniqueFile(files, uniqueFileNames, NEUTRAL_STANDING_FILE);
addUniqueFile(files, uniqueFileNames, LUNGE_FILE);
break;
case "Push up":
addUniqueFile(files, uniqueFileNames, PUSH_UP_FILE);
break;
case "Sit up":
addUniqueFile(files, uniqueFileNames, SIT_UP_FILE);
break;
case "Lunge":
addUniqueFile(files, uniqueFileNames, LUNGE_FILE);
addUniqueFile(files, uniqueFileNames, NEUTRAL_STANDING_FILE);
addUniqueFile(files, uniqueFileNames, SQUAT_FILE);
break;
// Add more cases for other exercises if needed
default:
break;
}
}
}

// Exercise by Default
addUniqueFile(files, uniqueFileNames, LUNGE_FILE);
addUniqueFile(files, uniqueFileNames, NEUTRAL_STANDING_FILE);
addUniqueFile(files, uniqueFileNames, SQUAT_FILE);
files.add(WARRIOR_YOGA_FILE);
files.add(TREE_YOGA_FILE);

return files;
}

private static void addUniqueFile(List<String> files, Set<String> uniqueFileNames, String fileName) {
if (uniqueFileNames.add(fileName)) {
// If the file name is unique, add it to the list
files.add(fileName);
}
}

private void loadPoseSamples(Context context) {

private void loadPoseSamples(Context context, String filePath) {
List<PoseSample> poseSamples = new ArrayList<>();
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(context.getAssets().open(POSE_SAMPLES_FILE)));

BufferedReader reader = new BufferedReader(new FileReader(filePath));

String csvLine = reader.readLine();
while (csvLine != null) {
// If line is not a valid {@link PoseSample}, we'll get null and skip adding to the list.
Expand Down
Loading

0 comments on commit 3022355

Please sign in to comment.