Skip to content
Commits on Source (38)
No preview for this file type
{
"java.compile.nullAnalysis.mode": "automatic"
}
\ No newline at end of file
This diff is collapsed.
### Accepted feedback:
- "Enhancement in the visual interface" by Manuel Segimon
- "I suggest a potential enhancement in the visual interface. Instead of adding a new object below the current one, consider a design that deletes the current one and adds a new one. This way, the page doesn’t get bigger the more objects you look at, improving the user experience."
- Our front end now should be able to do just that
- "Confusing object selection in browser" by Seyed Reza Sajjadinasab
- "It is not clear what are the different 0-14 objects. Selecting between them didn't result in any change in the output."
- We are adding class display for object numbers to the front end
- "install.txt is misleading" by Seyed Reza Sajjadinasab
- "It is said that the instruction provided is for "A Unix/Linux-based operating system", however, the installation source is a java library from a location in the lab machines. Using it on another Linux system will change "~/.bashrc" and cause problems for further usage of the OS.
The received error:
-bash: /ad/eng/opt/java/add_jdk17.sh: No such file or directory"
- This should be addressed now in the install.txt
- "Ask user what type of object to detect" by Seyed Reza Sajjadinasab
- "You can specify a few types of objects that are detectable. It is not clear now what type of object is detected running mvn exec:java -Dexec.mainClass="yolo.YOLOTest" -Dexec.classpathScope="test". For example, why books are not detected as objects?"
- The class names next to object names should clear this up
### Rejected feedback:
- "Web Interface improvement" by Tejas Thakur Singh
- "Add tabs or a compact grid view in order to fix the organization issues that come with having multiple views open"
- Sort of addressed already by Manuel's feedback
- "Java implementation of the GUI" by Seyed Reza Sajjadinasab
- "It was required to do the majority of the project with Java. I think it's better to provide a Java version for the GUI as well instead of java script GUI."
- We focused on functionality of the GUI for the purposes of our 3D localization, and javascript is better suited with the necessary libraries to perform this task
- "Showing the original video/picture" by Seyed Reza Sajjadinasab
- "The original video can be shown in the browser to make it easier to identify the significance of the tool and the process."
- Our reconstructed dense object map will take this into account. Furthermore, we are going to show the original scenario(s) the VSLAM is performed on during our demo. The final output on the front end is color mapped, so the objects are reletively visible in a 3D display of the scene
- "Window size not adjusted" by Seyed Reza Sajjadinasab
- "The size of the window is not adjusted while using a browser to view the result."
- This seemed to be a sececondary issue to our main goal for the project
- "Command line user interface for image and video" by Seyed Reza Sajjadinasab
- "It will be good if the user can pass the filename to the tool and it does the detection on the specified file."
- We have scripts available to perform this task on the backend, and we provide 2 RGBD datasets where users can perform VSLAM on for our functional front end. We also provide video captured using a monocular camera source that we can perform VSLAM on, but this dataset is not displayed in the front end due to our algorithms incompatibility with depth-less data
### Additional changes
- Improved object tracking algorithm
- Improved VSLAM by incorportaing VSLAM RGBD
- Ability to perform monocularr VSLAM on footage collected from arbitrary data source
- The biggest issue that was raised was the GUI, due to its lack of clarity. We have completely overhauled the frontend, and improved the backend to provide better accuracy. The following list details how we did this:
1. Migrated from the THREE.js pointcloud plotting library to Plotly.js
2. Improved styling of the frontend
...@@ -8,12 +8,11 @@ ...@@ -8,12 +8,11 @@
<artifactId>vslam-objects</artifactId> <artifactId>vslam-objects</artifactId>
<version>1.0</version> <version>1.0</version>
<properties> <properties>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<exec.mainClass>top.BackendJava</exec.mainClass> <exec.mainClass>top.BackendJava</exec.mainClass>
<!-- <exec.mainClass>yolo.YOLODetector</exec.mainClass> -->
</properties> </properties>
<build> <build>
...@@ -126,4 +125,4 @@ ...@@ -126,4 +125,4 @@
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
#!/bin/bash #!/bin/bash
# Define the script that runs the VSLAM implementation # Define the script that runs the VSLAM implementation
<<<<<<< HEAD
<<<<<<< HEAD
MATLAB_SCRIPT="/src/main/java/vslam/vslam_implementation_rgbd.m"
# Check if the correct number of arguments was provided
if [ "$#" -ne 1 ]; then
echo "Usage: $0 {tum_rgbd_dataset|imperial_college_london}"
exit 1
fi
# Determine which dataset to use based on the argument provided
if [ "$1" = "tum_rgbd_dataset" ]; then
DATASET_NAME="tum_rgbd_dataset"
elif [ "$1" = "imperial_college_london" ]; then
DATASET_NAME="imperial_college_london"
else
echo "Invalid dataset name. Choose either 'tum_rgbd_dataset' or 'imperial_college_london'"
exit 2
fi
=======
MATLAB_SCRIPT="/src/main/java/vslam/vslam_implementation.m"
# Define the dataset name
DATASET_NAME="self_made_dataset"
>>>>>>> divider
=======
MATLAB_SCRIPT="/src/main/java/vslam/vslam_implementation.m" MATLAB_SCRIPT="/src/main/java/vslam/vslam_implementation.m"
# Define the dataset name # Define the dataset name
DATASET_NAME="self_made_dataset" DATASET_NAME="self_made_dataset"
>>>>>>> 197296f30ca7b0c49c8308bf3194348f11ab6a30
# Navigate to the MATLAB script directory (assuming MATLAB can be called from command line) # Navigate to the MATLAB script directory (assuming MATLAB can be called from command line)
cd src/main/java/vslam cd src/main/java/vslam
......
File added
No preview for this file type
No preview for this file type
...@@ -34,7 +34,6 @@ public class MongoDBInteraction { ...@@ -34,7 +34,6 @@ public class MongoDBInteraction {
this.mongoClient = MongoClients.create(settings); this.mongoClient = MongoClients.create(settings);
this.database = mongoClient.getDatabase("Objects"); this.database = mongoClient.getDatabase("Objects");
this.objectCollection = database.getCollection("objectSets"); this.objectCollection = database.getCollection("objectSets");
System.out.println("MongoDB Connection Established");
} }
...@@ -46,10 +45,8 @@ public class MongoDBInteraction { ...@@ -46,10 +45,8 @@ public class MongoDBInteraction {
try { try {
Document doc = objectCollection.find().sort(new Document("index", -1)).first(); Document doc = objectCollection.find().sort(new Document("index", -1)).first();
if (doc == null) { if (doc == null) {
System.out.println("No document found.");
return null; return null;
} else { } else {
System.out.println("Document found: " + doc.toJson());
return convertDocumentToObjectSet(doc); return convertDocumentToObjectSet(doc);
} }
} catch (Exception e) { } catch (Exception e) {
...@@ -60,13 +57,11 @@ public class MongoDBInteraction { ...@@ -60,13 +57,11 @@ public class MongoDBInteraction {
private ObjectSet convertDocumentToObjectSet(Document doc) { private ObjectSet convertDocumentToObjectSet(Document doc) {
if (doc == null) { if (doc == null) {
System.out.println("Document is null, no conversion possible.");
return null; return null;
} }
List<Document> pointSetDocs = doc.getList("objectSets", Document.class); List<Document> pointSetDocs = doc.getList("objectSets", Document.class);
if (pointSetDocs == null || pointSetDocs.isEmpty()) { if (pointSetDocs == null || pointSetDocs.isEmpty()) {
System.out.println("No point sets found in document.");
return new ObjectSet(); return new ObjectSet();
} }
...@@ -76,7 +71,7 @@ public class MongoDBInteraction { ...@@ -76,7 +71,7 @@ public class MongoDBInteraction {
if (pointSet != null) { if (pointSet != null) {
objectSet.objects.add(pointSet); objectSet.objects.add(pointSet);
} else { } else {
System.out.println("Failed to convert point set document: " + pointSetDoc.toJson()); System.out.println("Failed to convert point set document");
} }
} }
return objectSet; return objectSet;
...@@ -84,14 +79,15 @@ public class MongoDBInteraction { ...@@ -84,14 +79,15 @@ public class MongoDBInteraction {
private PointSet convertDocumentToPointSet(Document doc) { private PointSet convertDocumentToPointSet(Document doc) {
if (doc == null) { if (doc == null) {
System.out.println("PointSet document is null.");
return null; return null;
} }
// Using Integer.parseInt to safely convert String to Integer if necessary // Using Integer.parseInt to safely convert String to Integer if necessary
int idx; int idx;
String pred;
try { try {
idx = doc.get("setId") instanceof Integer ? (Integer) doc.get("setId") : Integer.parseInt((String) doc.get("setId")); idx = doc.get("setId") instanceof Integer ? (Integer) doc.get("setId") : Integer.parseInt((String) doc.get("setId"));
pred = (String) doc.get("predName");
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
System.err.println("Invalid format for setId, must be an integer: " + doc.get("setId")); System.err.println("Invalid format for setId, must be an integer: " + doc.get("setId"));
return null; return null;
...@@ -99,11 +95,10 @@ public class MongoDBInteraction { ...@@ -99,11 +95,10 @@ public class MongoDBInteraction {
List<Document> pointsDocs = doc.getList("points", Document.class); List<Document> pointsDocs = doc.getList("points", Document.class);
if (pointsDocs == null) { if (pointsDocs == null) {
System.out.println("No points found in point set document."); return new PointSet(idx, pred);
return new PointSet(idx);
} }
PointSet pointSet = new PointSet(idx); PointSet pointSet = new PointSet(idx, pred);
for (Document pointDoc : pointsDocs) { for (Document pointDoc : pointsDocs) {
Point point = new Point( Point point = new Point(
pointDoc.getDouble("x").floatValue(), pointDoc.getDouble("x").floatValue(),
...@@ -130,6 +125,7 @@ public class MongoDBInteraction { ...@@ -130,6 +125,7 @@ public class MongoDBInteraction {
.append("B", p.B)); .append("B", p.B));
} }
return new Document("setId", setId) return new Document("setId", setId)
.append("predName", pointSet.getPred())
.append("points", pointsList); .append("points", pointsList);
} }
......
...@@ -3,6 +3,7 @@ package object_detection; ...@@ -3,6 +3,7 @@ package object_detection;
import com.opencsv.exceptions.CsvValidationException; import com.opencsv.exceptions.CsvValidationException;
import database.MongoDBInteraction; import database.MongoDBInteraction;
import object_detection.types.*; import object_detection.types.*;
import org.bytedeco.ffmpeg.avutil.Cmp_Const_Pointer_Const_Pointer;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
...@@ -16,19 +17,28 @@ public class ObjectDetector { ...@@ -16,19 +17,28 @@ public class ObjectDetector {
/** /**
* The starting function that creates an object set, compiles informatino, and returns it * The starting function that creates an object set, compiles informatino, and returns it
* @throws FileNotFoundException * @throws FileNotFoundException : if files have not been created yet
*/ */
public static void startProcess(String dataset) throws IOException, CsvValidationException { public static void startProcess(String dataset) throws IOException, CsvValidationException {
// for now, we can just set paths to the directories that hold keyframes and featurepoint CSVs // for now, we can just set paths to the directories that hold keyframes and featurepoint CSVs
String bbox_dir_pth;
String bbox_dir_pth = "src/main/java/vslam/tum_rgbd/BoundedInfo"; String pose_dir_path;
String pose_dir_path = "src/main/java/vslam/rumrgbd/CameraPoses"; CameraIntrinsics intrinsics;
List<Point> pointCloud;
if(dataset.equals("1")){ if(dataset.equals("1")){
bbox_dir_pth = "src/main/java/vslam/tum_rgbd/BoundedInfo";
pose_dir_path = "src/main/java/vslam/tum_rgbd/CameraPoses";
intrinsics = new CameraIntrinsics("src/main/java/vslam/tum_rgbd/CameraIntrinsics.csv");
pointCloud = Downsampler.get_voxels("src/main/java/vslam/tum_rgbd/pointcloud.csv", 0.05F);
}
else{
bbox_dir_pth = "src/main/java/vslam/imperial_london/BoundedInfo"; bbox_dir_pth = "src/main/java/vslam/imperial_london/BoundedInfo";
pose_dir_path = "src/main/java/vslam/imperial_london/CameraPoses"; pose_dir_path = "src/main/java/vslam/imperial_london/CameraPoses";
} intrinsics = new CameraIntrinsics("src/main/java/vslam/imperial_london/CameraIntrinsics.csv");
pointCloud = Downsampler.get_voxels("src/main/java/vslam/imperial_london/pointcloud.csv", 0.05F);
}
// get files // get files
File[] bbox_CSVs = getDirFiles(bbox_dir_pth); File[] bbox_CSVs = getDirFiles(bbox_dir_pth);
...@@ -41,8 +51,6 @@ public class ObjectDetector { ...@@ -41,8 +51,6 @@ public class ObjectDetector {
/* ################################################# /* #################################################
In the section below, we create a new ObjectSet, and iterate over each Keyframe In the section below, we create a new ObjectSet, and iterate over each Keyframe
################################################## */ ################################################## */
CameraIntrinsics intrinsics = new CameraIntrinsics("src/main/java/vslam/CameraIntrinsics.csv");
List<Point> pointCloud = Downsampler.get_voxels("src/main/java/vslam/pointcloud.csv", 0.05F);
ObjectSet os = new ObjectSet(intrinsics, pointCloud); ObjectSet os = new ObjectSet(intrinsics, pointCloud);
// iterate through each frame, create the frame, then process it // iterate through each frame, create the frame, then process it
...@@ -51,18 +59,7 @@ public class ObjectDetector { ...@@ -51,18 +59,7 @@ public class ObjectDetector {
Frame f = new Frame(bbox_CSVs[i].getPath(), cp); Frame f = new Frame(bbox_CSVs[i].getPath(), cp);
os.processFrame(f); os.processFrame(f);
System.out.println("Processed frame " + i); System.out.println("Processed frame " + i);
if(i == 5){
break;
}
}
Point[] pp = new Point[pointCloud.size()];
int i = 0;
for(Point p : pointCloud){
pp[i] = p;
i++;
} }
os.objects.add(new PointSet(0, pp));
// update MongoDB // update MongoDB
MongoDBInteraction mdbi = new MongoDBInteraction(); MongoDBInteraction mdbi = new MongoDBInteraction();
...@@ -90,9 +87,4 @@ public class ObjectDetector { ...@@ -90,9 +87,4 @@ public class ObjectDetector {
return f_arr; return f_arr;
} }
public static void main(String[] args) throws IOException, CsvValidationException {
startProcess();
}
} }
...@@ -17,6 +17,28 @@ public class BoundingBox2D { ...@@ -17,6 +17,28 @@ public class BoundingBox2D {
&& p.getY() <= (this.y + this.h); && p.getY() <= (this.y + this.h);
} }
/* ##########
Getters
########## */
public String getPredClass() {
return predClass;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getW() {
return w;
}
public int getH() {
return h;
}
// members // members
int x; int x;
......
package object_detection.types;
public class BoundingBox3D {
/**
* This class represents a single object in 3D space, and holds the points that fall within it, and its bounds
* @param ps : the first pointset used to
*/
public BoundingBox3D(PointSet ps){
this.ps = ps;
}
/* ###################
Members
##################### */
private PointSet ps;
}
...@@ -38,6 +38,25 @@ public class CameraIntrinsics { ...@@ -38,6 +38,25 @@ public class CameraIntrinsics {
this.K = new DMatrixRMaj(ktemp); this.K = new DMatrixRMaj(ktemp);
} }
/* ##########
Getters
########## */
public float[] getFocalLength() {
return FocalLength;
}
public float[] getPrincipalPoint() {
return PrincipalPoint;
}
public float[] getImageSize() {
return ImageSize;
}
public DMatrixRMaj getK() {
return K;
}
/* ############### /* ###############
Members Members
############### */ ############### */
...@@ -46,8 +65,4 @@ public class CameraIntrinsics { ...@@ -46,8 +65,4 @@ public class CameraIntrinsics {
float[] ImageSize; float[] ImageSize;
DMatrixRMaj K; DMatrixRMaj K;
public static void main(String[] args) throws FileNotFoundException {
CameraIntrinsics intrinsics = new CameraIntrinsics("/Users/roku/IdeaProjects/group8/src/main/java/vslam/CameraIntrinsics.csv");
}
} }
...@@ -39,6 +39,16 @@ public class CameraPose { ...@@ -39,6 +39,16 @@ public class CameraPose {
}); });
} }
/* ##########
Getters
########## */
public DMatrixRMaj getR() {
return R;
}
public DMatrixRMaj getTranslation() {
return translation;
}
/* ################## /* ##################
Members Members
......
...@@ -31,6 +31,12 @@ public class Frame { ...@@ -31,6 +31,12 @@ public class Frame {
ArrayList<BoundingBox2D> res = new ArrayList<>(); ArrayList<BoundingBox2D> res = new ArrayList<>();
while (scanner.hasNextLine()) { while (scanner.hasNextLine()) {
String[] line = scanner.nextLine().split(","); String[] line = scanner.nextLine().split(",");
double confidence = Double.parseDouble(line[1]);
// only keep boxes with confidence > 88%
if(confidence < 0.82){
continue;
}
// create the box accordingly // create the box accordingly
int x = Integer.parseInt(line[2]); int x = Integer.parseInt(line[2]);
int y = Integer.parseInt(line[3]); int y = Integer.parseInt(line[3]);
...@@ -73,9 +79,9 @@ public class Frame { ...@@ -73,9 +79,9 @@ public class Frame {
// check if point is visible in current frame // check if point is visible in current frame
if(projPoint.get(0,2) > 0){ if(projPoint.get(0,2) > 0){
if(x_div <= intrinsics.ImageSize[1] if(x_div < intrinsics.ImageSize[1]
&& x_div >= 0 && x_div >= 0
&& y_div <= intrinsics.ImageSize[0] && y_div < intrinsics.ImageSize[0]
&& y_div >= 0){ && y_div >= 0){
res.put(i, new Point2D((float) x_div, (float) y_div)); res.put(i, new Point2D((float) x_div, (float) y_div));
} }
...@@ -86,6 +92,21 @@ public class Frame { ...@@ -86,6 +92,21 @@ public class Frame {
return res; return res;
} }
/* ##########
Getters
########## */
public String getBboxPath() {
return bboxpath;
}
public List<BoundingBox2D> getBoxes() {
return boxes;
}
public CameraPose getCamera() {
return camera;
}
/* ######################### /* #########################
Members Members
########################### */ ########################### */
...@@ -93,14 +114,4 @@ public class Frame { ...@@ -93,14 +114,4 @@ public class Frame {
List<BoundingBox2D> boxes; List<BoundingBox2D> boxes;
CameraPose camera; CameraPose camera;
public static void main(String[] args) throws IOException, CsvValidationException {
System.out.println("Trying projection:");
CameraIntrinsics ci = new CameraIntrinsics("src/main/java/vslam/CameraIntrinsics.csv");
List<Point> pc = Downsampler.get_voxels("src/main/java/vslam/pointcloud.csv", 0.05F);
CameraPose cp = new CameraPose("src/main/java/vslam/CameraPoses/Pose_0002.csv");
Frame f = new Frame("src/main/java/vslam/BoundedInfo/KeyFrame_0002.csv", cp);
}
} }
...@@ -32,8 +32,6 @@ public class ObjectSet { ...@@ -32,8 +32,6 @@ public class ObjectSet {
// 2) Create a bitmap that holds the index of the bounding box that contains the pixel at bitmap[i][j] // 2) Create a bitmap that holds the index of the bounding box that contains the pixel at bitmap[i][j]
int[][] bitmap = new int[(int) intrinsics.ImageSize[0]][(int) intrinsics.ImageSize[1]]; int[][] bitmap = new int[(int) intrinsics.ImageSize[0]][(int) intrinsics.ImageSize[1]];
System.out.println(bitmap.length);
System.out.println(bitmap[0].length);
for(int b = 0; b < f.boxes.size(); b++){ for(int b = 0; b < f.boxes.size(); b++){
BoundingBox2D bbox = f.boxes.get(b); BoundingBox2D bbox = f.boxes.get(b);
// for each box, write to all points in bitmap that fall in box // for each box, write to all points in bitmap that fall in box
...@@ -47,7 +45,7 @@ public class ObjectSet { ...@@ -47,7 +45,7 @@ public class ObjectSet {
// 3) Find all points that fall within each box, add point to candidate objects // 3) Find all points that fall within each box, add point to candidate objects
List<PointSet> candidates = new ArrayList<>(); List<PointSet> candidates = new ArrayList<>();
for(int i = 0; i < f.boxes.size(); i++){ for(int i = 0; i < f.boxes.size(); i++){
candidates.add(new PointSet(i)); candidates.add(new PointSet(i, f.boxes.get(i).predClass));
} }
for(Map.Entry<Integer, Point2D> entry : projM.entrySet()){ for(Map.Entry<Integer, Point2D> entry : projM.entrySet()){
...@@ -60,8 +58,8 @@ public class ObjectSet { ...@@ -60,8 +58,8 @@ public class ObjectSet {
// 4) Now that we have a full list of candidate objects, we can do object resolution by combining candidates with overlapping points // 4) Now that we have a full list of candidate objects, we can do object resolution by combining candidates with overlapping points
for(PointSet c : candidates){ for(PointSet c : candidates){
if(c.pset.size() > 2){ if(c.pset.size() > 1000 && c.pset.size() < this.pointCloud.size()*0.75){
this.reconcileCandidate(c, 0.8); this.reconcileCandidate(c, 0.5);
} }
} }
...@@ -76,18 +74,14 @@ public class ObjectSet { ...@@ -76,18 +74,14 @@ public class ObjectSet {
// calculate overlapping points, if beyond some threshold, find intersection of the sets // calculate overlapping points, if beyond some threshold, find intersection of the sets
int count = 0; int count = 0;
for (Point p : obj.pset) { for (Point p : obj.pset) {
for (Point cp : c.pset) { if(c.pset.contains(p)){
if (Point.equals(p, cp, 0.0001F)) { count++;
count++;
break;
}
} }
} }
if (count > (c.pset.size() * threshold)) { if (count >= (obj.pset.size() * threshold)) {
//combine via intersection and return, since we know that we just combined those objects //combine via intersection and return, since we know that we just combined those objects
obj.pset.retainAll(c.pset); obj.pset.retainAll(c.pset);
System.out.println("reconciling");
return; return;
} }
} }
......
package object_detection.types; package object_detection.types;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Point { public class Point {
...@@ -39,13 +41,16 @@ public class Point { ...@@ -39,13 +41,16 @@ public class Point {
return false; return false;
} }
Point p = (Point) o; Point p = (Point) o;
return Point.equals(this, p, (float) 6); return Point.equals(this, p, 0.0001F);
} }
@Override @Override
public int hashCode() { public int hashCode() {
float res = this.x + this.y + this.z; return new HashCodeBuilder(17, 37)
return Float.hashCode(res); .append(this.x)
.append(this.y)
.append(this.z)
.toHashCode();
} }
@Override @Override
public String toString() { public String toString() {
......