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

[wpical] Add JSON Combiner #7640

Merged
merged 14 commits into from
Jan 10, 2025
270 changes: 178 additions & 92 deletions wpical/src/main/native/cpp/WPIcal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@

#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <numbers>
#include <string>
#include <vector>

#include <GLFW/glfw3.h>
#include <fmt/format.h>
#include <imgui.h>
#include <portable-file-dialogs.h>
#include <tagpose.h>
Expand Down Expand Up @@ -58,6 +60,81 @@ void drawCheck() {
ImGui::NewLine();
}

void openFileButton(const char* text, std::string& selected_file,
const std::string& file_type,
const std::string& file_extensions) {
if (ImGui::Button(text)) {
auto selector = std::make_unique<pfd::open_file>(
"Select File", "", std::vector<std::string>{file_type, file_extensions},
pfd::opt::none);

if (selector) {
ElliotScher marked this conversation as resolved.
Show resolved Hide resolved
auto selectedFiles = selector->result();
if (!selectedFiles.empty()) {
selected_file = selectedFiles[0];
}
selector.reset();
}
}
}

void openFilesButton(const char* text, std::vector<std::string>& selected_files,
const std::string& file_type,
const std::string& file_extensions) {
if (ImGui::Button(text)) {
auto selector = std::make_unique<pfd::open_file>(
"Select File", "", std::vector<std::string>{file_type, file_extensions},
pfd::opt::multiselect);

if (selector) {
auto selectedFiles = selector->result();
if (!selectedFiles.empty()) {
selected_files = selectedFiles;
}
selector.reset();
}
}
}

void openDirectoryButton(const char* text, std::string& selected_directory) {
if (ImGui::Button(text)) {
auto selector =
std::make_unique<pfd::select_folder>("Select Directory", "");
if (selector) {
auto selectedFiles = selector->result();
if (!selectedFiles.empty()) {
selected_directory = selectedFiles;
}
selector.reset();
}
}
}

std::string getFileName(std::string path) {
size_t lastSlash = path.find_last_of("/\\");
size_t lastDot = path.find_last_of(".");
return path.substr(lastSlash + 1, lastDot - lastSlash - 1);
}

static bool EmitEntryTarget(int tag_id, std::string& file) {
if (!file.empty()) {
auto text = fmt::format("{}: {}", tag_id, file);
ImGui::TextUnformatted(text.c_str());
} else {
ImGui::Text("Tag ID %i: <none (DROP HERE)>", tag_id);
}
bool rv = false;
if (ImGui::BeginDragDropTarget()) {
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload("FieldCalibration")) {
file = *(std::string*)payload->Data;
rv = true;
}
ImGui::EndDragDropTarget();
}
return rv;
}

static void DisplayGui() {
ImGui::GetStyle().WindowRounding = 0;

Expand All @@ -81,20 +158,14 @@ static void DisplayGui() {
}
ImGui::EndMenuBar();

static std::unique_ptr<pfd::open_file> camera_intrinsics_selector;
static std::string selected_camera_intrinsics;

static std::unique_ptr<pfd::open_file> field_map_selector;
static std::string selected_field_map;

static std::unique_ptr<pfd::select_folder>
field_calibration_directory_selector;
static std::string selected_field_calibration_directory;

static std::unique_ptr<pfd::select_folder> download_directory_selector;
static std::string selected_download_directory;

static std::string calibration_json_path;
static std::vector<std::string> selected_field_calibrations;
static std::map<int, std::string> combiner_map;
static int current_combiner_tag_id = 0;

cameracalibration::CameraModel cameraModel = {
.intrinsic_matrix = Eigen::Matrix<double, 3, 3>::Identity(),
Expand All @@ -118,13 +189,11 @@ static void DisplayGui() {

static Fieldmap currentCalibrationMap;
static Fieldmap currentReferenceMap;
static Fieldmap currentCombinerMap;

// camera matrix selector button
if (ImGui::Button("Upload Camera Intrinsics")) {
camera_intrinsics_selector = std::make_unique<pfd::open_file>(
"Select Camera Intrinsics JSON", "",
std::vector<std::string>{"JSON", "*.json"}, pfd::opt::none);
}
openFileButton("Select Camera Intrinsics JSON", selected_camera_intrinsics,
"JSON Files", "*.json");

ImGui::SameLine();
ImGui::Text("Or");
Expand All @@ -136,50 +205,21 @@ static void DisplayGui() {
ImGui::OpenPopup("Camera Calibration");
}

if (camera_intrinsics_selector) {
auto selectedFiles = camera_intrinsics_selector->result();
if (!selectedFiles.empty()) {
selected_camera_intrinsics = selectedFiles[0];
}
camera_intrinsics_selector.reset();
}

if (!selected_camera_intrinsics.empty()) {
drawCheck();
}

// field json selector button
if (ImGui::Button("Select Field Map JSON")) {
field_map_selector = std::make_unique<pfd::open_file>(
"Select Json File", "",
std::vector<std::string>{"JSON Files", "*.json"}, pfd::opt::none);
}

if (field_map_selector) {
auto selectedFiles = field_map_selector->result();
if (!selectedFiles.empty()) {
selected_field_map = selectedFiles[0];
}
field_map_selector.reset();
}
openFileButton("Select Field Map JSON", selected_field_map, "JSON Files",
"*.json");

if (!selected_field_map.empty()) {
drawCheck();
}

// field calibration directory selector button
if (ImGui::Button("Select Field Calibration Folder")) {
field_calibration_directory_selector = std::make_unique<pfd::select_folder>(
"Select Field Calibration Folder", "");
}

if (field_calibration_directory_selector) {
auto selectedFiles = field_calibration_directory_selector->result();
if (!selectedFiles.empty()) {
selected_field_calibration_directory = selectedFiles;
}
field_calibration_directory_selector.reset();
}
openDirectoryButton("Select Field Calibration Directory",
selected_field_calibration_directory);

if (!selected_field_calibration_directory.empty()) {
drawCheck();
Expand All @@ -193,7 +233,7 @@ static void DisplayGui() {
if (ImGui::Button("Calibrate!!!")) {
if (!selected_field_calibration_directory.empty() &&
!selected_camera_intrinsics.empty() && !selected_field_map.empty()) {
download_directory_selector =
auto download_directory_selector =
ElliotScher marked this conversation as resolved.
Show resolved Hide resolved
std::make_unique<pfd::select_folder>("Select Download Folder", "");
if (download_directory_selector) {
auto selectedFiles = download_directory_selector->result();
Expand Down Expand Up @@ -231,6 +271,10 @@ static void DisplayGui() {
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("Visualize Calibration");
}
if (ImGui::Button("Combine Calibrations")) {
ImGui::SetNextWindowSize(ImVec2(600, 400), ImGuiCond_Always);
ImGui::OpenPopup("Combine Calibrations");
}
if (selected_field_calibration_directory.empty() ||
selected_camera_intrinsics.empty() || selected_field_map.empty()) {
ImGui::TextWrapped(
Expand Down Expand Up @@ -320,21 +364,9 @@ static void DisplayGui() {
}

if (mrcal) {
if (ImGui::Button("Select Camera Calibration Video")) {
camera_intrinsics_selector = std::make_unique<pfd::open_file>(
"Select Camera Calibration Video", "",
std::vector<std::string>{"Video Files",
"*.mp4 *.mov *.m4v *.mkv *.avi"},
pfd::opt::none);
}

if (camera_intrinsics_selector) {
auto selectedFiles = camera_intrinsics_selector->result();
if (!selectedFiles.empty()) {
selected_camera_intrinsics = selectedFiles[0];
}
camera_intrinsics_selector.reset();
}
openFileButton("Select Camera Calibration Video",
selected_camera_intrinsics, "Video Files",
"*.mp4 *.mov *.m4v *.mkv *.avi");

ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
ImGui::InputDouble("Square Width (in)", &squareWidth);
Expand Down Expand Up @@ -379,21 +411,9 @@ static void DisplayGui() {
}
}
} else {
if (ImGui::Button("Select Camera Calibration Video")) {
camera_intrinsics_selector = std::make_unique<pfd::open_file>(
"Select Camera Calibration Video", "",
std::vector<std::string>{"Video Files",
"*.mp4 *.mov *.m4v *.mkv *.avi"},
pfd::opt::none);
}

if (camera_intrinsics_selector) {
auto selectedFiles = camera_intrinsics_selector->result();
if (!selectedFiles.empty()) {
selected_camera_intrinsics = selectedFiles[0];
}
camera_intrinsics_selector.reset();
}
openFileButton("Select Camera Calibration Video",
selected_camera_intrinsics, "Video Files",
"*.mp4 *.mov *.m4v *.mkv *.avi");

ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
ImGui::InputDouble("Square Width (in)", &squareWidth);
Expand Down Expand Up @@ -446,26 +466,16 @@ static void DisplayGui() {
// visualize calibration popup
if (ImGui::BeginPopupModal("Visualize Calibration", NULL,
ImGuiWindowFlags_AlwaysAutoResize)) {
if (ImGui::Button("Load Calibrated Field")) {
calibration_json_path =
std::make_unique<pfd::open_file>(
"Select Json File", "",
std::vector<std::string>{"JSON Files", "*.json"}, pfd::opt::none)
->result()[0];
}
openFileButton("Select Calibration JSON", calibration_json_path, "JSON",
"*.json");

if (!calibration_json_path.empty()) {
ImGui::SameLine();
drawCheck();
}

if (ImGui::Button("Load Reference Field")) {
selected_field_map =
std::make_unique<pfd::open_file>(
"Select Json File", "",
std::vector<std::string>{"JSON Files", "*.json"}, pfd::opt::none)
->result()[0];
}
openFileButton("Select Ideal Field Map", selected_field_map, "JSON",
"*.json");

if (!selected_field_map.empty()) {
ImGui::SameLine();
Expand Down Expand Up @@ -537,6 +547,82 @@ static void DisplayGui() {
ImGui::EndPopup();
}

if (ImGui::BeginPopupModal("Combine Calibrations", NULL,
ImGuiWindowFlags_AlwaysAutoResize)) {
openFileButton("Select Ideal Map", selected_field_map, "JSON", "*.json");
if (!selected_field_map.empty()) {
drawCheck();
std::ifstream json(selected_field_map);
currentReferenceMap = Fieldmap(wpi::json::parse(json));
currentCombinerMap = currentReferenceMap;
}
openFilesButton("Select Field Calibrations", selected_field_calibrations,
"JSON", "*.json");

if (!selected_field_map.empty() && !selected_field_calibrations.empty()) {
for (std::string& file : selected_field_calibrations) {
ImGui::Selectable(getFileName(file).c_str(), false,
ImGuiSelectableFlags_DontClosePopups);
if (ImGui::BeginDragDropSource()) {
ImGui::SetDragDropPayload("FieldCalibration", &file, sizeof(file));
ImGui::TextUnformatted(file.c_str());
ImGui::EndDragDropSource();
}
}

for (auto& [key, val] : combiner_map) {
EmitEntryTarget(key, val);
}

ImGui::InputInt("Tag ID", &current_combiner_tag_id);
ImGui::SameLine();
if (ImGui::Button("Add", ImVec2(0, 0)) &&
currentCombinerMap.hasTag(current_combiner_tag_id)) {
combiner_map.emplace(current_combiner_tag_id, "");
}
ImGui::SameLine();
if (ImGui::Button("Remove", ImVec2(0, 0))) {
combiner_map.erase(current_combiner_tag_id);
}
}
ImGui::Separator();
if (ImGui::Button("Close", ImVec2(0, 0))) {
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Download", ImVec2(0, 0))) {
for (auto& [key, val] : combiner_map) {
std::ifstream json(val);
Fieldmap map(wpi::json::parse(json));
currentCombinerMap.replaceTag(key, map.getTag(key));
}

if (!selected_download_directory.empty()) {
std::ofstream out(selected_download_directory + "/combination.json");
out << currentCombinerMap.toJson().dump(4);
out.close();
} else {
auto download_directory_selector =
std::make_unique<pfd::select_folder>("Select Download Folder", "");
ElliotScher marked this conversation as resolved.
Show resolved Hide resolved
if (download_directory_selector) {
auto selectedFiles = download_directory_selector->result();
if (!selectedFiles.empty()) {
selected_download_directory = selectedFiles;
}
download_directory_selector.reset();
}
std::ofstream json(selected_download_directory + "/combination.json");
json << currentCombinerMap.toJson().dump(4);
json.close();

std::ofstream fmap(selected_download_directory + "/combination.fmap");
fmap << fmap::convertfmap(currentCombinerMap.toJson()).dump(4);
fmap.close();
}
}
ImGui::EndPopup();
}

ImGui::End();
}

Expand Down
Loading
Loading