diff --git a/.gitignore b/.gitignore index e145363..a290142 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,4 @@ healthchecksdb */Dependencies/* Client/models prefs.ini +log.txt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a62f447 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Client/Vendor/spdlog"] + path = Client/Vendor/spdlog + url = https://github.com/gabime/spdlog diff --git a/Client/Client.vcxproj b/Client/Client.vcxproj index c665081..015b925 100644 --- a/Client/Client.vcxproj +++ b/Client/Client.vcxproj @@ -72,10 +72,10 @@ - $(Qt_INCLUDEPATH_);$(SolutionDir)Dependencies\libusb\include\libusb-1.0;$(SolutionDir)Dependencies\OpenCV\include\;$(SolutionDir)Dependencies\onnxruntime\include\;$(SolutionDir)AITracker\src\;$(ProjectDir)Include;$(QTDIR)\include;$(QTDIR)\include\QtUiTools;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtQuick;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtQml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;$(Platform)\$(Configuration)\uic;$(Platform)\$(Configuration)\moc;.\;%(AdditionalIncludeDirectories) + $(Qt_INCLUDEPATH_);$(SolutionDir)Dependencies\libusb\include\libusb-1.0;$(SolutionDir)Dependencies\OpenCV\include\;$(ProjectDir)\Vendor\spdlog\include\;$(SolutionDir)Dependencies\onnxruntime\include\;$(SolutionDir)AITracker\src\;$(ProjectDir)Include;$(QTDIR)\include;$(QTDIR)\include\QtUiTools;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtQuick;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtQml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;$(Platform)\$(Configuration)\uic;$(Platform)\$(Configuration)\moc;.\;%(AdditionalIncludeDirectories) - $(Qt_LIBPATH_);$(SolutionDir)Dependencies\libusb\MS64\static;$(SolutionDir)Dependencies\OpenCV\lib;$(SolutionDir)Dependencies\onnxruntime\lib\;%(AdditionalLibraryDirectories) + $(Qt_LIBPATH_);$(SolutionDir)Dependencies\libusb\MS64\static;$(SolutionDir)Dependencies\OpenCV\lib;$(SolutionDir)Dependencies\spdlog\lib\;$(SolutionDir)Dependencies\onnxruntime\lib\;%(AdditionalLibraryDirectories) $(Qt_LIBS_);opencv_world430.lib;onnxruntime.lib;Ws2_32.lib;libusb-1.0.lib;legacy_stdio_definitions.lib;%(AdditionalDependencies) true true @@ -105,7 +105,7 @@ $(Qt_LIBS_);opencv_world430d.lib;onnxruntime.lib;Ws2_32.lib;legacy_stdio_definitions.lib;libusb-1.0.lib;%(AdditionalDependencies) - $(Qt_INCLUDEPATH_);$(SolutionDir)Dependencies\libusb\include\libusb-1.0;$(SolutionDir)Dependencies\OpenCV\include\;$(SolutionDir)Dependencies\onnxruntime\include\;$(SolutionDir)PS3Driver\include\;$(SolutionDir)AITracker\src\;$(ProjectDir)Include;$(QTDIR)\include;$(QTDIR)\include\QtUiTools;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtQuick;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtQml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;$(Platform)\$(Configuration)\uic;$(Platform)\$(Configuration)\moc;.\;%(AdditionalIncludeDirectories) + $(Qt_INCLUDEPATH_);$(SolutionDir)Dependencies\libusb\include\libusb-1.0;$(SolutionDir)Dependencies\OpenCV\include\;$(SolutionDir)Dependencies\onnxruntime\include\;$(ProjectDir)Vendor\spdlog\include\;$(SolutionDir)PS3Driver\include\;$(SolutionDir)AITracker\src\;$(ProjectDir)Include;$(QTDIR)\include;$(QTDIR)\include\QtUiTools;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtQuick;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtQml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;$(Platform)\$(Configuration)\uic;$(Platform)\$(Configuration)\moc;.\;%(AdditionalIncludeDirectories) true diff --git a/Client/Vendor/spdlog b/Client/Vendor/spdlog new file mode 160000 index 0000000..9cd25dd --- /dev/null +++ b/Client/Vendor/spdlog @@ -0,0 +1 @@ +Subproject commit 9cd25dd21664be8752c3c96df2d58c0544d28c29 diff --git a/Client/src/Main.cpp b/Client/src/Main.cpp index 7d4bb49..f6fe835 100644 --- a/Client/src/Main.cpp +++ b/Client/src/Main.cpp @@ -10,6 +10,8 @@ #include #include "tracker/TrackerFactory.h" +#include "spdlog/spdlog.h" +#include "spdlog/sinks/basic_file_sink.h" int main(int argc, char *argv[]) @@ -23,15 +25,36 @@ int main(int argc, char *argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif + + + std::shared_ptr logger; + try + { + logger = spdlog::basic_logger_mt("aitrack", "log.txt", true); + logger->flush_on(spdlog::level::info); + } + catch (const spdlog::spdlog_ex& ex) + { + std::cout << "Log init failed: " << ex.what() << std::endl; + } + + + logger->info(" ---------- AITRACK LOG ----------"); + + QApplication app(argc, argv); WindowMain w; w.show(); + auto conf_mgr = std::make_unique("./prefs.ini"); + logger->info("Created/Found prefs.ini"); + auto t_factory = std::make_unique("./models/"); Presenter p((IView&)w, std::move(t_factory), std::move(conf_mgr)); + logger->info("App initialized"); return app.exec(); } diff --git a/Client/src/camera/CameraFactory.cpp b/Client/src/camera/CameraFactory.cpp index 4ca6412..442c461 100644 --- a/Client/src/camera/CameraFactory.cpp +++ b/Client/src/camera/CameraFactory.cpp @@ -55,7 +55,8 @@ std::vector> CameraFactory::getCameras(CameraSettings& s { try { - std::shared_ptr c = std::make_shared(640, 480, 30, i); + std::shared_ptr c = std::make_shared(settings.width, settings.height, settings.fps, i); + c->set_settings(settings); // Brightness / Exposure cams.push_back(std::move(c)); std::cout << "Found ID: " << i << std::endl; } diff --git a/Client/src/camera/CameraSettings.cpp b/Client/src/camera/CameraSettings.cpp index afa15d9..ea9bfde 100644 --- a/Client/src/camera/CameraSettings.cpp +++ b/Client/src/camera/CameraSettings.cpp @@ -16,7 +16,7 @@ CameraSettings::CameraSettings(CameraSettings& settings) gain = settings.gain; fps = settings.fps; width = settings.width; - height = settings.width; + height = settings.height; } CameraSettings::~CameraSettings() diff --git a/Client/src/camera/OCVCamera.cpp b/Client/src/camera/OCVCamera.cpp index ad22f6e..45f0986 100644 --- a/Client/src/camera/OCVCamera.cpp +++ b/Client/src/camera/OCVCamera.cpp @@ -17,7 +17,21 @@ OCVCamera::OCVCamera(int width, int height, int fps, int index) : } is_valid = true; - w_scale = (float)width/(float)cam_native_width; + + if (width < 0 || height < 0) + { + this->width = cam_native_width; + this->height = cam_native_height; + } + + if (fps < 0) + this->fps = cam_native_fps; + + + cap.set(cv::CAP_PROP_FRAME_WIDTH, this->width); + cap.set(cv::CAP_PROP_FRAME_HEIGHT, this->height); + cap.set(cv::CAP_PROP_FPS, this->fps); + exposure, gain = -1; } @@ -39,7 +53,9 @@ bool OCVCamera::is_camera_available() if (frame.empty()) return false; - cam_native_width = cap.get(cv::CAP_PROP_FRAME_WIDTH); + cam_native_width = (int)cap.get(cv::CAP_PROP_FRAME_WIDTH); + cam_native_height = (int)cap.get(cv::CAP_PROP_FRAME_HEIGHT); + cam_native_fps = (int)cap.get(cv::CAP_PROP_FPS); cap.release(); } return available; @@ -63,9 +79,6 @@ void OCVCamera::get_frame(uint8_t* buffer) { cv::Mat frame; cap.read(frame); - //Scale maintaining aspect ratio. If distorted, the model will get confused. - //TODO: Maybe cropping (width,height) section from the center is better. - cv::resize(frame, frame, size, w_scale, w_scale); cv::flip(frame, frame, 1); for (int i = 0; i < frame.cols * frame.rows * 3; i++) buffer[i] = frame.data[i]; @@ -74,16 +87,15 @@ void OCVCamera::get_frame(uint8_t* buffer) void OCVCamera::set_settings(CameraSettings& settings) { - this->width = settings.width; - this->fps = settings.fps; - this->height = settings.height; - w_scale = (float)width / (float)cam_native_width; - - // Opencv needs [0,1] ranges - exposure = settings.exposure < 0 ? -1.0F : (float)settings.exposure/255; - gain = settings.gain < 0 ? -1.0F : (float)settings.gain / 64; - cap.set(cv::CAP_PROP_EXPOSURE, exposure); - cap.set(cv::CAP_PROP_GAIN, gain); + this->width = settings.width > 0 ? settings.width : this->cam_native_width; + this->height = settings.height > 0 ? settings.height : this->cam_native_height; + this->fps = settings.fps > 0 ? settings.fps : this->cam_native_fps; + + // Disabled for the moment because of the different ranges in generic cameras. + //exposure = settings.exposure < 0 ? -1.0F : (float)settings.exposure/255; + //gain = settings.gain < 0 ? -1.0F : (float)settings.gain / 64; + //cap.set(cv::CAP_PROP_EXPOSURE, exposure); + //cap.set(cv::CAP_PROP_GAIN, gain); } CameraSettings OCVCamera::get_settings() diff --git a/Client/src/camera/OCVCamera.h b/Client/src/camera/OCVCamera.h index 2d51b2f..2d1e0bd 100644 --- a/Client/src/camera/OCVCamera.h +++ b/Client/src/camera/OCVCamera.h @@ -9,7 +9,7 @@ class OCVCamera : public Camera cv::Size size; float w_scale; float exposure, gain; - int cam_native_width; + int cam_native_height, cam_native_width, cam_native_fps; int cam_index; int CV_BACKEND; diff --git a/Client/src/model/Config.cpp b/Client/src/model/Config.cpp index a9b1cd3..628e13b 100644 --- a/Client/src/model/Config.cpp +++ b/Client/src/model/Config.cpp @@ -16,9 +16,9 @@ ConfigData ConfigData::getGenericConfig() conf.selected_model = 0; conf.selected_camera = 0; conf.num_cameras_detected = 0; - conf.video_width = 640; - conf.video_height = 480; - conf.video_fps = 30; + conf.video_width = -1; + conf.video_height = -1; + conf.video_fps = -1; conf.use_landmark_stab = true; conf.x, conf.y, conf.z, conf.pitch, conf.yaw, conf.roll = 0; conf.cam_exposure = -1; diff --git a/Client/src/presenter/presenter.cpp b/Client/src/presenter/presenter.cpp index 950307a..6322191 100644 --- a/Client/src/presenter/presenter.cpp +++ b/Client/src/presenter/presenter.cpp @@ -9,6 +9,9 @@ Presenter::Presenter(IView& view, std::unique_ptr&& t_factory, std::unique_ptr&& conf_mgr) { + + logger = spdlog::get("aitrack"); + this->tracker_factory = std::move(t_factory); this->conf_mgr = std::move(conf_mgr); state = this->conf_mgr->getConfig(); @@ -21,18 +24,18 @@ Presenter::Presenter(IView& view, std::unique_ptr&& t_factory, s // Init available model names to show in the GUI this->tracker_factory->get_model_names(state.model_names); - // Setup a filter to stabilize the recognized facial landmarks if needed. - update_stabilizer(state); - CameraFactory camfactory; CameraSettings camera_settings = build_camera_params(); + logger->info("Searching for cameras..."); all_cameras = camfactory.getCameras(camera_settings); + logger->info("Number of recognized cameras: {}", all_cameras.size()); if (all_cameras.size() == 0) { std::cout << "[ERROR] NO CAMERAS AVAILABLE" << std::endl; this->view->set_enabled(false); this->view->show_message("No cameras detected. Plug one and restart the program.", MSG_SEVERITY::CRITICAL); + logger->info("No cameras were detected"); } else { @@ -47,6 +50,12 @@ Presenter::Presenter(IView& view, std::unique_ptr&& t_factory, s // Build tracker init_tracker(state.selected_model); + // Setup a filter to stabilize the recognized facial landmarks if needed. + update_stabilizer(state); + + // Sync camera prefs between active camera and state. + update_camera_params(); + } // Check if there was a problem initing tracker @@ -79,6 +88,8 @@ void Presenter::init_sender(std::string &ip, int port) port_dest = 4242; this->udp_sender = std::make_unique(ip_str.data(), port_dest); + + this->logger->info("UDP sender reinitialized. IP: {} PORT: {}", ip_str, port_dest); } void Presenter::init_tracker(int type) @@ -92,6 +103,7 @@ void Presenter::init_tracker(int type) #ifdef _DEBUG std::cout << "Resetting old tracker" << std::endl; #endif + this->logger->info("Rebuilding tracker with new parameters"); this->t.reset(); this->t.release(); this->t = tracker_factory-> @@ -108,12 +120,14 @@ void Presenter::init_tracker(int type) } else { + this->logger->info("Building Tracker with selected camera: {}", state.selected_camera); this->t = tracker_factory->buildTracker(all_cameras[state.selected_camera]->width, all_cameras[state.selected_camera]->height, (float)state.prior_distance, tracker_factory->get_type(type)); } state.selected_model = type; + this->logger->info("Tracker initialized."); } @@ -132,8 +146,9 @@ void Presenter::run_loop() double buffer_data[6]; + this->logger->info("Starting camera {} capture", state.selected_camera); cam->start_camera(); - + this->logger->info("Camera {} started capturing", state.selected_camera); while(run) { @@ -171,6 +186,7 @@ void Presenter::run_loop() } cam->stop_camera(); + this->logger->info("Stop camera {} capture", state.selected_camera); } @@ -197,6 +213,7 @@ void Presenter::update_stabilizer(const ConfigData& data) { this->filter = std::make_unique(66 * 2); } + this->logger->info("Updated stabilizer."); } CameraSettings Presenter::build_camera_params() @@ -212,7 +229,15 @@ CameraSettings Presenter::build_camera_params() void Presenter::update_camera_params() { + this->logger->info("Updating camera parameters..."); all_cameras[state.selected_camera]->set_settings(build_camera_params()); + + // The camera can be using its default resolution so we must sync our state + // to it. If we are using our custom resolution that wont be necessary. + state.video_height = all_cameras[state.selected_camera]->height; + state.video_width = all_cameras[state.selected_camera]->width; + state.video_fps = all_cameras[state.selected_camera]->fps; + this->logger->info("Updated camera parameters. {}x{}@{}", state.video_width, state.video_height, state.video_fps); } @@ -239,6 +264,8 @@ void Presenter::toggle_tracking() void Presenter::save_prefs(const ConfigData& data) { + this->logger->info("Saving prefs"); + // Disable painting parts from the run loop if needed this->paint = data.show_video_feed; state.show_video_feed = data.show_video_feed; @@ -261,6 +288,7 @@ void Presenter::save_prefs(const ConfigData& data) state.video_fps = data.video_fps; state.video_height = data.video_height; state.video_width = data.video_width; + update_camera_params(); @@ -270,6 +298,7 @@ void Presenter::save_prefs(const ConfigData& data) conf_mgr->updateConfig(state); sync_ui_inputs(); + this->logger->info("Prefs saved"); } diff --git a/Client/src/presenter/presenter.h b/Client/src/presenter/presenter.h index 9d22109..7d42fc8 100644 --- a/Client/src/presenter/presenter.h +++ b/Client/src/presenter/presenter.h @@ -12,6 +12,8 @@ #include "../tracker/TrackerFactory.h" #include "../tracker/ITrackerWrapper.h" +#include "spdlog/spdlog.h" +#include "spdlog/sinks/basic_file_sink.h" class Presenter : IPresenter { @@ -20,8 +22,8 @@ class Presenter : IPresenter std::unique_ptr udp_sender; std::unique_ptr tracker_factory; std::unique_ptr t; - //std::unique_ptr camera; std::vector> all_cameras; + std::shared_ptr logger; // Current program's state + config. ConfigData state; diff --git a/Client/src/view/ConfigWindow.ui b/Client/src/view/ConfigWindow.ui index 2a2dcda..224dba0 100644 --- a/Client/src/view/ConfigWindow.ui +++ b/Client/src/view/ConfigWindow.ui @@ -70,13 +70,13 @@ - 640 + -1 3000 - 640 + -1 @@ -97,26 +97,26 @@ - 480 + -1 3000 - 480 + -1 - 15 + -1 120 - 30 + -1 diff --git a/Client/src/view/WindowMain.cpp b/Client/src/view/WindowMain.cpp index aa4d541..8f2378f 100644 --- a/Client/src/view/WindowMain.cpp +++ b/Client/src/view/WindowMain.cpp @@ -45,6 +45,7 @@ void WindowMain::paint_video_frame(cv::Mat& img) if (check_video_preview->isChecked()) tracking_frame->setPixmap( QPixmap::fromImage(QImage(img.data, img.cols, img.rows, img.step, QImage::Format_RGB888)) + .scaled(400,280, Qt::KeepAspectRatio, Qt::FastTransformation) ); } @@ -87,8 +88,6 @@ void WindowMain::set_tracking_mode(bool is_tracking) } - - void WindowMain::update_view_state(ConfigData conf) { set_inputs(conf);