Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CV Pipeline Integration #73

Merged
merged 82 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
f0b29e5
initial cv pipeline skeleton
atar13 Jan 4, 2024
01b63fc
added cv utilities tests
atar13 Jan 4, 2024
bbb84fe
mock camera implementation
atar13 Jan 5, 2024
94070c4
SearchState
atar13 Jan 5, 2024
dff1aee
unit test mock camera
atar13 Jan 5, 2024
dc4fdd8
cv pipeline integration test
atar13 Jan 5, 2024
952e020
moved pathing unit tests to their own folder
atar13 Jan 5, 2024
691b8ec
linter: allow non-Google library versions
Samir-Rashid Jan 15, 2024
534de34
cv: lint camera orchestrator
Samir-Rashid Jan 15, 2024
7bc51f8
added a localization algorithm
dn820 Feb 7, 2024
8094ac2
added terrain height
dn820 Feb 7, 2024
f227506
update ubuntu version :pray: (#78)
Tyler-Lentz Jan 17, 2024
6280e08
Chore/update ubuntu version (#79)
Tyler-Lentz Jan 17, 2024
a43cb42
Chore/update ubuntu version (#80)
Tyler-Lentz Jan 18, 2024
a7c98dd
Chore/update ubuntu version (#81)
Tyler-Lentz Jan 18, 2024
53b0368
Chore/update ubuntu version (#82)
Tyler-Lentz Jan 18, 2024
e0d4fbd
Chore/update ubuntu version (#83)
Tyler-Lentz Jan 18, 2024
3320b54
Chore/update ubuntu version (#84)
Tyler-Lentz Jan 18, 2024
0d11022
Chore/update ubuntu version (#85)
Tyler-Lentz Jan 18, 2024
a5ba8e9
Chore/update ubuntu version (#86)
Tyler-Lentz Jan 18, 2024
55d2830
Chore/update ubuntu version (#87)
Tyler-Lentz Jan 18, 2024
30202ff
Chore/update ubuntu version (#88)
Tyler-Lentz Jan 18, 2024
97e8514
Chore/update ubuntu version (#89)
Tyler-Lentz Jan 18, 2024
c121c7e
update Dockerfile to install pyenv and use it to build libtorch
atar13 Jan 21, 2024
34220d6
GCS Networking & General OBC Infrastructure (#55)
Tyler-Lentz Jan 22, 2024
498cb4b
reintroduce git submodule clone script
Tyler-Lentz Jan 22, 2024
b8789eb
actions: run docker action on project release
Samir-Rashid Jan 22, 2024
507097b
fix docker github action
Tyler-Lentz Jan 22, 2024
d5c48f8
fix filter frfr this time (#93)
Tyler-Lentz Jan 22, 2024
4f158af
Chore/dockerfile filter (#94)
Tyler-Lentz Jan 22, 2024
a90a08a
Hide ghcr auth instructions (#95)
Samir-Rashid Jan 24, 2024
440fead
added gnuplot to Docker for matplotplus (#97)
atar13 Jan 28, 2024
2417042
QT_QPA_PLATFORM env var for headless mode
atar13 Jan 31, 2024
9ba2e79
docker comments are sus
atar13 Jan 31, 2024
9e12d78
GCS Server: Mission Input (#96)
Tyler-Lentz Feb 5, 2024
dcf444b
cache apt-update instructions in Dockerfile (#109)
atar13 Feb 14, 2024
dff8c3e
add magick++ dependency
atar13 Feb 14, 2024
fd9c6cc
Mavlink Client (#107)
Tyler-Lentz Feb 16, 2024
781b538
cv pipeline integration test
atar13 Jan 5, 2024
d17807e
Add matching constructor code
AchuthKrishna Jan 21, 2024
8f2326b
Add match() implementation
AchuthKrishna Jan 21, 2024
b943852
Parameterize model path
AchuthKrishna Jan 21, 2024
a9ee234
Add changes to get compilation
AchuthKrishna Feb 1, 2024
6cf5fb9
Add fixes to Input
AchuthKrishna Feb 3, 2024
783cb83
Small fix to index
AchuthKrishna Feb 3, 2024
635564b
Fix NaN Error
AchuthKrishna Feb 9, 2024
43e63be
Add comments explaining from_blob
AchuthKrishna Feb 10, 2024
8c8b573
Refactor referenceImages
AchuthKrishna Feb 10, 2024
ce59aad
Clean Comments
AchuthKrishna Feb 10, 2024
6c83eab
missed this during rebase
atar13 Feb 17, 2024
4304cb0
adding cmake deps to get things to compile
atar13 Feb 17, 2024
3f6b44d
update pipeline and matching for protobuf datatypes
atar13 Feb 17, 2024
ed8a44f
Address PR Comments
AchuthKrishna Feb 21, 2024
68939df
Revert error handling, do linting
AchuthKrishna Feb 21, 2024
96f5ec0
Merge pull request #106 from tritonuas/feat/cv-orchestrator-matching
AchuthKrishna Feb 21, 2024
bde6948
gitkeeped models and images folders
atar13 Feb 25, 2024
dc86445
ignore correct images path
atar13 Feb 25, 2024
844746b
make targets to pull model files from google drive
atar13 Feb 26, 2024
690f1f6
split up localization implementations
atar13 Feb 28, 2024
c434527
initial localization unit tests
atar13 Feb 28, 2024
0d479ae
finished integrating segmentation
shijiew555 Mar 1, 2024
8a4bebe
Merge feat/cv-orchestrator into cv-segmentation-integration. Add mode…
shijiew555 Mar 1, 2024
14a8e3d
Merge remote-tracking branch 'origin/feat/cv-orchestrator' into cv-se…
shijiew555 Mar 1, 2024
80a3bff
complete integration test cv_segmentation.cpp
shijiew555 Mar 2, 2024
74b2c9f
fix lint
shijiew555 Mar 3, 2024
a2c143b
fix torchscript error
shijiew555 Mar 3, 2024
d80d340
Merge pull request #123 from tritonuas/cv-segmentation-integration
shijiew555 Mar 4, 2024
e3e663a
Merge remote-tracking branch 'origin/main' into feat/cv-orchestrator
atar13 Mar 29, 2024
0415e87
add imagemagick to cv_pipeline target
atar13 Mar 31, 2024
07304fc
move cv_pipeline to use BottleDropIndex
atar13 Mar 31, 2024
57c47fd
all targets compile
atar13 Apr 1, 2024
f7f8b55
move to use log statements
atar13 Apr 1, 2024
9031648
links to model/image drive files
atar13 Apr 1, 2024
b24ddcf
Merge remote-tracking branch 'origin/main' into feat/cv-orchestrator
atar13 Apr 1, 2024
c2c2a26
forgot )
atar13 Apr 1, 2024
48b7f41
satisfy cpplint gods
atar13 Apr 1, 2024
ab5be02
temporarily removing localization test assert 😳
atar13 Apr 1, 2024
0a6ca2a
fix model downloading make targets
atar13 Apr 2, 2024
e124a4c
automate pulling matching test images
atar13 Apr 2, 2024
7bb880e
remove extra comment block
atar13 Apr 2, 2024
b2ba112
satisfy cpplint gods again
atar13 Apr 2, 2024
5a8ee3e
comments about pulling matching/segmentation models
atar13 Apr 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
{
"name": "Existing Dockerfile",
"image": "ghcr.io/tritonuas/obcpp:main",
// "build": {
// "dockerfile": "Dockerfile"
// },

"customizations": {
"vscode": {
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ _deps/
Testing/
imgs/

models/*
!models/.gitkeep

tests/integration/images/*
!tests/integration/images/.gitkeep

.vscode/*
!.vscode/c_cpp_properties.json

Expand Down
64 changes: 63 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ target_add_protobuf(playground)
target_add_loguru(playground)

# load_torchvision_model
add_executable(load_torchvision_model tests/integration/load_torchvision_model.cpp)
add_executable(load_torchvision_model "tests/integration/load_torchvision_model.cpp")
target_add_torch(load_torchvision_model)
target_add_torchvision(load_torchvision_model)

Expand All @@ -136,6 +136,40 @@ target_add_mavsdk(mavlink_client)
target_add_matplot(mavlink_client)
target_add_loguru(mavlink_client)

# cv_pipeline
add_executable(cv_pipeline ${SOURCES} "tests/integration/cv_pipeline.cpp")
target_add_json(cv_pipeline)
target_add_matplot(cv_pipeline)
target_add_opencv(cv_pipeline)
target_add_loguru(cv_pipeline)
target_add_httplib(cv_pipeline)
target_add_protobuf(cv_pipeline)
target_add_torch(cv_pipeline)
target_add_torchvision(cv_pipeline)
target_add_mavsdk(cv_pipeline)
target_add_loguru(cv_pipeline)

# cv_matching
add_executable(cv_matching ${SOURCES} "tests/integration/cv_matching.cpp")
target_add_json(cv_matching)
target_add_matplot(cv_matching)
target_add_opencv(cv_matching)
target_add_torch(cv_matching)
target_add_torchvision(cv_matching)
target_add_loguru(cv_matching)
target_add_httplib(cv_matching)
target_add_mavsdk(cv_matching)

# cv_segmentation
add_executable(cv_segmentation ${SOURCES} "tests/integration/cv_segmentation.cpp")
target_add_json(cv_segmentation)
target_add_matplot(cv_segmentation)
target_add_opencv(cv_segmentation)
target_add_torch(cv_segmentation)
target_add_torchvision(cv_segmentation)
target_add_loguru(cv_segmentation)
target_add_httplib(cv_segmentation)
target_add_mavsdk(cv_segmentation)
# path_plotting
add_executable(path_plotting ${SOURCES} tests/integration/path_plotting.cpp)
target_add_torch(path_plotting)
Expand Down Expand Up @@ -163,6 +197,33 @@ add_subdirectory(tests/unit)
add_subdirectory(${DEPS_DIRECTORY}/google-test)
# =============================

# =============================
# Pull models
add_custom_target(pull_models
DEPENDS pull_saliency pull_matching pull_segmentation
)

# Saliency model
add_custom_target(pull_saliency
COMMAND gdown https://drive.google.com/uc?id=1S1IfXlGs_pCH49DwZmbD-tZA5YH0A1gx -O ${CMAKE_BINARY_DIR}/../models/torchscript_19.pth
)

# Matching model
add_custom_target(pull_matching
COMMAND gdown https://drive.google.com/file/d/1NeFiAfSSLXAZWlehfd0ox7p_jFF4YdrO -O ${CMAKE_BINARY_DIR}/../models/target_siamese_1.pt
)

# Segmentation model
add_custom_target(pull_segmentation
COMMAND gdown https://drive.google.com/file/d/1U2EbfJFzcjVnjTuD6ud-bIf8YOiEassf -O ${CMAKE_BINARY_DIR}/../models/fcn-model_20-epochs_06-01-2023T21-16-02.pth
)
# =============================

# =============================
# Pull testing images
#
# =============================

# =============================
# Linting

Expand All @@ -172,6 +233,7 @@ if(CPPLINT)
# define lint target
add_custom_target(lint
COMMAND cpplint
# Do not require licenses, TODO assignment, Google versions of C++ libs
--filter=-legal,-readability/todo,-build/c++11
--linelength=100
--recursive
Expand Down
51 changes: 36 additions & 15 deletions include/camera/interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,26 @@

#include <string>
#include <vector>
#include <memory>

#include <nlohmann/json.hpp>
#include <opencv2/opencv.hpp>

// class to contain all telemetry that should be tagged with an image.
// In the future this could be in a mavlink file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a mavlink file

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of a mavlink.hpp that would be added by Jasper in his Mavlink Client.

class ImageTelemetry {
public:
ImageTelemetry(double latitude, double longitude, double altitude, double airspeed, double yaw,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use the GPSCoord type. I like how you made a ImageTelemetry type so it is easy to add/remove fields in the future. I think it is more conventional to make this a struct since everything is public. Also this should have a default initializer {} for all the values.

Copy link
Member Author

@atar13 atar13 Jan 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of removing some of the fields in favor of GPSCoord. I have also changed ImageTelemetry to a struct.

What do you mean by default initializer? Is that the same as the constructor implementation in camera/interface.cpp? https://github.com/tritonuas/obcpp/blob/feat/cv-orchestrator/src/camera/interface.cpp#L3-L11

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that will make sure this all gets zero initialized.

double pitch, double roll);
const double latitude;
const double longitude;
const double altitude;
const double airspeed;
const double yaw;
const double pitch;
const double roll;
};

/*
* FYI: this is class that will standardize image data but
* if all of our cameras have a uniform image output type
Expand All @@ -19,14 +35,17 @@
class ImageData {
private:
const std::string NAME;
const std::string PATHS;
const std::string PATH;
const cv::Mat DATA;
const ImageTelemetry TELEMETRY;

public:
ImageData(std::string NAME, std::string PATH, cv::Mat DATA);
std::string getName();
std::string getPath();
cv::Mat getData();
ImageData(std::string NAME, std::string PATH, cv::Mat DATA, ImageTelemetry TELEMETRY);
ImageData(const ImageData&) = default;
std::string getName() const;
std::string getPath() const;
cv::Mat getData() const;
ImageTelemetry getTelemetry() const;
};

// ? possibly convert most common / important json fields to
Expand All @@ -40,7 +59,7 @@ class CameraConfiguration {

void updateConfig(nlohmann::json newSetting);

void updateConfigField(std::string key, T value);
// void updateConfigField(std::string key, T value);

nlohmann::json getConfig();

Expand All @@ -50,8 +69,8 @@ class CameraConfiguration {
class CameraInterface {
private:
CameraConfiguration config;
ImageData recentPicture; // might need to move it to public
bool doneTakingPicture; // overengineering time
std::unique_ptr<ImageData> recentPicture; // might need to move it to public
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well at least it should be fine if it's private ...because the smart pointer is handling all the scoping memory for us.

// overengineering time

🤔 I cannot give useful advice on the design of this interface ...because I have no idea what kinds of functionality we have been using in the past since '87. I do not want to block based on any minor improvements, so as long as you are happy with this we should forge ahead. That being said, it would be good to reping the people in your comment to get a better set of eyes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have removed that public comment. That was made by Boris in the original interface. And so was the over engineering comment. This PR wasn't supposed to drastically change the camera interface but we've already had a design talk with Boris during the meeting on how to simplify the API.

bool doneTakingPicture; // overengineering time
std::string uploadPath;
// Interpreter interp
// TODO: SERVER CONNECTION HERE ?
Expand All @@ -61,19 +80,21 @@ class CameraInterface {
public:
explicit CameraInterface(CameraConfiguration config);

void connect();
virtual ~CameraInterface() = default;

virtual void connect() = 0;

bool verifyConnection();
virtual bool verifyConnection() = 0;

void takePicture();
virtual void takePicture() = 0;

ImageData getLastPicture();
virtual ImageData getLastPicture() = 0;

bool takePictureForSeconds(int sec);
virtual bool takePictureForSeconds(int sec) = 0;

void startTakingPictures(double intervalSec);
virtual void startTakingPictures(double intervalSec) = 0;

bool isDoneTakingPictures();
virtual bool isDoneTakingPictures() = 0;

CameraConfiguration getConfig();

Expand Down
24 changes: 24 additions & 0 deletions include/camera/mock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef INCLUDE_CAMERA_MOCK_HPP_
#define INCLUDE_CAMERA_MOCK_HPP_

#include <memory>

#include "camera/interface.hpp"

class MockCamera : public CameraInterface {
public:
explicit MockCamera(CameraConfiguration config);
~MockCamera() = default;
void connect() override;
bool verifyConnection() override;
void takePicture() override;
ImageData getLastPicture() override;
bool takePictureForSeconds(int sec) override;
void startTakingPictures(double intervalSec) override;
bool isDoneTakingPictures() override;

private:
std::unique_ptr<ImageData> lastPicture;
};

#endif // INCLUDE_CAMERA_MOCK_HPP_
55 changes: 55 additions & 0 deletions include/cv/classification.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef INCLUDE_CV_CLASSIFICATION_HPP_
#define INCLUDE_CV_CLASSIFICATION_HPP_

#include <string>
#include <opencv2/opencv.hpp>

struct ClassificationResults {
// TODO: replace with protobuf structs instead of strings
std::string shape;
std::string shapeColor;
std::string character;
std::string characterColor;
};

// Classification is responsible for predicting characteristics about
// ground comptition targets. These characterisitcs include shape type,
// alphanumeric character type, shape color, and alphanumeric character color.
// Currently, the shape and character classifiers are implemented using a
// Convolutional Neural Network (CNN).
// The color classifier is implented using a K-nearest neigbors model (KNN)
// The implementation of the models themselves can be found here:
// https://github.com/tritonuas/taxonomy-101
// In this class we will take the pretrained models and use them to make
// inferences.
class Classification {
public:
// classify takes a cropped image of the target (saliency output) and
// two binary masks to represent which region of pixels correspond to
// shape and character respectivel (output of segmentation). Using this
// data, the shape type, character type, shape color and character color
// will be predicted.
ClassificationResults classify(cv::Mat croppedImage, cv::Mat shapeMask, cv::Mat characterMask);

private:
// classifyShape takes a cropped image of the target (output of saliency)
// and a binary mask (output of segmentation). The binary mask should
// represent which region of pixels correspond to the shape region of
// the target.
std::string classifyShape(cv::Mat croppedImage, cv::Mat shapeMask);

// classifyShape takes a cropped image of the target (output of saliency)
// and a binary mask (output of segmentation). The binary mask should
// represent which region of pixels correspond to the character region of
// the target.
std::string classifyCharacter(cv::Mat croppedImage, cv::Mat characterMask);

// classify the primary color of a region described by a binary mask.
// This can be used for finding both shape and character color since
// we will use the same algorithm to detect the primary color in
// whatever region the mask describes. All that changes is the mask
// that's passed in.
std::string classifyColor(cv::Mat croppedImage, cv::Mat mask);
};

#endif // INCLUDE_CV_CLASSIFICATION_HPP_
86 changes: 86 additions & 0 deletions include/cv/localization.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#ifndef INCLUDE_CV_LOCALIZATION_HPP_
#define INCLUDE_CV_LOCALIZATION_HPP_

#include "cv/utilities.hpp"

#include "camera/interface.hpp"
#include "utilities/datatypes.hpp"

// TODO: these should be constants in the config file
// (or maybe queried by camera)
#define PIXEL_SIZE_MM 0.0024
#define FOCAL_LENGTH_MM 50
#define IMG_WIDTH_PX 5472
#define IMG_HEIGHT_PX 3648

// Localization is responsible for calculating the real world latitude/longitude
// of competition targets.
// See our Python implementation here: https://github.com/tritonuas/localization
class Localization {
public:
// localize is responsible for transforming the position of a target
// within a full resolution image (image coordinates) to it's position
// in the real world (latitude/longitude coords). We are given the
// pixel coordinates of the target from saliency and the GPS position of
// the plane at the time of image capture.
//
// TODO: also need to pass in camera/lens information such as sensor width,
// focal length, and image width/height
virtual GPSCoord localize(const ImageTelemetry& telemetry, const Bbox& targetBbox) = 0;

protected:
struct CameraIntrinsics {
double pixelSize; //mm
double focalLength; //mm
double resolutionX; //Pixels
double resolutionY; //Pixels
};

CameraIntrinsics camera{
.pixelSize = PIXEL_SIZE_MM,
.focalLength = FOCAL_LENGTH_MM,
.resolutionX = IMG_WIDTH_PX,
.resolutionY = IMG_HEIGHT_PX,
};
};

// Localization by converting via ECEF coordinates (Earth Centered, Earth Fixed)
class ECEFLocalization : Localization {
public:
GPSCoord localize(const ImageTelemetry& telemetry, const Bbox& targetBbox) override;
private:
// ECEF - Earth Centered, Earth Fixed coordinate system. 0,0,0 is the center of the Earth.
struct ECEFCoordinates {
double x; //Meters in the plane of the equator in the direction of the prime meridian
double y; //Meters in the plane of the equator in the direction of 90 degrees East
double z; //Meters in the direction of the North pole
};

// ENU - East, North, Up coordinate system. Used to show an offset from a certain location on the Earth.
struct ENUCoordinates {
double e; //Meters East from reference location
double n; //Meters North from reference location
double u; //Meters Up from reference location
};


struct CameraVector {
double roll; //Radians
double pitch; //Radians
double heading; //Radians
};

ECEFCoordinates GPStoECEF(GPSCoord gps);
ECEFCoordinates ENUtoECEF(ENUCoordinates offset, GPSCoord originGPS);
GPSCoord ECEFtoGPS(ECEFCoordinates ecef);
CameraVector PixelsToAngle(CameraIntrinsics camera, CameraVector state, double targetX, double targetY);
ENUCoordinates AngleToENU(CameraVector target, GPSCoord aircraft, double terrainHeight);
};

// Localization using GSD (ground sample distance) ratio
class GSDLocalization : Localization {
public:
GPSCoord localize(const ImageTelemetry& telemetry, const Bbox& targetBbox) override;
};

#endif // INCLUDE_CV_LOCALIZATION_HPP_
Loading
Loading