-
Notifications
You must be signed in to change notification settings - Fork 0
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
Changes from 68 commits
f0b29e5
01b63fc
bbb84fe
94070c4
dff1aee
dc4fdd8
952e020
691b8ec
534de34
7bc51f8
8094ac2
f227506
6280e08
a43cb42
a7c98dd
53b0368
e0d4fbd
3320b54
0d11022
a5ba8e9
55d2830
30202ff
97e8514
c121c7e
34220d6
498cb4b
b8789eb
507097b
d5c48f8
4f158af
a90a08a
440fead
2417042
9ba2e79
9e12d78
dcf444b
dff8c3e
fd9c6cc
781b538
d17807e
8f2326b
b943852
a9ee234
6cf5fb9
783cb83
635564b
43e63be
8c8b573
ce59aad
6c83eab
4304cb0
3f6b44d
ed8a44f
68939df
96f5ec0
bde6948
dc86445
844746b
690f1f6
c434527
0d479ae
8a4bebe
14a8e3d
80a3bff
74b2c9f
a2c143b
d80d340
e3e663a
0415e87
07304fc
57c47fd
f7f8b55
9031648
b24ddcf
c2c2a26
48b7f41
ab5be02
0a6ca2a
e124a4c
7bb880e
b2ba112
5a8ee3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
class ImageTelemetry { | ||
public: | ||
ImageTelemetry(double latitude, double longitude, double altitude, double airspeed, double yaw, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could use the There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 What do you mean by default initializer? Is that the same as the constructor implementation in There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
@@ -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 | ||
|
@@ -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(); | ||
|
||
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
🤔 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ? | ||
|
@@ -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(); | ||
|
||
|
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_ |
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_ |
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_ |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.