|
|
| #include <b64/encode.h> |
| #include <fstream> |
| #include <jsoncpp/json/json.h> |
| #include <opencv2/opencv.hpp> |
| #include <sstream> |
| #include <vector> |
|
|
| |
| #include <boost/archive/iterators/base64_from_binary.hpp> |
| #include <boost/archive/iterators/binary_from_base64.hpp> |
| #include <boost/archive/iterators/transform_width.hpp> |
|
|
| |
| struct APIParams { |
| |
| std::vector<std::string> data; |
|
|
| |
| std::vector<int> max_keypoints; |
|
|
| |
| std::vector<std::string> timestamps; |
|
|
| |
| bool grayscale; |
|
|
| |
| std::vector<std::vector<int>> image_hw; |
|
|
| |
| int feature_type; |
|
|
| |
| std::vector<double> rotates; |
|
|
| |
| std::vector<double> scales; |
|
|
| |
| std::vector<std::vector<float>> reference_points; |
|
|
| |
| bool binarize; |
| }; |
|
|
| |
| |
| |
| |
| |
| class KeyPointResults { |
| public: |
| KeyPointResults() { |
| } |
|
|
| |
| |
| |
| |
| |
| KeyPointResults(const std::vector<std::vector<cv::KeyPoint>>& kp, |
| const std::vector<cv::Mat>& desc) |
| : keypoints(kp), descriptors(desc) { |
| } |
|
|
| |
| |
| |
| |
| |
| inline void append_keypoints(std::vector<cv::KeyPoint>& kpts) { |
| keypoints.emplace_back(kpts); |
| } |
|
|
| |
| |
| |
| |
| |
| inline void append_descriptors(cv::Mat& desc) { |
| descriptors.emplace_back(desc); |
| } |
|
|
| |
| |
| |
| |
| |
| inline std::vector<std::vector<cv::KeyPoint>> get_keypoints() { |
| return keypoints; |
| } |
|
|
| |
| |
| |
| |
| |
| inline std::vector<cv::Mat> get_descriptors() { |
| return descriptors; |
| } |
|
|
| private: |
| std::vector<std::vector<cv::KeyPoint>> keypoints; |
| std::vector<cv::Mat> descriptors; |
| std::vector<std::vector<float>> scores; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| std::string base64_decode(const std::string& base64) { |
| using namespace boost::archive::iterators; |
| using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>; |
|
|
| |
| auto end = base64.find_last_not_of(" \t\n\r"); |
| if (end != std::string::npos) { |
| |
| end += 1; |
| } |
|
|
| |
| return std::string(It(base64.begin()), It(base64.begin() + end)); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| cv::Mat base64_to_image(const std::string& base64) { |
| |
| std::string decodedStr = base64_decode(base64); |
|
|
| |
| std::vector<uchar> data(decodedStr.begin(), decodedStr.end()); |
| cv::Mat img = cv::imdecode(data, cv::IMREAD_GRAYSCALE); |
|
|
| |
| if (img.empty()) { |
| throw std::runtime_error("Failed to decode image"); |
| } |
|
|
| return img; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| std::string image_to_base64(cv::Mat& img) { |
| if (img.empty()) { |
| throw std::runtime_error("Failed to read image"); |
| } |
|
|
| |
| std::vector<uchar> buf; |
| if (!cv::imencode(".png", img, buf)) { |
| throw std::runtime_error("Failed to encode image"); |
| } |
|
|
| |
| using namespace boost::archive::iterators; |
| using It = |
| base64_from_binary<transform_width<std::vector<uchar>::const_iterator, 6, 8>>; |
| std::string base64(It(buf.begin()), It(buf.end())); |
|
|
| |
| base64.append((3 - buf.size() % 3) % 3, '='); |
|
|
| return base64; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* s) { |
| size_t newLength = size * nmemb; |
| try { |
| |
| s->resize(s->size() + newLength); |
| } catch (std::bad_alloc& e) { |
| |
| return 0; |
| } |
|
|
| |
| std::copy(static_cast<const char*>(contents), |
| static_cast<const char*>(contents) + newLength, |
| s->begin() + s->size() - newLength); |
| return newLength; |
| } |
|
|
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> Json::Value toJson(const T& val) { |
| return Json::Value(val); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> Json::Value vectorToJson(const std::vector<T>& vec) { |
| Json::Value json(Json::arrayValue); |
| for (const auto& item : vec) { |
| json.append(item); |
| } |
| return json; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename T> |
| Json::Value nestedVectorToJson(const std::vector<std::vector<T>>& vec) { |
| Json::Value json(Json::arrayValue); |
| for (const auto& subVec : vec) { |
| json.append(vectorToJson(subVec)); |
| } |
| return json; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Json::Value paramsToJson(const APIParams& params) { |
| Json::Value json; |
| json["data"] = vectorToJson(params.data); |
| json["max_keypoints"] = vectorToJson(params.max_keypoints); |
| json["timestamps"] = vectorToJson(params.timestamps); |
| json["grayscale"] = toJson(params.grayscale); |
| json["image_hw"] = nestedVectorToJson(params.image_hw); |
| json["feature_type"] = toJson(params.feature_type); |
| json["rotates"] = vectorToJson(params.rotates); |
| json["scales"] = vectorToJson(params.scales); |
| json["reference_points"] = nestedVectorToJson(params.reference_points); |
| json["binarize"] = toJson(params.binarize); |
| return json; |
| } |
|
|
| template <typename T> cv::Mat jsonToMat(Json::Value json) { |
| int rows = json.size(); |
| int cols = json[0].size(); |
|
|
| |
| std::vector<T> data; |
| data.reserve(rows * cols); |
|
|
| for (int i = 0; i < rows; i++) { |
| for (int j = 0; j < cols; j++) { |
| data.push_back(static_cast<T>(json[i][j].asInt())); |
| } |
| } |
|
|
| |
| cv::Mat mat(rows, cols, CV_8UC1, |
| data.data()); |
| |
| |
|
|
| return mat; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| KeyPointResults decode_response(const std::string& response, bool viz = true) { |
| Json::CharReaderBuilder builder; |
| Json::CharReader* reader = builder.newCharReader(); |
|
|
| Json::Value jsonData; |
| std::string errors; |
|
|
| |
| bool parsingSuccessful = reader->parse( |
| response.c_str(), response.c_str() + response.size(), &jsonData, &errors); |
| delete reader; |
|
|
| if (!parsingSuccessful) { |
| |
| std::cout << "Failed to parse the JSON, errors:" << std::endl; |
| std::cout << errors << std::endl; |
| return KeyPointResults(); |
| } |
|
|
| KeyPointResults kpts_results; |
|
|
| |
| for (const auto& jsonItem : jsonData) { |
| auto jkeypoints = jsonItem["keypoints"]; |
| auto jkeypoints_orig = jsonItem["keypoints_orig"]; |
| auto jdescriptors = jsonItem["descriptors"]; |
| auto jscores = jsonItem["scores"]; |
| auto jimageSize = jsonItem["image_size"]; |
| auto joriginalSize = jsonItem["original_size"]; |
| auto jsize = jsonItem["size"]; |
|
|
| std::vector<cv::KeyPoint> vkeypoints; |
| std::vector<float> vscores; |
|
|
| |
| int counter = 0; |
| for (const auto& keypoint : jkeypoints_orig) { |
| if (counter < 10) { |
| |
| std::cout << keypoint[0].asFloat() << ", " << keypoint[1].asFloat() |
| << std::endl; |
| } |
| counter++; |
| |
| vkeypoints.emplace_back( |
| cv::KeyPoint(keypoint[0].asFloat(), keypoint[1].asFloat(), 0.0)); |
| } |
|
|
| if (viz && jsonItem.isMember("image_orig")) { |
| auto jimg_orig = jsonItem["image_orig"]; |
| cv::Mat img = jsonToMat<uchar>(jimg_orig); |
| cv::imwrite("viz_image_orig.jpg", img); |
|
|
| |
| cv::Mat imgWithKeypoints; |
| cv::drawKeypoints(img, vkeypoints, imgWithKeypoints, cv::Scalar(0, 0, 255)); |
|
|
| |
| std::string filename = "viz_image_orig_keypoints.jpg"; |
| cv::imwrite(filename, imgWithKeypoints); |
| } |
|
|
| |
| cv::Mat descriptors = jsonToMat<uchar>(jdescriptors); |
| kpts_results.append_keypoints(vkeypoints); |
| kpts_results.append_descriptors(descriptors); |
| } |
| return kpts_results; |
| } |
|
|