diff --git a/.gitignore b/.gitignore index b1a9a70..63cf4ce 100644 --- a/.gitignore +++ b/.gitignore @@ -350,7 +350,9 @@ Client/models prefs.ini log.txt + # CMake CMakeCache.txt CMakeFiles/ - +/cmake-build-debug/ +cmake_install.cmake diff --git a/AITracker/AITracker.vcxproj b/AITracker/AITracker.vcxproj index c2efa05..509e3c8 100644 --- a/AITracker/AITracker.vcxproj +++ b/AITracker/AITracker.vcxproj @@ -189,7 +189,7 @@ true $(SolutionDir)Dependencies\OpenCV\include\;$(SolutionDir)Dependencies\onnxruntime\include\;%(AdditionalIncludeDirectories) MultiThreadedDLL - Disabled + MaxSpeed Console diff --git a/AITracker/src/PositionSolver.cpp b/AITracker/src/PositionSolver.cpp index 0b73bb1..e6361ef 100644 --- a/AITracker/src/PositionSolver.cpp +++ b/AITracker/src/PositionSolver.cpp @@ -1,5 +1,6 @@ #include "PositionSolver.h" +#define USE_FOV // Use FOV correction for the camera matrix. PositionSolver::PositionSolver( int width, @@ -20,7 +21,7 @@ PositionSolver::PositionSolver( { this->prior_pitch = -1.57; this->prior_yaw = -1.57; - this->prior_distance = prior_distance * -2.; + this->prior_distance = prior_distance * -2.0; this->rv[0] = this->prior_pitch; this->rv[1] = this->prior_yaw; @@ -28,8 +29,8 @@ PositionSolver::PositionSolver( this->tv[2] = this->prior_distance; head3dScale = (cv::Mat_(3, 3) << - x_scale, 0.0, 0, - 0.0, y_scale, 0, + y_scale, 0.0, 0, // pitch is rv[0], pitch involves y-axis + 0.0, x_scale, 0, // yaw is rv[1], yaw involves x-axis 0.0, 0.0, z_scale ); @@ -63,9 +64,9 @@ PositionSolver::PositionSolver( { contour_indices = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,27,28,29,30,31,32,33,34,35,36,39,42,45 }; - landmark_points_buffer = cv::Mat(contour_indices.size(), 1, CV_32FC2); + landmark_points_buffer = cv::Mat((int)contour_indices.size(), 1, CV_32FC2); - mat3dcontour = (cv::Mat_(contour_indices.size(), 3) << + mat3dcontour = (cv::Mat_((int)contour_indices.size(), 3) << 0.45517698, -0.30089578, 0.76442945, 0.44899884, -0.16699584, 0.76514298, 0.43743154, -0.02265548, 0.73926717, @@ -102,15 +103,44 @@ PositionSolver::PositionSolver( // https://github.com/opentrack/opentrack/blob/3cc3ef246ad71c463c8952bcc96984b25d85b516/tracker-aruco/ftnoir_tracker_aruco.cpp#L193 // Taking into account the camera FOV instead of assuming raw image dims is more clever and // will make the solver more camera-agnostic. - float diag_fov = fov * TO_RAD; + float diag_fov = (float)(fov * TO_RAD); // Get expressed in sensor-size units + #ifdef USE_FOV + // field of view is a rectangular viewport with corners on a circular lens + // the diagonal of the rectangle can be expressed as the angular field of view or pixels + // the width of the rectangle can be expressed as either the field of view width or width in pixels + // the height of the rectangle can be expressed as either the field of view height or height in pixes + double width_squared = (double)width * width; + double height_squared = (double)height * height; + double diagonal_squared = width_squared + height_squared; + double diagonal = sqrt(diagonal_squared); // hypotenuse of triangle + + // set default focalLength for width and heigh if field of view is not set + double focalLength_width = width; + double focalLength_height = height; + if (fov != 0.0) + { + double fov_w = (double)diag_fov * width / diagonal; + double fov_h = (double)diag_fov * height / diagonal; + + focalLength_width = 0.5 * width / tan(0.5 * fov_w); + focalLength_height = 0.5 * height / tan(0.5 * fov_h); + } + + camera_matrix = (cv::Mat_(3, 3) << + focalLength_height, 0, height / 2, + 0, focalLength_width, width / 2, + 0, 0, 1 + ); + + #else double fov_w = 2. * atan(tan(diag_fov / 2.) / sqrt(1. + height / (double)width * height / (double)width)); double fov_h = 2. * atan(tan(diag_fov / 2.) / sqrt(1. + width / (double)height * width / (double)height)); - float i_height = .5 * height / (tan(.5*fov_w)); - float i_width = .5* width / (tan(.5*fov_h)); + float i_height = (float)(0.5f * height / (tan(0.5 * fov_w))); + float i_width = (float)(0.5f * width / (tan(0.5 * fov_h))); /*camera_matrix = (cv::Mat_(3, 3) << height, 0, height / 2, @@ -122,7 +152,10 @@ PositionSolver::PositionSolver( i_width, 0, height / 2, 0, i_height, width / 2, 0, 0, 1 - ); + ); + + + #endif camera_distortion = (cv::Mat_(4, 1) << 0, 0, 0, 0); @@ -131,6 +164,7 @@ PositionSolver::PositionSolver( if(complex) std::cout << "Using complex solver" << std::endl; } + void PositionSolver::solve_rotation(FaceData* face_data) { int contour_idx = 0; @@ -139,8 +173,7 @@ void PositionSolver::solve_rotation(FaceData* face_data) for (int i = 0; i < contour_indices.size(); i++) { contour_idx = contour_indices[i]; - landmark_points_buffer.at(i, j) = (int)face_data->landmark_coords[2 * contour_idx + j]; - + landmark_points_buffer.at(i, j) = (float)(int)face_data->landmark_coords[2 * contour_idx + j]; // fix complation warnings. } } @@ -164,15 +197,18 @@ void PositionSolver::solve_rotation(FaceData* face_data) for (int i = 0; i < 3; i++) { face_data->rotation[i] = rvec.at(i, 0); - face_data->translation[i] = tvec.at(i, 0) * 10; + face_data->translation[i] = tvec.at(i, 0) * 10; // scale solvePnP coordinates to opentrack units in centimeters } - // We dont want the Z axis oversaturated. + // We dont want the Z axis oversaturated since opentrack has +/-600 centimeter range face_data->translation[2] /= 100; - std::cout << face_data->to_string() << std::endl; +#ifdef _DEBUG + std::cout << face_data->to_string() << std::endl; // disable copy constructor and output to std::cout +#endif correct_rotation(*face_data); + clip_rotations(*face_data); } @@ -218,14 +254,38 @@ void PositionSolver::get_euler(cv::Mat& rvec, cv::Mat& tvec) void PositionSolver::correct_rotation(FaceData& face_data) { - float distance = -(face_data.translation[2]); - float lateral_offset = face_data.translation[1]; - float verical_offset = face_data.translation[0]; + float distance = (float) -(face_data.translation[2]); + float lateral_offset = (float)face_data.translation[1]; + float verical_offset = (float)face_data.translation[0]; - float correction_yaw = std::atan(std::tan(lateral_offset / distance)) * TO_DEG; - float correction_pitch = std::atan(std::tan(verical_offset / distance)) * TO_DEG; + float correction_yaw = (float)(std::atan(lateral_offset / distance) * TO_DEG); // (lateral_offset / distance) is already tangent, so only need atan to obtain radians + float correction_pitch = (float)(std::atan(verical_offset / distance) * TO_DEG); // (verical_offset / distance) is already tangent, so only need atan to obtain radians face_data.rotation[1] += correction_yaw; face_data.rotation[0] += correction_pitch; + + // Note: We could saturate pitch here, but its better to let the user do it via Opentrack. + // The coefficient could be problematic for some users. + //face_data.rotation[0] = face_data.rotation[0] * 1.5; +} + + +void PositionSolver::clip_rotations(FaceData& face_data) +{ + // Limit yaw between -90.0 and +90.0 degrees + if (face_data.rotation[1] >= 90.0) + face_data.rotation[1] = 90.0; + else if (face_data.rotation[1] <= -90.0) + face_data.rotation[1] = -90.0; + // Limit pitch between -90.0 and +90.0 + if (face_data.rotation[0] >= 90.0) + face_data.rotation[0] = 90.0; + else if (face_data.rotation[0] <= -90.0) + face_data.rotation[0] = -90.0; + // Limit roll between -90.0 and +90.0 + if (face_data.rotation[2] >= 90.0) + face_data.rotation[2] = 90.0; + else if (face_data.rotation[2] <= -90.0) + face_data.rotation[2] = -90.0; } diff --git a/AITracker/src/PositionSolver.h b/AITracker/src/PositionSolver.h index 1f3bd2b..cd9e78e 100644 --- a/AITracker/src/PositionSolver.h +++ b/AITracker/src/PositionSolver.h @@ -1,7 +1,7 @@ #pragma once #include "opencv2/core/matx.hpp" -#include "opencv.hpp" +#include "opencv2/opencv.hpp" #include "data.h" /** @@ -68,5 +68,12 @@ class PositionSolver * This method corrects them. */ void correct_rotation(FaceData& face_data); + + + /** + * Ensures all rotations are in -90/90 range. + * (No human head can rotate more supposing camera view is frontal). + */ + void clip_rotations(FaceData& face_data); }; diff --git a/AITracker/src/data.cpp b/AITracker/src/data.cpp index b92f58d..95b3c47 100644 --- a/AITracker/src/data.cpp +++ b/AITracker/src/data.cpp @@ -9,7 +9,6 @@ FaceData::FaceData(): face_detected = false; } - std::string FaceData::to_string() { std::string datastring = @@ -21,7 +20,7 @@ std::string FaceData::to_string() std::string(" X: ") + std::to_string(this->translation[0]) + ", Y: " + std::to_string(this->translation[1]) + ", Z: " + - std::to_string(this->translation[2]) ; + std::to_string(this->translation[2]); return datastring; } diff --git a/AITracker/src/filters.cpp b/AITracker/src/filters.cpp index bd6bd5b..33df811 100644 --- a/AITracker/src/filters.cpp +++ b/AITracker/src/filters.cpp @@ -1,37 +1,57 @@ #include "filters.h" - #include +#include + MAFilter::MAFilter(int steps, int array_size) { this->n_steps = steps; this->array_size = array_size; - this->idx = 0; + this->idx = 0; // this->idx < this->n_steps - this->circular_buffer = new float[steps * array_size]; + this->circular_buffer = (float *)new float[steps * array_size]; // float[steps][array_size] + this->sum = (float *)new float[array_size]; // use this array to cache the sum + for (int i = 0; i < array_size; i++) + this->sum[i] = nanf(""); } MAFilter::~MAFilter() { delete[] this->circular_buffer; + delete[] this->sum; } void MAFilter::filter(float* in_array, float* out_array) { int offset = this->idx * this->array_size; + // equivalent to: + // typedef float (*CIRCULAR_BUFFER_IDX)[this->array_size]; + // typedef float (*CIRCULAR_BUFFER)[this->n_steps][this->array_size]; + float *circular_buffer_idx = &this->circular_buffer[offset]; // CIRCULAR_BUFFER_IDX circular_buffer_idx = &((CIRCULAR_BUFFER)this->circular_buffer)[this->idx][0]; + for (int i = 0; i < this->array_size; i++) { - // Insert current position - this->circular_buffer[offset + i] = in_array[i]; - out_array[i] = 0; - - // get mean of all steps for this position - for (int j = 0; j < this->n_steps; j++) + if (isnan(this->sum[i])) { - out_array[i] += this->circular_buffer[j * this->array_size + i]; + // initialize sum + this->sum[i] = in_array[i] * this->n_steps; + // calculate average + out_array[i] = this->sum[i] / this->n_steps; + // initialize empty circular_buffer with new value + for (int j = 0; j < this->n_steps; j++) + { + this->circular_buffer[j * this->array_size + i] = in_array[i]; + } + } + else + { + // Recalculate sum by subtracting old value and adding new value + this->sum[i] = this->sum[i] - circular_buffer_idx[i] + in_array[i]; + // calculate average + out_array[i] = this->sum[i] / this->n_steps; + // Insert current position + circular_buffer_idx[i] = in_array[i]; } - - out_array[i] /= this->n_steps; } this->idx = (this->idx + 1) % this->n_steps; @@ -56,7 +76,7 @@ void EAFilter::filter(float* in_array, float* out_array) { for (int i = 0; i < array_size; i++) { - out_array[i] = 0.6 * in_array[i] + 0.4 * this->last_value[i]; + out_array[i] = (0.6f * in_array[i] + 0.4f * this->last_value[i]); this->last_value[i] = in_array[i]; } diff --git a/AITracker/src/filters.h b/AITracker/src/filters.h index a9745b2..4b23545 100644 --- a/AITracker/src/filters.h +++ b/AITracker/src/filters.h @@ -16,8 +16,7 @@ class MAFilter : public IFilter int n_steps; float *circular_buffer; - - + float *sum; public: MAFilter(int steps, int array_size); @@ -34,8 +33,6 @@ class EAFilter : public IFilter int array_size; float* last_value; - - public: EAFilter(int array_size); ~EAFilter(); diff --git a/AITracker/src/imageprocessor.cpp b/AITracker/src/imageprocessor.cpp index 03b5137..416d857 100644 --- a/AITracker/src/imageprocessor.cpp +++ b/AITracker/src/imageprocessor.cpp @@ -13,27 +13,19 @@ ImageProcessor::ImageProcessor() : void ImageProcessor::normalize(cv::Mat& image) { cv::divide(image, std_scaling, image); - - /*float* ptr = image.ptr(); - for (int channel = 0; channel < 3; channel++){ - for (int i = 0; i < 224 * 224; i++) { - ptr[224*224*channel + i] /= std_scaling[channel]; - } - }*/ - cv::subtract(image, mean_scaling, image); } -/*void ImageProcessor::cvt_format(float* from, float* dest, int dim_x, int dim_y) +void ImageProcessor::cvt_format(float* from, float* dest, int dim_x, int dim_y) { for (int channel = 1; channel < 4; channel++) { - for (int row = 0; row < 224; row++) + for (int row = 0; row < dim_x; row++) { - for (int col = 0; col < 224; col++) + for (int col = 0; col < dim_y; col++) { - dest[((channel - 1) * 224 * 224) + (224 * col + row)] = from[3 * (224 * col + row)]; + dest[((channel - 1) * dim_x * dim_y) + (dim_y * col + row)] = from[3 * (dim_y * col + row)]; } } } @@ -41,43 +33,38 @@ void ImageProcessor::normalize(cv::Mat& image) void ImageProcessor::transpose(float* from, float* dest, int dim_x, int dim_y) { - int stride = 224 * 224; + int stride = dim_x * dim_y; for (int c = 0; c < 3; c++) { - for (int i = 0; i < 224 * 224; i++) - { - dest[i + stride*c] = from[c + i*3]; - } - } -}*/ - - -void ImageProcessor::cvt_format(float* from, float* dest, int dim_x, int dim_y) -{ - for (int channel = 1; channel < 4; channel++) - { - for (int row = 0; row < dim_x; row++) + float * from_by_channel = &from[c]; + float * dest_by_channel = &dest[stride * c]; + for (int i = 0; i < stride; i++) { - for (int col = 0; col < dim_y; col++) - { - dest[((channel - 1) * dim_x * dim_y) + (dim_y * col + row)] = from[3 * (dim_y * col + row)]; - } + dest_by_channel[i] = from_by_channel[i*3]; } } } -void ImageProcessor::transpose(float* from, float* dest, int dim_x, int dim_y) + +void ImageProcessor::normalize_and_transpose(cv::Mat& image, float* dest, int dim_x, int dim_y) { - int stride = dim_x * dim_y; + const int stride = dim_x * dim_y; - for (int c = 0; c < 3; c++) + // combine normalize and transpose methods to reduce for loops + float* from = (float*)image.data; + for (int channel = 0; channel < 3; channel++) { - for (int i = 0; i < dim_x * dim_y; i++) + float std_scaline_for_channel = (float)std_scaling[channel]; + float mean_scaling_for_channel = (float)mean_scaling[channel]; + + for (int i = 0; i < stride; i++) { - dest[i + stride*c] = from[c + i*3]; + float& from_reference = from[channel + i * 3]; // use a reference to reduce indexing + from_reference /= std_scaline_for_channel; /* remove internal for for loop of cv::divide(image, std_scaling, image); */ + from_reference -= mean_scaling_for_channel; /* remove internal for for loop of cv::subtract(image, mean_scaling, image); */ + + dest[stride * channel + i] = from_reference; /* transpose */ } } } - - diff --git a/AITracker/src/imageprocessor.h b/AITracker/src/imageprocessor.h index a4c0c81..65e8ec7 100644 --- a/AITracker/src/imageprocessor.h +++ b/AITracker/src/imageprocessor.h @@ -1,14 +1,20 @@ #pragma once -#include "opencv.hpp" +#include "opencv2/opencv.hpp" class ImageProcessor { public: ImageProcessor(); void normalize(cv::Mat& image); - void cvt_format(float* from, float* dest, int dim_x = 224, int dim_y=224); - void transpose(float* from, float* dest, int dim_x = 224, int dim_y=224); + void cvt_format(float* from, float* dest, int dim_x = 224, int dim_y = 224); + void transpose(float* from, float* dest, int dim_x = 224, int dim_y = 224); + + /* + Alternative implementation of the normalize and transpose functions which executes the same + functionality in a single run. Using this processing time cuts in half. + */ + void normalize_and_transpose(cv::Mat& image, float* dest, int dim_x = 224, int dim_y = 224); private: cv::Scalar mean_scaling, std_scaling; diff --git a/AITracker/src/model.cpp b/AITracker/src/model.cpp index 1371e34..b85f6d1 100644 --- a/AITracker/src/model.cpp +++ b/AITracker/src/model.cpp @@ -7,7 +7,6 @@ #include - Tracker::Tracker(std::unique_ptr&& solver, std::wstring& detection_model_path, std::wstring& landmark_model_path): improc(), memory_info(allocator.GetInfo()), @@ -23,37 +22,45 @@ Tracker::Tracker(std::unique_ptr&& solver, std::wstring& detecti session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); session_options.SetInterOpNumThreads(1); session_options.SetIntraOpNumThreads(1); + session_options.SetExecutionMode(ExecutionMode::ORT_PARALLEL); enviro->DisableTelemetryEvents(); - session = std::make_unique(*enviro, detection_model_path.data(), session_options); + // Landmark detector session_lm = std::make_unique(*enviro, landmark_model_path.data(), session_options); + // Face detector + float score_threshold = .8; + float nms_threshold = .3; + int topK = 50; + face_detector = cv::FaceDetectorYN::create( + std::string(detection_model_path.begin(), detection_model_path.end()), + "", + cv::Size(224, 224), + score_threshold, + nms_threshold, + topK + ); + tensor_input_size = tensor_input_dims[1] * tensor_input_dims[2] * tensor_input_dims[3]; } void Tracker::predict(cv::Mat& image, FaceData& face_data, const std::unique_ptr& filter) { - cv::Mat img_copy = image.clone(); - img_copy.convertTo(img_copy, CV_32F); - cv::cvtColor(img_copy, img_copy, cv::COLOR_BGR2RGB); - - // Normalization complexity is too high (O(mn)), better to normalize scaled images in - // detect_face and detect_landmarks functions. - - detect_face(img_copy, face_data); + detect_face(image, face_data); if (face_data.face_detected) { cv::Point p1(face_data.face_coords[0], face_data.face_coords[1]); cv::Point p2(face_data.face_coords[2], face_data.face_coords[3]); - cv::Mat cropped = img_copy(cv::Rect(p1, p2)); + cv::Mat cropped = image(cv::Rect(p1, p2)); int height = face_data.face_coords[2] - face_data.face_coords[0]; int width = face_data.face_coords[3] - face_data.face_coords[1]; - float scale_x = (float)width / 224; - float scale_y = (float)height / 224; + float scale_x = (float)width / 224.0f; + float scale_y = (float)height / 224.0f; + detect_landmarks(cropped, face_data.face_coords[0], face_data.face_coords[1], scale_x, scale_y, face_data); if (filter != nullptr) @@ -63,82 +70,73 @@ void Tracker::predict(cv::Mat& image, FaceData& face_data, const std::unique_ptr } } -float logit(float p) -{ - if (p >= 1.0) - p = 0.99999; - else if (p <= 0.0) - p = 0.0000001; - p = p / (1 - p); - return log(p) / 16; +float inline logit(float p) +{ + if (p >= 0.9999999f) + p = 0.9999999f; + else if (p <= 0.0000001f) + p = 0.0000001f; + + p = p / (1.0f - p); + return log(p) / 16.0f; } void Tracker::detect_face(const cv::Mat& image, FaceData& face_data) { - cv::Mat resized; + cv::Mat resized, faces; cv::resize(image, resized, cv::Size(224, 224), NULL, NULL, cv::INTER_LINEAR); - improc.normalize(resized); - improc.transpose((float*)resized.data, buffer_data); - - Ort::Value input_tensor = Ort::Value::CreateTensor(memory_info, buffer_data, tensor_input_size, tensor_input_dims, 4); - - - auto output_tensors = session->Run(Ort::RunOptions{ nullptr }, - detection_input_node_names.data(), &input_tensor, 1, detection_output_node_names.data(), 2); - - float* output_arr = output_tensors[0].GetTensorMutableData(); - float* maxpool_arr = output_tensors[1].GetTensorMutableData(); + float width = (float)image.cols; + float height = (float)image.rows; + int im_width = resized.cols; + int im_height = resized.rows; - cv::Mat out(4, tensor_detection_output_dims, CV_32F, output_arr); - cv::Mat maxpool(4, tensor_detection_output_dims, CV_32F, maxpool_arr); + this->face_detector->detect(resized, faces); - - cv::Mat first(56, 56, CV_32F, out.ptr(0,0)); - cv::Mat second(56, 56, CV_32F, out.ptr(0,1)); - - cv::Point p(-1, -1); - cv::minMaxLoc(first, NULL, NULL, NULL, &p); - - - float c = first.at(p); - float r = second.at(p) * 2 * 56; - int x = p.x * 4; - int y = p.y * 4; - - - face_data.face_detected = c > .7 ? true : false; - - if (face_data.face_detected) + + + // Get data + face_data.face_detected = false; + if (faces.rows > 0) { - float face[] = { x - r, y - r, 2 * r, 2 * r }; - float width = image.cols; - float height = image.rows; - - face[0] *= width / 224; - face[2] *= width / 224; - face[1] *= height / 224; - face[3] *= height / 224; + face_data.face_detected = true; + float x0 = faces.at(0, 0); + float y0 = faces.at(0, 1); + float face_w = faces.at(0, 2); + float face_h = faces.at(0, 3); + + + float w_ratio = (width / im_width); + float h_ratio = (height / im_height); + + float x_offset = 0;//face_w * 0.01; + float y_offset = 0;// face_h * 0.01; + + float face[] = { + ((x0 - x_offset) * (w_ratio) ), + ((y0 - y_offset) * (h_ratio) ), + ((face_w) * (w_ratio) ), + ((face_h) * (h_ratio) ) + }; proc_face_detect(face, width, height); - face_data.face_coords[0] = face[0]; - face_data.face_coords[1] = face[1]; - face_data.face_coords[2] = face[2]; - face_data.face_coords[3] = face[3]; + face_data.face_coords[0] = (int)face[0]; + face_data.face_coords[1] = (int)face[1]; + face_data.face_coords[2] = (int)face[2]; + face_data.face_coords[3] = (int)face[3]; + } - } - - void Tracker::detect_landmarks(const cv::Mat& image, int x0, int y0, float scale_x, float scale_y, FaceData& face_data) { cv::Mat resized; cv::resize(image, resized, cv::Size(224, 224), NULL, NULL, cv::INTER_LINEAR); - improc.normalize(resized); - improc.transpose((float*)resized.data, buffer_data); + resized.convertTo(resized, CV_32F); + cv::cvtColor(resized, resized, cv::COLOR_BGR2RGB); + improc.normalize_and_transpose(resized, buffer_data); // combine methods Ort::Value input_tensor = Ort::Value::CreateTensor(memory_info, buffer_data, tensor_input_size, tensor_input_dims, 4); @@ -159,15 +157,15 @@ void Tracker::proc_face_detect(float* face, float width, float height) float w = face[2]; float h = face[3]; - int crop_x1 = (int)(x - w * 0.09f); - int crop_y1 = (int)(y - h * 0.450f); - int crop_x2 = (int)(x + w + w * 0.09f); - int crop_y2 = (int)(y + h + h * 0.450f); + int crop_x1 = (int)(x); + int crop_y1 = (int)(y); + int crop_x2 = (int)(x + w); + int crop_y2 = (int)(y + h + h * 0.1f); // force a little taller BB so the chin tends to be covered - face[0] = std::max(0, crop_x1); - face[1] = std::max(0, crop_y1); - face[2] = std::min((int)width, crop_x2); - face[3] = std::min((int)height, crop_y2); + face[0] = (float)std::max(0, crop_x1); + face[1] = (float)std::max(0, crop_y1); + face[2] = (float)std::min((int)width, crop_x2); + face[3] = (float)std::min((int)height, crop_y2); } @@ -179,12 +177,14 @@ void Tracker::proc_heatmaps(float* heatmaps, int x0, int y0, float scale_x, floa int offset = heatmap_size * landmark; int argmax = -100; float maxval = -100; + + float* landmark_heatmap = &heatmaps[offset]; // reduce indexing for (int i = 0; i < heatmap_size; i++) { - if (heatmaps[offset + i] > maxval) + if (landmark_heatmap[i] > maxval) { argmax = i; - maxval = heatmaps[offset + i]; + maxval = landmark_heatmap[i]; } } @@ -192,15 +192,15 @@ void Tracker::proc_heatmaps(float* heatmaps, int x0, int y0, float scale_x, floa int y = argmax % 28; - float conf = heatmaps[offset + argmax]; + // float conf = heatmaps[offset + argmax]; unreferenced local variable float res = 223; - int off_x = floor(res * (logit(heatmaps[66 * heatmap_size + offset + argmax])) + 0.1); - int off_y = floor(res * (logit(heatmaps[2 * 66 * heatmap_size + offset + argmax])) + 0.1); + int off_x = (int)floor(res * (logit(heatmaps[66 * heatmap_size + offset + argmax])) + 0.1f); + int off_y = (int)floor(res * (logit(heatmaps[2 * 66 * heatmap_size + offset + argmax])) + 0.1f); - float lm_x = (float)y0 + (float)(scale_x * (res * (float(x) / 27.) + off_x)); - float lm_y = (float)x0 + (float)(scale_y * (res * (float(y) / 27.) + off_y)); + float lm_x = (float)y0 + (float)(scale_x * (res * (float(x) / 27.0f) + off_x)); + float lm_y = (float)x0 + (float)(scale_y * (res * (float(y) / 27.0f) + off_y)); face_data.landmark_coords[2 * landmark] = lm_x; face_data.landmark_coords[2 * landmark + 1] = lm_y; diff --git a/AITracker/src/model.h b/AITracker/src/model.h index 320d200..a7a2804 100644 --- a/AITracker/src/model.h +++ b/AITracker/src/model.h @@ -1,12 +1,15 @@ #pragma once -#include "opencv.hpp" +#include "opencv2/opencv.hpp" + #include #include "data.h" #include "imageprocessor.h" #include "PositionSolver.h" #include "filters.h" + + class Tracker { @@ -32,6 +35,7 @@ class Tracker std::vector landmarks_input_node_names; std::vector landmarks_output_node_names; + cv::Ptr face_detector; size_t tensor_input_size; int64_t tensor_input_dims[4] = { 1,3,224,224 }; diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f8ba81..d1eae81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ SET(ONNXRUNTIME_EXTRACT_PATH "Dependencies/") #SET(PS3Driver_URL "") #SET(PS3Driver_PATH "") -SET(OPENCV_URL "https://github.com/opencv/opencv/releases/download/4.3.0/opencv-4.3.0-vc14_vc15.exe") -SET(OPENCV_PATH "${DEPS_DIR}opencv-4.3.0-vc14_vc15.exe") +SET(OPENCV_URL "https://github.com/opencv/opencv/releases/download/4.6.0/opencv-4.6.0-vc14_vc15.exe") +SET(OPENCV_PATH "${DEPS_DIR}opencv-4.6.0-vc14_vc15.exe") SET(LIBUSB_URL "https://github.com/libusb/libusb/releases/download/v1.0.23/libusb-1.0.23.7z") SET(LIBUSB_NAME "libusb-1.0.23") diff --git a/Camera.sln b/Camera.sln index ca44b7a..f146dfd 100644 --- a/Camera.sln +++ b/Camera.sln @@ -44,7 +44,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8A67DE57-0604-4880-B0CC-9B96E5E3EFCD} Qt5Version = $(DefaultQtVersion) + SolutionGuid = {8A67DE57-0604-4880-B0CC-9B96E5E3EFCD} EndGlobalSection EndGlobal diff --git a/Client/Client.vcxproj b/Client/Client.vcxproj index 5bb37b0..8fcd8d8 100644 --- a/Client/Client.vcxproj +++ b/Client/Client.vcxproj @@ -78,7 +78,7 @@ $(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) + $(Qt_LIBS_);opencv_world460.lib;onnxruntime.lib;Ws2_32.lib;libusb-1.0.lib;legacy_stdio_definitions.lib;%(AdditionalDependencies) true true @@ -104,7 +104,7 @@ $(Qt_LIBPATH_);$(SolutionDir)Dependencies\libusb\MS64\static;$(SolutionDir)Dependencies\OpenCV\lib;$(SolutionDir)Dependencies\onnxruntime\lib\;%(AdditionalLibraryDirectories) - $(Qt_LIBS_);opencv_world430d.lib;onnxruntime.lib;Ws2_32.lib;legacy_stdio_definitions.lib;libusb-1.0.lib;%(AdditionalDependencies) + $(Qt_LIBS_);opencv_world460d.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\;$(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) @@ -155,12 +155,12 @@ true true None - Disabled + MaxSpeed MultiThreadedDLL Console - true + false diff --git a/Client/src/Main.cpp b/Client/src/Main.cpp index 25dfda6..3d9111f 100644 --- a/Client/src/Main.cpp +++ b/Client/src/Main.cpp @@ -21,10 +21,6 @@ int main(int argc, char *argv[]) { - SetEnvironmentVariable(LPWSTR("OMP_NUM_THREADS"), LPWSTR("1")); - omp_set_num_threads(1); // Disable ONNX paralelization so we dont steal all cpu cores. - omp_set_dynamic(0); - #if defined(Q_OS_WIN) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif @@ -45,16 +41,26 @@ int main(int argc, char *argv[]) logger->info(" ---------- AITRACK LOG ----------"); + auto conf_mgr = std::make_unique("./prefs.ini"); + logger->info("Created/Found prefs.ini"); + + auto state = conf_mgr->getConfig(); + if (state.onnx_set_env_threads) { + std::wstring ws = std::to_wstring(state.onnx_env_threads); + SetEnvironmentVariable(LPWSTR(L"OMP_NUM_THREADS"), ws.c_str()); + } + if (state.onnx_set_num_threads) { + omp_set_num_threads(state.onnx_num_threads); + } + if (state.onnx_set_dynamic) { + omp_set_dynamic(state.onnx_dynamic); + } 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)); diff --git a/Client/src/camera/OCVCamera.h b/Client/src/camera/OCVCamera.h index 2d1e0bd..81492b5 100644 --- a/Client/src/camera/OCVCamera.h +++ b/Client/src/camera/OCVCamera.h @@ -1,6 +1,6 @@ #pragma once #include "Camera.h" -#include "opencv.hpp" +#include "opencv2/opencv.hpp" class OCVCamera : public Camera { diff --git a/Client/src/model/Config.cpp b/Client/src/model/Config.cpp index e4c652c..dd72360 100644 --- a/Client/src/model/Config.cpp +++ b/Client/src/model/Config.cpp @@ -17,16 +17,23 @@ ConfigData ConfigData::getGenericConfig() conf.num_cameras_detected = 0; conf.video_width = -1; conf.video_height = -1; - conf.video_fps = -1; + conf.video_fps = 30; conf.use_landmark_stab = true; conf.autocheck_updates = true; conf.tracking_shortcut_enabled = false; conf.x, conf.y, conf.z, conf.pitch, conf.yaw, conf.roll = 0; conf.cam_exposure = -1; conf.cam_gain = -1; + conf.onnx_set_env_threads = true; + conf.onnx_env_threads = 1; + conf.onnx_set_num_threads = true; + conf.onnx_num_threads = 1; + conf.onnx_set_dynamic = true; + conf.onnx_dynamic = 0; conf.head_scale_x = 1.0; conf.head_scale_y = 1.0; conf.head_scale_z = 1.0; + return conf; } @@ -59,10 +66,19 @@ void ConfigMgr::updateConfig(const ConfigData& data) conf.setValue("cam_gain", data.cam_gain); conf.setValue("selected_camera", data.selected_camera); conf.setValue("autocheck_updates", data.autocheck_updates); + + conf.setValue("onnx_set_env_threads", data.onnx_set_env_threads); + conf.setValue("onnx_env_threads", data.onnx_env_threads); + conf.setValue("onnx_set_num_threads", data.onnx_set_num_threads); + conf.setValue("onnx_num_threads", data.onnx_num_threads); + conf.setValue("onnx_set_dynamic", data.onnx_set_dynamic); + conf.setValue("onnx_dynamic", data.onnx_dynamic); + conf.setValue("head_3d_scale_x", data.head_scale_x); conf.setValue("head_3d_scale_y", data.head_scale_y); conf.setValue("head_3d_scale_z", data.head_scale_z); conf.setValue("tracking_shortcut_enabled", data.tracking_shortcut_enabled); + } ConfigData ConfigMgr::getConfig() @@ -82,10 +98,17 @@ ConfigData ConfigMgr::getConfig() c.cam_exposure= conf.value("cam_exposure", -1).toInt(); c.cam_gain = conf.value("cam_gain", -1).toInt(); c.autocheck_updates = conf.value("autocheck_updates", 1).toBool(); + c.onnx_set_env_threads = conf.value("set_env_threads", true).toBool(); + c.onnx_env_threads = conf.value("env_threads", 1).toInt(); + c.onnx_set_num_threads = conf.value("set_num_threads", true).toBool(); + c.onnx_num_threads = conf.value("num_threads", 1).toInt(); + c.onnx_set_dynamic = conf.value("set_dynamic", true).toBool(); + c.onnx_dynamic = conf.value("dynamic", 0).toInt(); c.head_scale_x = conf.value("head_3d_scale_x", 1.0).toDouble(); c.head_scale_y = conf.value("head_3d_scale_y", 1.0).toDouble(); c.head_scale_z = conf.value("head_3d_scale_z", 1.0).toDouble(); c.tracking_shortcut_enabled= conf.value("tracking_shortcut_enabled", false).toBool(); + return c; } diff --git a/Client/src/model/Config.h b/Client/src/model/Config.h index fc37a03..1a2f279 100644 --- a/Client/src/model/Config.h +++ b/Client/src/model/Config.h @@ -30,6 +30,13 @@ struct ConfigData int cam_exposure; int cam_gain; + bool onnx_set_env_threads; + int onnx_env_threads; + bool onnx_set_num_threads; + int onnx_num_threads; + bool onnx_set_dynamic; + int onnx_dynamic; + std::vector model_names; int selected_model; diff --git a/Client/src/model/UDPSender.cpp b/Client/src/model/UDPSender.cpp index 6798495..15d5f29 100644 --- a/Client/src/model/UDPSender.cpp +++ b/Client/src/model/UDPSender.cpp @@ -4,27 +4,54 @@ UDPSender::UDPSender(const char* dest_ip, int dest_port) { - this->ip = std::string(dest_ip); this->port = dest_port; + //std::cout << "ip: " << this->ip << " port: " << this->port << std::endl; - dest = sockaddr_in(); - local = sockaddr_in(); - WSAStartup(MAKEWORD(2, 2), &data); - local.sin_family = AF_INET; - inet_pton(AF_INET, dest_ip, &local.sin_addr.s_addr); - local.sin_port = htons(0); - dest.sin_family = AF_INET; - inet_pton(AF_INET, dest_ip, &dest.sin_addr.s_addr); - dest.sin_port = htons(dest_port); + memset(&dest_IPv6, 0, sizeof(dest_IPv6)); + memset(&local_IPv6, 0, sizeof(local_IPv6)); + + if (inet_pton(AF_INET6, dest_ip, &dest_IPv6.sin6_addr) == 1) + { + // valid IPv6 address + this->s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + dest_IPv6.sin6_family = AF_INET6; + dest_IPv6.sin6_port = htons(dest_port); + local_IPv6.sin6_addr = IN6ADDR_ANY_INIT; + local_IPv6.sin6_family = AF_INET6; + local_IPv6.sin6_port = htons(0); + + //local_IPv6.sin6_addr = IN6ADDR_ANY_INIT; + bind(s, (sockaddr*)&local_IPv6, sizeof(local_IPv6)); + } + else if (inet_pton(AF_INET, dest_ip, &dest.sin_addr) == 1) + { + // valid IPv4 address + this->s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + dest.sin_family = AF_INET; + dest.sin_port = htons(dest_port); + + local.sin_family = AF_INET; + local.sin_port = htons(0); + //local.sin_addr.S_un.S_addr = INADDR_ANY; + bind(s, (sockaddr*)&local, sizeof(local)); + } + else + { + // In case of invalid address better mark this sender as invalid + // and not use loopback. User of this class hould know whether he/she + // has made a mistake. + this->valid = false; + std::cout << "Invalid IP Address" << std::endl; + } - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - bind(s, (sockaddr*)&local, sizeof(local)); } UDPSender::~UDPSender() diff --git a/Client/src/model/UDPSender.h b/Client/src/model/UDPSender.h index d46b4aa..bb68e92 100644 --- a/Client/src/model/UDPSender.h +++ b/Client/src/model/UDPSender.h @@ -2,9 +2,11 @@ #include #include +#include #include + /** Data sender to Opentrack using UDP */ @@ -14,8 +16,16 @@ class UDPSender const int BUFFER_SIZE = sizeof(double) * 6; double position_data[6]; - sockaddr_in dest; - sockaddr_in local; + union + { + sockaddr_in dest; + sockaddr_in6 dest_IPv6; + }; + union + { + sockaddr_in local; + sockaddr_in6 local_IPv6; + }; WSAData data; SOCKET s; @@ -23,6 +33,7 @@ class UDPSender public: std::string ip; int port; + bool valid = true; UDPSender(const char* dest_ip, int dest_port); ~UDPSender(); diff --git a/Client/src/presenter/presenter.cpp b/Client/src/presenter/presenter.cpp index d91bf12..9b780fe 100644 --- a/Client/src/presenter/presenter.cpp +++ b/Client/src/presenter/presenter.cpp @@ -3,7 +3,7 @@ #include #include "presenter.h" -#include "opencv.hpp" +#include "opencv2/opencv.hpp" #include "../camera/CameraFactory.h" @@ -209,7 +209,7 @@ void Presenter::run_loop() } cv::Point p1(d.face_coords[0], d.face_coords[1]); cv::Point p2(d.face_coords[2], d.face_coords[3]); - cv::rectangle(mat, p1, p2, color_blue, 1); + cv::rectangle(mat, p1, p2, color_blue, 2); } update_tracking_data(d); diff --git a/Client/src/version.h b/Client/src/version.h index 6ef866d..acf28c9 100644 --- a/Client/src/version.h +++ b/Client/src/version.h @@ -1,3 +1,3 @@ #pragma once -#define AITRACK_VERSION "v0.6.5-alpha" \ No newline at end of file +#define AITRACK_VERSION "v0.6.6-alpha" \ No newline at end of file diff --git a/Client/src/view/ConfigWindow.cpp b/Client/src/view/ConfigWindow.cpp index d06240a..4b84da6 100644 --- a/Client/src/view/ConfigWindow.cpp +++ b/Client/src/view/ConfigWindow.cpp @@ -1,4 +1,5 @@ #include "ConfigWindow.h" +#include ConfigWindow::ConfigWindow(IRootView *prev_window, QWidget *parent) : QWidget(parent) @@ -77,6 +78,11 @@ ConfigData ConfigWindow::get_inputs() conf.autocheck_updates = check_auto_update->isChecked(); conf.tracking_shortcut_enabled = check_enable_tracking_shortcut->isChecked(); + if (conf.ip.length() == 0) + conf.ip = std::string("127.0.0.1"); /* default to loopback IPv4 on same computer */ + if (conf.port == 0) + conf.port = 4242; /* default to opentrack port */ + return conf; } diff --git a/Client/src/view/WindowMain.h b/Client/src/view/WindowMain.h index 6b9d3f3..2fb692c 100644 --- a/Client/src/view/WindowMain.h +++ b/Client/src/view/WindowMain.h @@ -6,7 +6,7 @@ #include -#include "opencv.hpp" +#include "opencv2/opencv.hpp" #include "../presenter/i_presenter.h" #include "ui_MainWindow.h" diff --git a/Client/src/view/i_view.h b/Client/src/view/i_view.h index 4f4d29f..d9a2429 100644 --- a/Client/src/view/i_view.h +++ b/Client/src/view/i_view.h @@ -1,7 +1,7 @@ #pragma once -#include "opencv.hpp" +#include "opencv2/opencv.hpp" #include "../model/Config.h" #include "../presenter/i_presenter.h" diff --git a/PS3Driver/src/ps3eye.cpp b/PS3Driver/src/ps3eye.cpp index f661c92..e039b13 100644 --- a/PS3Driver/src/ps3eye.cpp +++ b/PS3Driver/src/ps3eye.cpp @@ -189,7 +189,7 @@ static const uint8_t ov772x_reg_initdata[][2] = { { 0x11, 0x00 }, { 0x0D, 0x41 }, - { 0x8E, 0x00 }, // De-noise threshold - jfrancois 0x00 - orig 0x04 + { 0x8E, 0x00 } // De-noise threshold - jfrancois 0x00 - orig 0x04 }; static const uint8_t bridge_start_vga[][2] = { @@ -201,7 +201,7 @@ static const uint8_t bridge_start_vga[][2] = { {0x1d, 0x2C}, /* frame size */ {0x1d, 0x00}, /* frame size */ {0xc0, 0x50}, - {0xc1, 0x3c}, + {0xc1, 0x3c} }; static const uint8_t sensor_start_vga[][2] = { {0x12, 0x01}, @@ -211,7 +211,7 @@ static const uint8_t sensor_start_vga[][2] = { {0x1a, 0xf0}, {0x29, 0xa0}, {0x2c, 0xf0}, - {0x65, 0x20}, + {0x65, 0x20} }; static const uint8_t bridge_start_qvga[][2] = { {0x1c, 0x00}, @@ -222,7 +222,7 @@ static const uint8_t bridge_start_qvga[][2] = { {0x1d, 0x4b}, /* frame size */ {0x1d, 0x00}, /* frame size */ {0xc0, 0x28}, - {0xc1, 0x1e}, + {0xc1, 0x1e} }; static const uint8_t sensor_start_qvga[][2] = { {0x12, 0x41}, @@ -232,7 +232,7 @@ static const uint8_t sensor_start_qvga[][2] = { {0x1a, 0x78}, {0x29, 0x50}, {0x2c, 0x78}, - {0x65, 0x2f}, + {0x65, 0x2f} }; /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ @@ -812,10 +812,12 @@ class URBDesc USBMgr::instance()->cameraStopped(); - free(transfer_buffer); + if (transfer_buffer) + free(transfer_buffer); transfer_buffer = NULL; - delete frame_queue; + if (frame_queue) + delete frame_queue; frame_queue = NULL; } @@ -826,7 +828,7 @@ class URBDesc num_active_transfers_condition.notify_one(); } - void frame_add(enum gspca_packet_type packet_type, const uint8_t *data, int len) + void inline frame_add(enum gspca_packet_type packet_type, const uint8_t *data, int len) { if (packet_type == FIRST_PACKET) { @@ -1312,7 +1314,7 @@ uint16_t PS3EYECam::ov534_set_frame_rate(uint16_t frame_rate, bool dry_run) {8, 0x02, 0x01, 0x02}, {5, 0x04, 0x01, 0x02}, {3, 0x06, 0x01, 0x02}, - {2, 0x09, 0x01, 0x02}, + {2, 0x09, 0x01, 0x02} }; static const struct rate_s rate_1[] = { /* 320x240 */ {290, 0x00, 0xc1, 0x04}, @@ -1336,7 +1338,7 @@ uint16_t PS3EYECam::ov534_set_frame_rate(uint16_t frame_rate, bool dry_run) {7, 0x04, 0x01, 0x04}, {5, 0x06, 0x01, 0x04}, {3, 0x09, 0x01, 0x04}, - {2, 0x18, 0x01, 0x02}, + {2, 0x18, 0x01, 0x02} }; if (frame_width == 640) { @@ -1362,24 +1364,25 @@ uint16_t PS3EYECam::ov534_set_frame_rate(uint16_t frame_rate, bool dry_run) return r->fps; } -void PS3EYECam::ov534_reg_write(uint16_t reg, uint8_t val) +void inline PS3EYECam::ov534_reg_write(uint16_t reg, uint8_t val) { int ret; //debug("reg=0x%04x, val=0%02x", reg, val); - usb_buf[0] = val; + // usb_buf[0] = val; + + ret = libusb_control_transfer(handle_, + LIBUSB_ENDPOINT_OUT | + LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + 0x01, 0x00, reg, + &val, 1, 500); - ret = libusb_control_transfer(handle_, - LIBUSB_ENDPOINT_OUT | - LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, - 0x01, 0x00, reg, - usb_buf, 1, 500); if (ret < 0) { debug("write failed\n"); } } -uint8_t PS3EYECam::ov534_reg_read(uint16_t reg) +uint8_t inline PS3EYECam::ov534_reg_read(uint16_t reg) { int ret; @@ -1396,7 +1399,7 @@ uint8_t PS3EYECam::ov534_reg_read(uint16_t reg) return usb_buf[0]; } -int PS3EYECam::sccb_check_status() +int inline PS3EYECam::sccb_check_status() { uint8_t data; int i; @@ -1419,7 +1422,7 @@ int PS3EYECam::sccb_check_status() return 0; } -void PS3EYECam::sccb_reg_write(uint8_t reg, uint8_t val) +void inline PS3EYECam::sccb_reg_write(uint8_t reg, uint8_t val) { //debug("reg: 0x%02x, val: 0x%02x", reg, val); ov534_reg_write(OV534_REG_SUBADDR, reg); @@ -1432,7 +1435,7 @@ void PS3EYECam::sccb_reg_write(uint8_t reg, uint8_t val) } -uint8_t PS3EYECam::sccb_reg_read(uint16_t reg) +uint8_t inline PS3EYECam::sccb_reg_read(uint16_t reg) { ov534_reg_write(OV534_REG_SUBADDR, (uint8_t)reg); ov534_reg_write(OV534_REG_OPERATION, OV534_OP_WRITE_2); diff --git a/README.md b/README.md index 7fe2214..cf1fbb1 100644 --- a/README.md +++ b/README.md @@ -63,4 +63,4 @@ Thank you! ## Acknowledgements - [inspirit](https://github.com/inspirit), for the PS3 C++ camera library which I used during development. -- [emilianavt](https://github.com/emilianavt/), for porting the original Pytorch pretrained models to ONNX. +- [emilianavt](https://github.com/emilianavt/), for porting the original Pytorch pretrained landmark model to ONNX format. diff --git a/models/detection.onnx b/models/detection.onnx index 60bbf7a..f223594 100644 Binary files a/models/detection.onnx and b/models/detection.onnx differ