Galaxis Codebase  1.0.0
Team Galaxis software stack for the Carolo Cup 2023 - ROS2 based software
QRCodeDetectionNode.cpp
Go to the documentation of this file.
2 
3 #include <iostream>
4 #include <string>
5 #include <cmath>
6 #include <thread>
7 #include <cstdio>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <experimental/filesystem>
11 #include <memory>
12 #include <chrono>
13 
14 #include <opencv2/core.hpp>
15 #include <opencv2/imgcodecs.hpp>
16 #include <opencv2/highgui.hpp>
17 #include <opencv2/objdetect.hpp>
18 #include <opencv2/imgproc.hpp>
19 
20 #include <cv_bridge/cv_bridge.h>
21 #include <std_msgs/msg/header.hpp>
22 #include <sensor_msgs/image_encodings.hpp>
23 
25 #include "utils/logger.hpp"
26 
27 
28 using namespace galaxis::utils;
29 
30 //ros-eloquent-rosbag2-storage-default-plugins
31 namespace fs = std::experimental::filesystem;
32 
34  this->m_detector = cv::QRCodeDetector();
35 
36  galaxis::ros::create_publisher(this, m_qrCodeDetectionPubSPtr);
37 
38  auto qosReliable = galaxis::ros::get_qos_profile(galaxis::ros::QoS_Profile_t::QOS_RELIABLE);
39  // rclcpp::QoS qosBestEffort = galaxis::ros::get_qos_profile(galaxis::ros::QoS_Profile_t::QOS_BEST_EFFORT);
40  m_imgSubscriber = this->create_subscription<sensor_msgs::msg::Image>(
41  galaxis::ros::TOPIC_CAMERA_RAW,
42  qosReliable,
43  std::bind(&QRCodeDetectionNode::onImgCallback, this, std::placeholders::_1));
44  // m_debugImgPublisher = this->create_publisher<sensor_msgs::msg::Image>("/galaxis/qrcodedetection/debug/img", qosBestEffort);
45 
46  // std::string test_path = "./nodes/QRCodeDetectorNode/test_video.mp4";
47  // std::thread(&QRCodeDetectionNode::test_detection_loop, this, test_path).detach();
48 }
49 
50 void QRCodeDetectionNode::onImgCallback(const sensor_msgs::msg::Image::SharedPtr p_ImgMsg){
51  cv::Mat boundingBox;
52  cv::Mat image = cv_bridge::toCvShare(p_ImgMsg, "bgr8")->image;
53 
54  bool foundQR = this->m_detector.detect(image, boundingBox);
55 
56  // check if bounding box is a clean rectangle
57  foundQR = foundQR && this->checkBoundingBox(boundingBox, image);
58  if(foundQR){
59  this->drawBox(image, boundingBox);
60  }
61 
62  // Publish results
63  // this->publishImage(image); // enable for debug
64  if(foundQR && m_foundQRCount <= m_foundQRCountForSendingMessage * 2){
66  }
67  else if(!foundQR && m_foundQRCount >= 0) {
69  }
70 
72  log("Sending message: QR Code found.");
73 
74  m_qrCodeFoundSometime = true;
75  this->publishQR(p_ImgMsg->header.stamp, true);
76  }
77  else {
78  log("Sending message: QR Code NOT found.");
79  this->publishQR(p_ImgMsg->header.stamp, false);
80 
82  log("Node stopped.");
83  std::this_thread::sleep_for(std::chrono::milliseconds(250));
84  std::exit(0);
85  }
86  }
87 }
88 
90  cv::VideoCapture cap = cv::VideoCapture(path);
91  if(!cap.isOpened()){
92  log_error("Error openning video stream or file");
93  }
94  cv::Mat frame, boundingBox;
95  int frameCounter = 0;
96 
97  while(cap.isOpened()){
98  bool ret = cap.read(frame);
99  frameCounter++;
100 
101  // reset video to beginning if end has been reached
102  if(frameCounter == cap.get(cv::CAP_PROP_FRAME_COUNT)){
103  frameCounter = 0;
104  cap.set(cv::CAP_PROP_POS_FRAMES, 0);
105  }
106  if(!ret){continue;}
107 
108  bool foundQR = m_detector.detect(frame, boundingBox);
109  // check if bounding box is a clean rectangle
110  foundQR = foundQR && this->checkBoundingBox(boundingBox, frame);
111 
112  if(foundQR){
113  // draw bounding box on frame
114  drawBox(frame, boundingBox);
115  cv::imshow("detection", frame);
116  cv::waitKey(1);
117  // this->publishImage(frame);
118  }
119  // publish detection
120  this->publishQR(this->get_clock()->now(), foundQR);
121  }
122  cap.release();
123 }
124 
125 void QRCodeDetectionNode::publishQR(rclcpp::Time stamp, bool detected){
126  std::unique_ptr<QRCodeDetectType> qrMsgUPtr = std::make_unique<QRCodeDetectType>();
127  qrMsgUPtr->header.stamp = stamp;
128  qrMsgUPtr->detected = detected;
129 
130  m_qrCodeDetectionPubSPtr->publish(std::move(qrMsgUPtr));
131 }
132 
133 // void QRCodeDetectionNode::publishImage(cv::Mat &image){
134 // std::unique_ptr<sensor_msgs::msg::Image> msgImgUPtr = std::make_unique<sensor_msgs::msg::Image>();
135 // std_msgs::msg::Header header;
136 // header.frame_id = "qr";
137 // header.stamp = this->get_clock()->now();
138 // cv_bridge::CvImage imgBridge = cv_bridge::CvImage(header, sensor_msgs::image_encodings::RGB8, image);
139 // imgBridge.toImageMsg(*msgImgUPtr);
140 // m_debugImgPublisher->publish(std::move(msgImgUPtr));
141 // }
142 
143 bool QRCodeDetectionNode::checkBoundingBox(cv::Mat &bbox, cv::Mat &image){
144  // allowed deviation
145  float percentage = 0.3;
146  cv::Point2i topLeft = cv::Point2i(bbox.at<float>(0,0),bbox.at<float>(0,1));
147  cv::Point2i topRight = cv::Point2i(bbox.at<float>(1,0),bbox.at<float>(1,1));
148  cv::Point2i botRight = cv::Point2i(bbox.at<float>(2,0),bbox.at<float>(2,1));
149  cv::Point2i botLeft = cv::Point2i(bbox.at<float>(3,0),bbox.at<float>(3,1));
150  // std::cout << "Difference: " << std::abs(topLeft.y - topRight.y) << " Target: " << percentage * image.rows << std::endl;
151  // std::cout << "Difference: " << std::abs(topRight.x - botRight.x) << " Target: " << percentage * image.cols << std::endl;
152  // std::cout << "Difference: " << std::abs(botRight.y - botLeft.y) << " Target: " << percentage * image.rows << std::endl;
153  // std::cout << "Difference: " << std::abs(botLeft.x - topLeft.x) << " Target: " << percentage * image.cols << std::endl;
154 
155  return std::abs(topLeft.y - topRight.y) < percentage * image.rows&&
156  std::abs(topRight.x - botRight.x) < percentage * image.cols&&
157  std::abs(botRight.y - botLeft.y) < percentage * image.rows&&
158  std::abs(botLeft.x - topLeft.x) < percentage * image.cols;
159 }
160 
161 void QRCodeDetectionNode::drawBox(cv::Mat &image, cv::Mat &bbox){
162  int n = bbox.rows;
163  for(int i = 0 ; i < n ; i++){
164  cv::line(
165  image,
166  cv::Point2i(bbox.at<float>(i,0),bbox.at<float>(i,1)),
167  cv::Point2i(bbox.at<float>((i+1) % n,0), bbox.at<float>((i+1) % n,1)), cv::Scalar(255,0,0),
168  3
169  );
170  }
171 }
QRCodeDetectionNode::m_qrCodeFoundSometime
bool m_qrCodeFoundSometime
Definition: QRCodeDetectionNode.hpp:34
galaxis::utils::log_error
void log_error(const Args &... args)
Definition: logger.hpp:50
node_ros_pubsub_wrapper.hpp
QRCodeDetectionNode::m_foundQRCountForSendingMessage
int m_foundQRCountForSendingMessage
Definition: QRCodeDetectionNode.hpp:32
QRCodeDetectionNode::m_qrCodeDetectionPubSPtr
rclcpp::Publisher< QRCodeDetectType >::SharedPtr m_qrCodeDetectionPubSPtr
Definition: QRCodeDetectionNode.hpp:27
QRCodeDetectionNode::QRCodeDetectionNode
QRCodeDetectionNode()
Definition: QRCodeDetectionNode.cpp:33
QRCodeDetectionNode::m_detector
cv::QRCodeDetector m_detector
Definition: QRCodeDetectionNode.hpp:20
QRCodeDetectionNode::m_imgSubscriber
rclcpp::Subscription< sensor_msgs::msg::Image >::SharedPtr m_imgSubscriber
Definition: QRCodeDetectionNode.hpp:29
QRCodeDetectionNode::checkBoundingBox
bool checkBoundingBox(cv::Mat &bbox, cv::Mat &image)
Definition: QRCodeDetectionNode.cpp:143
QRCodeDetectionNode::test_detection_loop
void test_detection_loop(std::string path)
Definition: QRCodeDetectionNode.cpp:89
QRCodeDetectionNode::m_foundQRCount
int m_foundQRCount
Definition: QRCodeDetectionNode.hpp:31
QRCodeDetectionNode::onImgCallback
void onImgCallback(const sensor_msgs::msg::Image::SharedPtr p_ImgMsg)
Definition: QRCodeDetectionNode.cpp:50
QRCodeDetectionNode.hpp
GalaxisNode
Definition: GalaxisNode.hpp:21
logger.hpp
galaxis::utils
Definition: clock.hpp:5
QRCodeDetectionNode::drawBox
void drawBox(cv::Mat &im, cv::Mat &bbox)
Definition: QRCodeDetectionNode.cpp:161
galaxis::utils::log
void log(const Args &... args)
Definition: logger.hpp:33
QRCodeDetectionNode::publishQR
void publishQR(rclcpp::Time stamp, bool detected)
Definition: QRCodeDetectionNode.cpp:125