main.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #include <opencv2/opencv.hpp>
  2. #include <iostream>
  3. #include <string>
  4. #include <vector>
  5. #include <opencv2/dnn.hpp>
  6. // #include "./clip.cpp/clip.h"
  7. // #include "./clip.cpp/examples/common-clip.h"
  8. using cv::Mat;
  9. using std::cout;
  10. using std::endl;
  11. using std::string;
  12. using std::vector;
  13. //using namespace Ort;
  14. int factor = 4; // downsample factor
  15. double short_term_rate = 0.01; // short-term rate
  16. int short_term_history = 200; // short-term history
  17. double long_term_rate = 0.0005; // long-term rate
  18. int long_term_history = 5000; // long-term history
  19. float iou_threshold = 0.6; // iou threshold
  20. string model_path = "models/ggml-model-f16.gguf"; // clip model path
  21. string algo = "MOG2";
  22. // 定义proposal的结构体
  23. struct proposal{
  24. int x, y, w, h;
  25. int life;
  26. int status;
  27. };
  28. float compute_iou(proposal p1, proposal p2) {
  29. float x1 = p1.x;
  30. float y1 = p1.y;
  31. float w1 = p1.w;
  32. float h1 = p1.h;
  33. float x2 = p2.x;
  34. float y2 = p2.y;
  35. float w2 = p2.w;
  36. float h2 = p2.h;
  37. float area1 = w1 * h1;
  38. float area2 = w2 * h2;
  39. float x_overlap = std::max(0.0f, std::min(x1 + w1, x2 + w2) - std::max(x1, x2));
  40. float y_overlap = std::max(0.0f, std::min(y1 + h1, y2 + h2) - std::max(y1, y2));
  41. float overlap_area = x_overlap * y_overlap;
  42. float iou = overlap_area / (area1 + area2 - overlap_area);
  43. return iou;
  44. }
  45. int proposal_count = 0;
  46. Mat solve_proposal(Mat& frame, proposal& p) {
  47. // 截取proposal区域
  48. cv::Rect rect(p.x, p.y, p.w, p.h);
  49. Mat roi = frame(rect);
  50. // 计算proposal的特征
  51. // 保存proposal的图片及序号
  52. string img_path = "./proposals/proposal_" + std::to_string(proposal_count) + ".jpg";
  53. //string img_path = "./proposals/proposal.jpg";
  54. proposal_count++;
  55. cv::imwrite(img_path, roi);
  56. printf("detect proposal: x=%d, y=%d, w=%d, h=%d\n", p.x, p.y, p.w, p.h);
  57. // 计算proposal的特征
  58. return roi;
  59. }
  60. int main() {
  61. // Read video
  62. cv::VideoCapture cap("/home/cl/onnx_run/abandoned_od/vedios/vedio-g.mp4");
  63. if (!cap.isOpened()) {
  64. cout << "Error opening video stream or file" << endl;
  65. return -1;
  66. }
  67. printf("Frame size: %d x %d\n", cap.get(cv::CAP_PROP_FRAME_WIDTH), cap.get(cv::CAP_PROP_FRAME_HEIGHT));
  68. printf("FPS: %f\n", cap.get(cv::CAP_PROP_FPS));
  69. int fps = cap.get(cv::CAP_PROP_FPS);
  70. int frame_delay = 1000 / fps; // delay between frames in ms
  71. // Resize video
  72. int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
  73. int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
  74. int new_width = width / factor;
  75. int new_height = height / factor;
  76. // Initialize background subtractor
  77. cv::Ptr<cv::BackgroundSubtractor> pShortBG, pLongBG;
  78. if (algo == "MOG2") {
  79. pLongBG= cv::createBackgroundSubtractorMOG2(long_term_history, 16.0, false);
  80. pShortBG = cv::createBackgroundSubtractorMOG2(short_term_history, 16.0, false);
  81. } else {
  82. cout << "Invalid algorithm name" << endl;
  83. return -1;
  84. }
  85. // Initialize variables
  86. // proposal List
  87. vector<proposal> proposals;
  88. // loop through video
  89. while(1){
  90. // 遍历frame
  91. // Read frame
  92. Mat origin_frame, frame, ltMask, stMask, subMask;
  93. cap >> frame;
  94. if (frame.empty()) {
  95. break;
  96. }
  97. origin_frame = frame.clone();
  98. // get index of frame
  99. int index = cap.get(cv::CAP_PROP_POS_FRAMES);
  100. //printf("Frame %d\n", index);
  101. // save frame
  102. cv::imwrite("./frames/frame.jpg", frame);
  103. // Resize frame
  104. cv::resize(frame, frame, cv::Size(new_width, new_height));
  105. // Guassian blur
  106. cv::GaussianBlur(frame, frame, cv::Size(5, 5), 0);
  107. // Convert to grayscale
  108. cv::cvtColor(frame, frame, cv::COLOR_BGR2GRAY);
  109. cv::imwrite("./frames/gray.jpg", frame);
  110. // Update background model
  111. pLongBG->apply(frame, ltMask, long_term_rate);
  112. cv::imwrite("./masks/ltMask.jpg", ltMask);
  113. pShortBG->apply(frame, stMask, short_term_rate);
  114. cv::imwrite("./masks/stMask.jpg", stMask);
  115. // ltMask 减去 stMask
  116. cv::subtract(ltMask, stMask, subMask);
  117. cv::imwrite("./masks/subMask.jpg", subMask);
  118. // Denoise
  119. // erode and dilate
  120. Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5));
  121. cv::erode(subMask, subMask, kernel, cv::Point(-1,-1), 2, 1, 1);
  122. kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
  123. cv::dilate(subMask, subMask, cv::Mat(), cv::Point(-1,-1), 2, 1, 1);
  124. // gussian blur
  125. cv::GaussianBlur(subMask, subMask, cv::Size(49, 49), 7);
  126. cv::imwrite("./masks/subMask_denoised.jpg", subMask);
  127. // fgMask_denoised[fgMask_denoised <= 5] = 0
  128. subMask.setTo(0, subMask <= 5);
  129. // save subMask
  130. // 按顺序保存图片
  131. cv::imwrite("./masks/mask.jpg", subMask);
  132. //cv::imwrite("./masks/subMask.jpg", subMask);
  133. // find contours
  134. vector<vector<cv::Point>> contours;
  135. cv::findContours(subMask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
  136. double area_ts = 10000 / (factor * factor); // threshold for contour area
  137. double perimeter_ts = 400 / (factor); // threshold for contour perimeter
  138. //printf("Contours: %d\n", contours.size());
  139. // 遍历所有轮廓
  140. for (int i = 0; i < contours.size(); i++) {
  141. // 计算轮廓的面积和周长
  142. double area = cv::contourArea(contours[i]);
  143. double perimeter = cv::arcLength(contours[i], true);
  144. // 过滤掉太小的轮廓
  145. if (area > area_ts && perimeter > perimeter_ts) {
  146. cv::drawContours(frame, contours, i, cv::Scalar(0, 0, 255), 2);
  147. // 获取矩形的x,y,w,h
  148. cv::Rect rect = cv::boundingRect(contours[i]);
  149. //printf("x=%d, y=%d, w=%d, h=%d\n", rect.x, rect.y, rect.width, rect.height);
  150. // 画矩形
  151. cv::rectangle(frame, rect, cv::Scalar(0, 255, 0), 2);
  152. proposal p;
  153. p.x = rect.x * factor;
  154. p.y = rect.y * factor;
  155. p.w = rect.width * factor;
  156. p.h = rect.height * factor;
  157. //printf("x=%d, y=%d, w=%d, h=%d\n", p.x, p.y, p.w, p.h);
  158. p.life = 10;
  159. p.status = 0;
  160. for (int j = 0; j < proposals.size(); j++) {
  161. // compute iou
  162. float iou = 0;
  163. iou = compute_iou(p, proposals[j]);
  164. if (iou > iou_threshold) {
  165. p.status = -1; // 重叠,不添加
  166. proposals[j].life++; // 延长生命周期
  167. if (proposals[j].status == 2){
  168. continue; // 已经进行过检测
  169. }
  170. proposals[j].status = 1; // 未检测,有效proposal
  171. }
  172. }
  173. if (p.status == 0){
  174. // 新增proposal
  175. proposals.push_back(p);
  176. //printf("New proposal: x=%d, y=%d, w=%d, h=%d\n", p.x, p.y, p.w, p.h);
  177. }
  178. }
  179. }
  180. // 遍历proposal,更新状态
  181. for (int i = 0; i < proposals.size(); i++) {
  182. if (proposals[i].status == 1) {
  183. if (proposals[i].life > 60) {
  184. // 生存超过50帧
  185. Mat roi = solve_proposal(origin_frame, proposals[i]);
  186. // 对roi进行clip visual feature extraction
  187. // 保存结果
  188. proposals[i].status = 2; // 已检测
  189. }
  190. }else {
  191. proposals[i].life--; // 生命周期减一
  192. if (proposals[i].life == 0) {
  193. // 生命周期结束,删除proposal
  194. proposals.erase(proposals.begin() + i);
  195. i--;
  196. }
  197. }
  198. }
  199. // Display frame
  200. //cv::imshow("frame", frame);
  201. //cv::imshow("subMask", subMask);
  202. // Wait for key press
  203. // int key = cv::waitKey(frame_delay-10);
  204. // if (key == 27) {
  205. // break;
  206. // }
  207. // Release video
  208. //cv::destroyAllWindows();
  209. }
  210. cap.release();
  211. //clip_free(ctx);
  212. return 0;
  213. }