AI Watch A1
Multi-person 3D skeleton detection using Intel RealSense and OpenPose with Kafka support.
OpenCV_Manager.cpp
Go to the documentation of this file.
1//
2// OpenCV_Manager.cpp
3// AI Watch A1
4//
5// Created by Denny Caruso on 23/07/22.
6//
7
8// License: Apache 2.0. See LICENSE file in root directory.
9// Copyright(c) 2022. All Rights Reserved.
10
11#include "OpenCV_Manager.hpp"
12
13
14
15cv::Mat OpenCV_Manager::realsenseFrameToMat (const rs2::frame & singleFrame) {
16 rs2::video_frame videoFrame = singleFrame.as<rs2::video_frame>();
17 const int frameWidth = videoFrame.get_width(), frameHeight = videoFrame.get_height();
18
19 switch (singleFrame.get_profile().format()) {
20 case RS2_FORMAT_BGR8:
21 return cv::Mat(cv::Size(frameWidth, frameHeight), CV_8UC3, (void *) singleFrame.get_data(), cv::Mat::AUTO_STEP);
22 case RS2_FORMAT_RGB8: {
23 cv::Mat rgbFrame = cv::Mat(cv::Size(frameWidth, frameHeight), CV_8UC3, (void *) singleFrame.get_data(), cv::Mat::AUTO_STEP);
24 cv::cvtColor(rgbFrame, rgbFrame, cv::COLOR_RGB2BGR);
25 return rgbFrame;
26 }
27 case RS2_FORMAT_Z16:
28 return cv::Mat(cv::Size(frameWidth, frameHeight), CV_16UC1, (void *) singleFrame.get_data(), cv::Mat::AUTO_STEP);
29 case RS2_FORMAT_Y8:
30 return cv::Mat(cv::Size(frameWidth, frameHeight), CV_8UC1, (void *) singleFrame.get_data(), cv::Mat::AUTO_STEP);
31 default:
32 throw std::runtime_error("Frame format is not supported yet!");
33 break;
34 }
35}
36
37void OpenCV_Manager::getVideoFramesCV (unsigned int user_nFrame, rs2::pipeline & pipelineStream, float scale, const unsigned short int framesToSkip) {
38 UsageManager * usageManagerInstance = UsageManager::getInstance();
39 if (usageManagerInstance == nullptr) CV_Error(USAGE_MANAGER_NULLPTR_ERROR, USAGE_MANAGER_NULLPTR_SCOPE);
40 char ** argv = * usageManagerInstance->get_argv();
41 const char * imagesFolder = argv[imagesFolderOffset];
42 FacadeSingleton * facadeSingletonInstance = FacadeSingleton::getInstance();
43 if (facadeSingletonInstance == nullptr) CV_Error(FACADE_SINGLETON_NULLPTR_ERROR, FACADE_SINGLETON_NULLPTR_SCOPE);
44 RealSenseManager * cameraManager = facadeSingletonInstance->getCameraManager();
45 ImageManager * imageManager = facadeSingletonInstance->getImageManager();
46
47 // Do this until we don't capture, convert, scale, compute and save user_nFrame frame
48 for (unsigned int nFrame = 0; nFrame < user_nFrame; nFrame++) {
49 // Capture
50 unsigned int frameID = cameraManager->getFrameID();
51 rs2::depth_frame depthFrame = rs2::depth_frame(rs2::frame());
52 rs2::frame colorFrame, colorizedDepthFrame;
53 cameraManager->getVideoFramesRS(user_nFrame, pipelineStream, depthFrame, colorFrame, colorizedDepthFrame, framesToSkip);
54 int cols = depthFrame.get_width(), rows = depthFrame.get_height();
55 // Convert
56 cv::Mat colorImage = realsenseFrameToMat(colorFrame), distanceImage = cv::Mat::zeros(rows, cols, CV_32FC1);
57 cv::Mat depthImage = realsenseFrameToMat(depthFrame), colorizedDepthImage = realsenseFrameToMat(colorizedDepthFrame);
58 // Scale
59 depthImage *= 1000.0 * scale;
60 // Compute distance
61 for (int i = 0; i < cols; i++) for (int j = 0; j < rows; j++) distanceImage.at <float> (j, i) = (float) depthFrame.get_distance(i, j);
62
63 std::stringstream colorImagePath, distanceImagePath, colorizedDepthImagePath;
64 colorImagePath << imagesFolder << "rgb/" << frameID << "_Color.png";
65 distanceImagePath << imagesFolder << "d/" << frameID << "_Distance.exr";
66 colorizedDepthImagePath << imagesFolder << "depth/" << frameID << "_Depth.png";
67 // Save
68 imageManager->saveImages( { colorImage, distanceImage, colorizedDepthImage },
69 { colorImagePath.str(), distanceImagePath.str(), colorizedDepthImagePath.str() } );
70 imageManager->releaseImages( { colorImage, depthImage, distanceImage, colorizedDepthImage } );
71 }
72}
73
74void OpenCV_Manager::showSkeletonsCV (unsigned int user_nFrame, const float skeletonThreshold) {
75 FacadeSingleton * facadeSingletonInstance = FacadeSingleton::getInstance();
76 if (facadeSingletonInstance == nullptr) CV_Error(FACADE_SINGLETON_NULLPTR_ERROR, FACADE_SINGLETON_NULLPTR_SCOPE);
77 RealSenseManager * cameraManager = facadeSingletonInstance->getCameraManager();
78 OutputManagerJSON * outputManagerJSON = (OutputManagerJSON *) facadeSingletonInstance->getOutputManager();
79 UsageManager * usageManagerInstance = facadeSingletonInstance->getUsageManager();
80 if (usageManagerInstance == nullptr) CV_Error(USAGE_MANAGER_NULLPTR_ERROR, USAGE_MANAGER_NULLPTR_SCOPE);
81 ImageManager * imageManager = facadeSingletonInstance->getImageManager();
82 char ** argv = * usageManagerInstance->get_argv(), * imagesFolder = argv[imagesFolderOffset], * outputFolder = argv[outputFolderOffset];
83 unsigned int frameID = cameraManager->getFrameID(), currentImageID;
84
85 Json::Value currentJSON;
86
87 // Do this until we don't iterate on user_nFrame frame
88 for (unsigned int nFrame = 0; nFrame < user_nFrame; nFrame++) {
89 std::stringstream inputJsonFilePath, skeletonImagePath, colorImagePath, distanceImagePath, colorizedDepthImagePath, skeletonOnlyImagePath, outputJsonFilePath;
90 currentImageID = frameID - user_nFrame + nFrame;
91
92 // Internal Approach OpenPose
93// inputJsonFilePath << outputFolder << "op/" << nFrame << "_keypoints.json";
94 // External Approach OpenPose
95 inputJsonFilePath << outputFolder << "op/" << currentImageID << "_Color_keypoints.json";
96
97 // Try to load OpenPose's output JSON file
98 if (outputManagerJSON->loadJSON(inputJsonFilePath.str(), currentJSON)) {
99 Json::Value people = outputManagerJSON->getValueAt("people", currentJSON);
100 colorImagePath << imagesFolder << "rgb/" << currentImageID << "_Color.png";
101 distanceImagePath << imagesFolder << "d/" << currentImageID << "_Distance.exr";
102 colorizedDepthImagePath << imagesFolder << "depth/" << currentImageID << "_Depth.png";
103
104 // Load images captured previously from camera
105 cv::Mat colorImage, colorizedDepthImage;
106 imageManager->loadImage(colorImagePath.str(), cv::IMREAD_COLOR, colorImage);
107 cv::Mat distanceImage = cv::Mat(colorImage.rows, colorImage.cols, CV_32FC1);
108 imageManager->loadImage(distanceImagePath.str(), cv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH, distanceImage);
109 imageManager->loadImage(colorizedDepthImagePath.str(), cv::IMREAD_COLOR, colorizedDepthImage);
110 // Note: Comment following line for better performance
111 imageManager->showImages( { colorImage, colorizedDepthImage }, { "Frame No Skeleton", "Frame Colorized Depth" } );
112 cv::Mat skeletonOnlyImage = cv::Mat::zeros(colorImage.rows, colorImage.cols, colorImage.type());
113
114 // Produce a JSON output file for people present in this frame
115 outputManagerJSON->createJSON(people, colorImage, distanceImage, skeletonOnlyImage, currentImageID, outputFolder, skeletonThreshold);
116
117 // Show images and save them. Note: Comment following line for better performance
118 imageManager->showImages( { skeletonOnlyImage, colorImage }, { "Frame Skeleton Background Cut", "Frame Skeleton" } );
119 skeletonOnlyImagePath << imagesFolder << "sk/" << currentImageID << "_sk.png";
120 skeletonImagePath << imagesFolder << "skeleton/" << currentImageID << "_Skeleton.png";
121 imageManager->saveImages( { colorImage, skeletonOnlyImage }, { skeletonImagePath.str(), skeletonOnlyImagePath.str() } );
122 imageManager->releaseImages( { colorImage, distanceImage, colorizedDepthImage, skeletonOnlyImage } );
123 }
124 }
125}
FacadeSingleton class is used as a single access point to a simplified interface.
ImageManager * getImageManager(void)
Get the ImageManager pointer.
OutputManager * getOutputManager(void)
Get the OutputManager pointer.
UsageManager * getUsageManager(void)
Get the UsageManager pointer.
RealSenseManager * getCameraManager(void)
Get the RealSenseManager pointer.
static FacadeSingleton * getInstance(void)
Get the unique class instance. This methods should be called in the following scenario: when we just ...
ImageManager class is a general-purpose class useful for operations on images such as loading,...
void showImages(const std::initializer_list< cv::Mat > &images, const std::initializer_list< std::string > &windowNames)
Shows multiple images.
void releaseImages(const std::initializer_list< cv::Mat > &images)
Releases multiple images.
void saveImages(const std::initializer_list< cv::Mat > &images, const std::initializer_list< std::string > &imagePaths)
Saves multiple images.
void loadImage(std::string imagePath, int loadType, cv::Mat &inputImage)
Loads a single image.
void getVideoFramesCV(unsigned int user_nFrame, rs2::pipeline &pipelineStream, float scale, const unsigned short int framesToSkip)
Get user_nFrame video frames from the pipeline by applying a specific scaling factor.
cv::Mat realsenseFrameToMat(const rs2::frame &singleFrame)
This method converts a frame of type rs2::frame to cv::Mat.
void showSkeletonsCV(unsigned int user_nFrame, const float skeletonThreshold)
Retrieve OpenPose's output, convert it to RealSense coordinate's space, show results and save them.
OutputManagerJSON class is a class that abstracts final JSON output-producing operations.
void createJSON(Json::Value &people, cv::Mat &colorImage, cv::Mat &distanceImage, cv::Mat &skeletonOnlyImage, unsigned int nFrame, const char *outputFolder, const float skeletonThreshold)
This methods take a reference to a JSON node that represents all the people's informations within the...
Json::Value getValueAt(std::string key, Json::Value currentJSON)
Utility method to get the value at a given key in a given JSON node.
bool loadJSON(std::string filePathJSON, Json::Value &currentJSON)
Loads a JSON file and returns it as a reference. The JSON file path on disk is given.
RealSenseManager class is a class that abstracts the behavior of an Intel RealSense Camera,...
virtual void getVideoFramesRS(unsigned int user_nFrame, rs2::pipeline &pipelineStream, rs2::depth_frame &depthFrame, rs2::frame &colorFrame, rs2::frame &colorizedDepthFrame, const unsigned short int framesToSkip)=0
Get user_nFrame video frames from the pipeline by applying a specific scaling factor....
unsigned int getFrameID(void)
Get the current frame ID value.
UsageManager class is a utility class that helps with configuration parameters.
char *** get_argv(void)
Get the argv's pointer.
static UsageManager * getInstance(void)
Get the unique class instance. This methods should be called in the following scenario: when we just ...
static const short int imagesFolderOffset
Definition: constants.hpp:64
static const short int USAGE_MANAGER_NULLPTR_ERROR
Definition: constants.hpp:35
static const short int FACADE_SINGLETON_NULLPTR_ERROR
Definition: constants.hpp:32
static const short int outputFolderOffset
Definition: constants.hpp:65
static const char * USAGE_MANAGER_NULLPTR_SCOPE
Definition: constants.hpp:36
static const char * FACADE_SINGLETON_NULLPTR_SCOPE
Definition: constants.hpp:33