drawNode.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #include "common/utils.hpp"
  2. #include "nodes/base/base.hpp"
  3. #include "nodes/draw/drawNode.hpp"
  4. #include "nodes/draw/position.hpp"
  5. #include <opencv2/opencv.hpp>
  6. #include <chrono>
  7. #include <tuple>
  8. namespace GNode
  9. {
  10. const std::vector<std::pair<int, int>> coco_pairs = {
  11. {0, 1}, {0, 2}, {0, 11}, {0, 12}, {1, 3}, {2, 4},
  12. {5, 6}, {5, 7}, {7, 9}, {6, 8}, {8, 10},
  13. {11, 12}, {5, 11}, {6, 12},
  14. {11, 13}, {13, 15}, {12, 14}, {14, 16}
  15. };
  16. static std::tuple<int, int, int> getFontSize(const std::string& text)
  17. {
  18. int baseline = 0;
  19. cv::Size textSize = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 1.0, 2, &baseline);
  20. // std::cout << textSize << std::endl;
  21. return std::make_tuple(textSize.width, textSize.height, baseline);
  22. }
  23. static void overlay_mask(
  24. cv::Mat& image, const cv::Mat& smallMask,
  25. int roiX, int roiY,
  26. const cv::Scalar& color, double alpha)
  27. {
  28. if (image.empty() || smallMask.empty() ||
  29. image.type() != CV_8UC3 || smallMask.type() != CV_8UC1) {
  30. return;
  31. }
  32. alpha = std::max(0.0, std::min(1.0, alpha));
  33. cv::Rect roiRect(roiX, roiY, smallMask.cols, smallMask.rows);
  34. cv::Rect imageRect(0, 0, image.cols, image.rows);
  35. cv::Rect intersectionRect = roiRect & imageRect; // 使用 & 操作符计算交集
  36. if (intersectionRect.width <= 0 || intersectionRect.height <= 0) {
  37. return;
  38. }
  39. cv::Mat originalROI = image(intersectionRect); // ROI 指向 image 的数据
  40. int maskStartX = intersectionRect.x - roiX;
  41. int maskStartY = intersectionRect.y - roiY;
  42. cv::Rect maskIntersectionRect(maskStartX, maskStartY, intersectionRect.width, intersectionRect.height);
  43. cv::Mat smallMaskROI = smallMask(maskIntersectionRect);
  44. cv::Mat colorPatchROI(intersectionRect.size(), image.type(), color);
  45. cv::Mat tempColoredROI = originalROI.clone(); // 需要一个临时区域进行覆盖
  46. colorPatchROI.copyTo(tempColoredROI, smallMaskROI);
  47. cv::addWeighted(originalROI, 1.0 - alpha, tempColoredROI, alpha, 0.0, originalROI);
  48. }
  49. static std::tuple<uint8_t, uint8_t, uint8_t> hsv2bgr(float h, float s, float v)
  50. {
  51. const int h_i = static_cast<int>(h * 6);
  52. const float f = h * 6 - h_i;
  53. const float p = v * (1 - s);
  54. const float q = v * (1 - f * s);
  55. const float t = v * (1 - (1 - f) * s);
  56. float r, g, b;
  57. switch (h_i) {
  58. case 0:
  59. r = v, g = t, b = p;
  60. break;
  61. case 1:
  62. r = q, g = v, b = p;
  63. break;
  64. case 2:
  65. r = p, g = v, b = t;
  66. break;
  67. case 3:
  68. r = p, g = q, b = v;
  69. break;
  70. case 4:
  71. r = t, g = p, b = v;
  72. break;
  73. case 5:
  74. r = v, g = p, b = q;
  75. break;
  76. default:
  77. r = 1, g = 1, b = 1;
  78. break;
  79. }
  80. return std::make_tuple(static_cast<uint8_t>(b * 255), static_cast<uint8_t>(g * 255),
  81. static_cast<uint8_t>(r * 255));
  82. }
  83. static std::tuple<uint8_t, uint8_t, uint8_t> random_color(int id)
  84. {
  85. float h_plane = ((((unsigned int)id << 2) ^ 0x937151) % 100) / 100.0f;
  86. float s_plane = ((((unsigned int)id << 3) ^ 0x315793) % 100) / 100.0f;
  87. return hsv2bgr(h_plane, s_plane, 1);
  88. }
  89. static float box_iou(const data::Box& box1, const data::Box& box2)
  90. {
  91. float inter_x1 = std::max(box1.left, box2.left);
  92. float inter_y1 = std::max(box1.top, box2.top);
  93. float inter_x2 = std::min(box1.right, box2.right);
  94. float inter_y2 = std::min(box1.bottom, box2.bottom);
  95. float inter_area = std::max(0.0f, inter_x2 - inter_x1) * std::max(0.0f, inter_y2 - inter_y1);
  96. float box1_area = (box1.right - box1.left) * (box1.bottom - box1.top);
  97. float box2_area = (box2.right - box2.left) * (box2.bottom - box2.top);
  98. return inter_area / (box1_area + box2_area - inter_area + 1e-6f); // Avoid division by zero
  99. }
  100. void DrawNode::handle_data(std::shared_ptr<meta::BaseData>& meta_data)
  101. {
  102. auto frame_data = std::dynamic_pointer_cast<meta::FrameData>(meta_data);
  103. bool show_track = true;
  104. cv::Mat image = frame_data->image.clone();
  105. int image_width = image.cols;
  106. int image_height = image.rows;
  107. PositionManager<float> pm(getFontSize);
  108. for (auto& box : frame_data->boxes)
  109. {
  110. if (show_track)
  111. {
  112. float max_iou = 0.0f;
  113. for (const auto& track_box : frame_data->track_boxes)
  114. {
  115. float iou = box_iou(box, track_box);
  116. if (iou > max_iou && iou > 0.7f)
  117. {
  118. max_iou = iou;
  119. box.class_id = track_box.class_id;
  120. }
  121. }
  122. }
  123. uint8_t b, g, r;
  124. std::tie(b, g, r) = random_color(box.class_id);
  125. cv::rectangle(image, cv::Point(box.left, box.top), cv::Point(box.right, box.bottom), cv::Scalar(b, g, r), 2);
  126. std::tuple<int, int, int, int> pbox = std::make_tuple(box.left, box.top, box.right, box.bottom);
  127. int x, y;
  128. std::string text;
  129. if (box.class_id >= 0)
  130. {
  131. text = str_format("%s %.2f id=%d", box.label.c_str(), box.score, box.class_id);
  132. }
  133. else
  134. {
  135. text = str_format("%s %.2f", box.label.c_str(), box.score);
  136. }
  137. std::tie(x, y) = pm.selectOptimalPosition(pbox, image_width, image_height, text);
  138. cv::putText(image, text, cv::Point(x, y), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2);
  139. if (!box.seg_mask.empty())
  140. {
  141. overlay_mask(image, box.seg_mask, box.left, box.top, cv::Scalar(b, g, r), 0.6);
  142. }
  143. if (!box.keypoints.empty())
  144. {
  145. for (const auto& point : box.keypoints)
  146. {
  147. cv::circle(image, cv::Point(point.x, point.y), 5, cv::Scalar(b, g, r), -1);
  148. }
  149. for (const auto& pair : coco_pairs)
  150. {
  151. int startIdx = pair.first;
  152. int endIdx = pair.second;
  153. if (startIdx < box.keypoints.size() && endIdx < box.keypoints.size())
  154. {
  155. int x1 = (int)box.keypoints[startIdx].x;
  156. int y1 = (int)box.keypoints[startIdx].y;
  157. int x2 = (int)box.keypoints[endIdx].x;
  158. int y2 = (int)box.keypoints[endIdx].y;
  159. cv::line(image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(b, g, r), 2);
  160. }
  161. }
  162. }
  163. }
  164. frame_data->draw_image = image;
  165. }
  166. }