detector.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. #include "detector.h"
  2. #include "dma_util.h"
  3. #include "rknn_api.h"
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include <sys/ioctl.h>
  10. #include <sys/mman.h>
  11. #include <linux/dma-heap.h>
  12. #include <linux/dma-buf.h>
  13. #include <math.h>
  14. #include <rga/im2d.h>
  15. #include <rga/rga.h>
  16. #define DBG(...) fprintf(stderr, __VA_ARGS__)
  17. struct Detector {
  18. rknn_context ctx;
  19. int model_w;
  20. int model_h;
  21. int model_type;
  22. rknn_input_output_num io_num;
  23. rknn_tensor_attr *input_attrs;
  24. rknn_tensor_attr *output_attrs;
  25. float conf_thresh;
  26. float nms_thresh;
  27. int rgb_fd;
  28. void *rgb_map;
  29. size_t rgb_size;
  30. int rgb_initialized;
  31. };
  32. enum {
  33. MODEL_YOLOV5 = 0,
  34. MODEL_YOLOV8 = 1,
  35. };
  36. Detector *detector_create(const char *model_path, float conf_thresh, float nms_thresh) {
  37. Detector *det = calloc(1, sizeof(Detector));
  38. if (!det) return NULL;
  39. det->conf_thresh = conf_thresh;
  40. det->nms_thresh = nms_thresh;
  41. det->ctx = 0;
  42. FILE *fp = fopen(model_path, "rb");
  43. if (!fp) { DBG("det: cannot open model %s\n", model_path); goto fail; }
  44. fseek(fp, 0, SEEK_END);
  45. long model_size = ftell(fp);
  46. rewind(fp);
  47. void *model_data = malloc(model_size);
  48. if (!model_data) { fclose(fp); goto fail; }
  49. if (fread(model_data, 1, model_size, fp) != (size_t)model_size) {
  50. fclose(fp); free(model_data); goto fail;
  51. }
  52. fclose(fp);
  53. int ret = rknn_init(&det->ctx, model_data, model_size, 0, NULL);
  54. free(model_data);
  55. if (ret < 0) { DBG("det: rknn_init failed %d\n", ret); goto fail; }
  56. ret = rknn_query(det->ctx, RKNN_QUERY_IN_OUT_NUM, &det->io_num, sizeof(det->io_num));
  57. if (ret < 0) { DBG("det: query io num failed %d\n", ret); goto fail; }
  58. DBG("det: %d inputs, %d outputs\n", det->io_num.n_input, det->io_num.n_output);
  59. det->input_attrs = calloc(det->io_num.n_input, sizeof(rknn_tensor_attr));
  60. det->output_attrs = calloc(det->io_num.n_output, sizeof(rknn_tensor_attr));
  61. if (!det->input_attrs || !det->output_attrs) goto fail;
  62. for (uint32_t i = 0; i < det->io_num.n_input; i++) {
  63. det->input_attrs[i].index = i;
  64. rknn_query(det->ctx, RKNN_QUERY_INPUT_ATTR, &det->input_attrs[i], sizeof(rknn_tensor_attr));
  65. DBG("det: input[%d] %s n_dims=%d dims=[%d,%d,%d,%d] fmt=%d type=%d\n",
  66. i, det->input_attrs[i].name, det->input_attrs[i].n_dims,
  67. det->input_attrs[i].dims[0], det->input_attrs[i].dims[1],
  68. det->input_attrs[i].dims[2], det->input_attrs[i].dims[3],
  69. det->input_attrs[i].fmt, det->input_attrs[i].type);
  70. }
  71. for (uint32_t i = 0; i < det->io_num.n_output; i++) {
  72. det->output_attrs[i].index = i;
  73. rknn_query(det->ctx, RKNN_QUERY_OUTPUT_ATTR, &det->output_attrs[i], sizeof(rknn_tensor_attr));
  74. DBG("det: output[%d] %s n_dims=%d dims=[%d,%d,%d,%d] fmt=%d type=%d\n",
  75. i, det->output_attrs[i].name, det->output_attrs[i].n_dims,
  76. det->output_attrs[i].dims[0], det->output_attrs[i].dims[1],
  77. det->output_attrs[i].dims[2], det->output_attrs[i].dims[3],
  78. det->output_attrs[i].fmt, det->output_attrs[i].type);
  79. }
  80. det->model_w = det->input_attrs[0].dims[3];
  81. det->model_h = det->input_attrs[0].dims[2];
  82. det->model_type = MODEL_YOLOV8;
  83. if (det->io_num.n_output == 3) {
  84. int all_anchor = 1;
  85. for (uint32_t i = 0; i < det->io_num.n_output; i++) {
  86. if (det->output_attrs[i].n_dims != 3 ||
  87. !(det->output_attrs[i].dims[2] == 85 ||
  88. det->output_attrs[i].dims[2] == 56)) {
  89. all_anchor = 0;
  90. break;
  91. }
  92. }
  93. if (all_anchor) det->model_type = MODEL_YOLOV5;
  94. }
  95. DBG("det: model input %dx%d type=%s\n", det->model_w, det->model_h,
  96. det->model_type == MODEL_YOLOV5 ? "yolov5" : "yolov8");
  97. det->rgb_size = det->model_w * det->model_h * 3;
  98. if (dma_heap_alloc("reserved", det->rgb_size, &det->rgb_fd) < 0) {
  99. DBG("det: failed to alloc rgb buffer\n");
  100. goto fail;
  101. }
  102. det->rgb_map = mmap(NULL, det->rgb_size, PROT_READ | PROT_WRITE, MAP_SHARED, det->rgb_fd, 0);
  103. if (det->rgb_map == MAP_FAILED) {
  104. DBG("det: mmap rgb buffer failed\n");
  105. close(det->rgb_fd); det->rgb_fd = -1;
  106. goto fail;
  107. }
  108. det->rgb_initialized = 1;
  109. DBG("det: created successfully, model %dx%d\n", det->model_w, det->model_h);
  110. return det;
  111. fail:
  112. detector_destroy(det);
  113. return NULL;
  114. }
  115. void detector_destroy(Detector *det) {
  116. if (!det) return;
  117. if (det->rgb_initialized && det->rgb_map && det->rgb_map != MAP_FAILED)
  118. munmap(det->rgb_map, det->rgb_size);
  119. if (det->rgb_fd >= 0) close(det->rgb_fd);
  120. if (det->ctx) rknn_destroy(det->ctx);
  121. free(det->input_attrs);
  122. free(det->output_attrs);
  123. free(det);
  124. }
  125. int detector_get_input_width(Detector *det) { return det->model_w; }
  126. int detector_get_input_height(Detector *det) { return det->model_h; }
  127. static int rga_scale_nv12_to_rgb(int src_fd, int src_w, int src_h,
  128. int dst_fd, int dst_w, int dst_h,
  129. void *rgb_map, size_t rgb_size) {
  130. memset(rgb_map, 0, rgb_size);
  131. float scale = fminf((float)dst_w / src_w, (float)dst_h / src_h);
  132. int content_w = (int)(src_w * scale);
  133. int content_h = (int)(src_h * scale);
  134. int pad_x = (dst_w - content_w) / 2;
  135. int pad_y = (dst_h - content_h) / 2;
  136. rga_buffer_t src = wrapbuffer_fd_t(src_fd, src_w, src_h, src_w, src_h, RK_FORMAT_YCbCr_420_SP);
  137. rga_buffer_t dst = wrapbuffer_fd_t(dst_fd, dst_w, dst_h, dst_w, dst_h, RK_FORMAT_RGB_888);
  138. im_rect src_rect = {0, 0, src_w, src_h};
  139. im_rect dst_rect = {pad_x, pad_y, content_w, content_h};
  140. rga_buffer_t pat;
  141. memset(&pat, 0, sizeof(pat));
  142. im_rect prect;
  143. memset(&prect, 0, sizeof(prect));
  144. int ret = improcess(src, dst, pat, src_rect, dst_rect, prect, IM_SYNC);
  145. if (ret != IM_STATUS_SUCCESS) {
  146. DBG("det: RGA scale failed: %d\n", ret);
  147. return -1;
  148. }
  149. return 0;
  150. }
  151. static inline float sigmoid(float x) {
  152. return 1.0f / (1.0f + expf(-x));
  153. }
  154. static int yolov5_decode(Detector *det, rknn_output *outputs,
  155. DetResult *results, int max_results) {
  156. int num = 0;
  157. int num_classes = -1;
  158. for (uint32_t o = 0; o < det->io_num.n_output; o++) {
  159. rknn_tensor_attr *oa = &det->output_attrs[o];
  160. if (oa->n_dims != 3) continue;
  161. int C = oa->dims[2];
  162. if (C != 85 && C != 56) continue;
  163. if (num_classes < 0) num_classes = C - 5;
  164. }
  165. if (num_classes <= 0) return 0;
  166. int anchors[][3][2] = {
  167. {{10,13}, {16,30}, {33,23}},
  168. {{30,61}, {62,45}, {59,119}},
  169. {{116,90}, {156,198}, {373,326}},
  170. };
  171. int strides[] = {8, 16, 32};
  172. for (uint32_t o = 0; o < det->io_num.n_output && o < 3; o++) {
  173. rknn_tensor_attr *oa = &det->output_attrs[o];
  174. if (oa->n_dims != 3) continue;
  175. int C = oa->dims[2];
  176. if (C != 85 && C != 56) continue;
  177. int num_anchors = oa->dims[1];
  178. int grid_size = num_anchors / 3;
  179. int grid_h = grid_size, grid_w = grid_size;
  180. for (int g = (int)sqrtf(grid_size); g >= 1; g--) {
  181. if (grid_size % g == 0) { grid_h = g; grid_w = grid_size / g; break; }
  182. }
  183. float *data = (float *)outputs[o].buf;
  184. int stride = strides[o];
  185. for (int a = 0; a < 3 && num < max_results; a++) {
  186. for (int gy = 0; gy < grid_h && num < max_results; gy++) {
  187. for (int gx = 0; gx < grid_w && num < max_results; gx++) {
  188. int idx = a * grid_h * grid_w + gy * grid_w + gx;
  189. float *p = data + idx * C;
  190. float obj_conf = sigmoid(p[4]);
  191. if (obj_conf < det->conf_thresh) continue;
  192. float max_cls = 0;
  193. int best_cls = 0;
  194. for (int c = 0; c < num_classes; c++) {
  195. float s = sigmoid(p[5 + c]);
  196. if (s > max_cls) { max_cls = s; best_cls = c; }
  197. }
  198. float score = obj_conf * max_cls;
  199. if (score < det->conf_thresh) continue;
  200. float cx = (sigmoid(p[0]) * 2.0f - 0.5f + gx) * stride;
  201. float cy = (sigmoid(p[1]) * 2.0f - 0.5f + gy) * stride;
  202. float bw = powf(sigmoid(p[2]) * 2.0f, 2) * anchors[o][a][0];
  203. float bh = powf(sigmoid(p[3]) * 2.0f, 2) * anchors[o][a][1];
  204. results[num].x1 = cx - bw / 2;
  205. results[num].y1 = cy - bh / 2;
  206. results[num].x2 = cx + bw / 2;
  207. results[num].y2 = cy + bh / 2;
  208. results[num].score = score;
  209. results[num].label = best_cls;
  210. num++;
  211. }
  212. }
  213. }
  214. }
  215. return num;
  216. }
  217. static int yolov8_decode(Detector *det, rknn_output *outputs,
  218. DetResult *results, int max_results) {
  219. int num = 0;
  220. for (uint32_t o = 0; o < det->io_num.n_output; o++) {
  221. rknn_tensor_attr *oa = &det->output_attrs[o];
  222. int n_dims = oa->n_dims;
  223. uint32_t *dims = oa->dims;
  224. if (n_dims != 3) continue;
  225. int C, H, W;
  226. int num_classes;
  227. if (dims[1] == 84 || dims[1] == 56) {
  228. C = dims[1]; H = 1; W = dims[2];
  229. num_classes = C - 4;
  230. } else if (dims[2] == 84 || dims[2] == 56) {
  231. C = dims[2]; H = dims[1]; W = 1;
  232. num_classes = C - 4;
  233. } else {
  234. H = dims[1]; W = dims[2];
  235. C = (n_dims > 3) ? dims[3] : 1;
  236. num_classes = C - 4;
  237. }
  238. if (num_classes <= 0) continue;
  239. float *data = (float *)outputs[o].buf;
  240. int num_candidates;
  241. int ch_stride;
  242. if (dims[1] == 84 || dims[1] == 56) {
  243. num_candidates = dims[2];
  244. ch_stride = 1;
  245. } else if (dims[2] == 84 || dims[2] == 56) {
  246. num_candidates = dims[1];
  247. ch_stride = 1;
  248. } else {
  249. num_candidates = H * W;
  250. ch_stride = num_candidates;
  251. }
  252. for (int i = 0; i < num_candidates && num < max_results; i++) {
  253. float cx, cy, bw, bh;
  254. float max_score = 0;
  255. int best_label = -1;
  256. if (dims[1] == 84 || dims[1] == 56) {
  257. cx = data[0 * num_candidates + i];
  258. cy = data[1 * num_candidates + i];
  259. bw = data[2 * num_candidates + i];
  260. bh = data[3 * num_candidates + i];
  261. for (int c = 0; c < num_classes; c++) {
  262. float s = data[(4 + c) * num_candidates + i];
  263. if (s > max_score) { max_score = s; best_label = c; }
  264. }
  265. } else if (dims[2] == 84 || dims[2] == 56) {
  266. cx = data[i * C + 0];
  267. cy = data[i * C + 1];
  268. bw = data[i * C + 2];
  269. bh = data[i * C + 3];
  270. for (int c = 0; c < num_classes; c++) {
  271. float s = data[i * C + 4 + c];
  272. if (s > max_score) { max_score = s; best_label = c; }
  273. }
  274. } else {
  275. int idx = i;
  276. cx = data[0 * ch_stride + idx];
  277. cy = data[1 * ch_stride + idx];
  278. bw = data[2 * ch_stride + idx];
  279. bh = data[3 * ch_stride + idx];
  280. for (int c = 0; c < num_classes; c++) {
  281. float s = data[(4 + c) * ch_stride + idx];
  282. if (s > max_score) { max_score = s; best_label = c; }
  283. }
  284. }
  285. if (max_score > det->conf_thresh && best_label >= 0) {
  286. float x1 = cx - bw / 2;
  287. float y1 = cy - bh / 2;
  288. float x2 = cx + bw / 2;
  289. float y2 = cy + bh / 2;
  290. results[num].x1 = x1;
  291. results[num].y1 = y1;
  292. results[num].x2 = x2;
  293. results[num].y2 = y2;
  294. results[num].score = max_score;
  295. results[num].label = best_label;
  296. num++;
  297. }
  298. }
  299. }
  300. return num;
  301. }
  302. static int cmp_score_desc(const void *a, const void *b) {
  303. float sa = ((const DetResult *)a)->score;
  304. float sb = ((const DetResult *)b)->score;
  305. if (sb > sa) return 1;
  306. if (sb < sa) return -1;
  307. return 0;
  308. }
  309. static int nms(DetResult *boxes, int num_boxes, float iou_thresh) {
  310. if (num_boxes == 0) return 0;
  311. int *keep = malloc(num_boxes * sizeof(int));
  312. int *removed = calloc(num_boxes, sizeof(int));
  313. int kept = 0;
  314. for (int i = 0; i < num_boxes; i++) {
  315. if (removed[i]) continue;
  316. keep[kept++] = i;
  317. for (int j = i + 1; j < num_boxes; j++) {
  318. if (removed[j]) continue;
  319. float x1 = fmaxf(boxes[i].x1, boxes[j].x1);
  320. float y1 = fmaxf(boxes[i].y1, boxes[j].y1);
  321. float x2 = fminf(boxes[i].x2, boxes[j].x2);
  322. float y2 = fminf(boxes[i].y2, boxes[j].y2);
  323. float inter = fmaxf(0, x2 - x1) * fmaxf(0, y2 - y1);
  324. float a1 = (boxes[i].x2 - boxes[i].x1) * (boxes[i].y2 - boxes[i].y1);
  325. float a2 = (boxes[j].x2 - boxes[j].x1) * (boxes[j].y2 - boxes[j].y1);
  326. float iou = inter / (a1 + a2 - inter + 1e-6f);
  327. if (iou > iou_thresh) removed[j] = 1;
  328. }
  329. }
  330. for (int i = 0; i < kept; i++)
  331. boxes[i] = boxes[keep[i]];
  332. free(keep);
  333. free(removed);
  334. return kept;
  335. }
  336. int detector_detect(Detector *det, int src_nv12_fd, int src_w, int src_h,
  337. DetResult *results, int *num_results) {
  338. *num_results = 0;
  339. if (!det || !det->rgb_initialized) return -1;
  340. int mw = det->model_w;
  341. int mh = det->model_h;
  342. if (rga_scale_nv12_to_rgb(src_nv12_fd, src_w, src_h,
  343. det->rgb_fd, mw, mh,
  344. det->rgb_map, det->rgb_size) < 0)
  345. return -1;
  346. /* RGA wrote the RGB buffer via DMA; invalidate CPU cache before
  347. rknn_inputs_set reads it, otherwise detection sees stale pixels. */
  348. {
  349. struct dma_buf_sync sync = { .flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_READ };
  350. ioctl(det->rgb_fd, DMA_BUF_IOCTL_SYNC, &sync);
  351. }
  352. rknn_input inputs[1];
  353. memset(inputs, 0, sizeof(inputs));
  354. inputs[0].index = 0;
  355. inputs[0].type = RKNN_TENSOR_UINT8;
  356. inputs[0].fmt = RKNN_TENSOR_NHWC;
  357. inputs[0].pass_through = 0;
  358. inputs[0].buf = det->rgb_map;
  359. inputs[0].size = det->rgb_size;
  360. int ret = rknn_inputs_set(det->ctx, 1, inputs);
  361. if (ret < 0) { DBG("det: rknn_inputs_set failed %d\n", ret); return -1; }
  362. ret = rknn_run(det->ctx, NULL);
  363. if (ret < 0) { DBG("det: rknn_run failed %d\n", ret); return -1; }
  364. rknn_output outputs[det->io_num.n_output];
  365. memset(outputs, 0, sizeof(outputs));
  366. for (uint32_t i = 0; i < det->io_num.n_output; i++) {
  367. outputs[i].want_float = 1;
  368. outputs[i].is_prealloc = 0;
  369. outputs[i].index = i;
  370. }
  371. ret = rknn_outputs_get(det->ctx, det->io_num.n_output, outputs, NULL);
  372. if (ret < 0) { DBG("det: rknn_outputs_get failed %d\n", ret); return -1; }
  373. int num_raw;
  374. if (det->model_type == MODEL_YOLOV5)
  375. num_raw = yolov5_decode(det, outputs, results, MAX_DETECTIONS);
  376. else
  377. num_raw = yolov8_decode(det, outputs, results, MAX_DETECTIONS);
  378. qsort(results, num_raw, sizeof(DetResult), cmp_score_desc);
  379. int num_kept = nms(results, num_raw, det->nms_thresh);
  380. *num_results = num_kept;
  381. rknn_outputs_release(det->ctx, det->io_num.n_output, outputs);
  382. return 0;
  383. }
  384. static const uint8_t BOX_COLORS[][3] = {
  385. {255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {255, 255, 0},
  386. {255, 0, 255}, {0, 255, 255}, {128, 255, 0}, {255, 128, 0},
  387. {0, 128, 255}, {255, 0, 128},
  388. };
  389. void detector_draw_one_result(DetResult *r, void *y_plane, int out_w, int out_h,
  390. int tile_x, int tile_y, int tile_w, int tile_h,
  391. int src_w, int src_h) {
  392. if (!r || !y_plane) return;
  393. int mw, mh;
  394. mw = (tile_w > 0) ? tile_w : out_w;
  395. mh = (tile_h > 0) ? tile_h : out_h;
  396. float scale_x = (float)mw / src_w;
  397. float scale_y = (float)mh / src_h;
  398. int dx1 = tile_x + (int)(r->x1 * scale_x);
  399. int dy1 = tile_y + (int)(r->y1 * scale_y);
  400. int dx2 = tile_x + (int)(r->x2 * scale_x);
  401. int dy2 = tile_y + (int)(r->y2 * scale_y);
  402. if (dx1 < 0) dx1 = 0;
  403. if (dy1 < 0) dy1 = 0;
  404. if (dx2 >= out_w) dx2 = out_w - 1;
  405. if (dy2 >= out_h) dy2 = out_h - 1;
  406. if (dx1 >= dx2 || dy1 >= dy2) return;
  407. uint8_t *y = (uint8_t *)y_plane;
  408. uint8_t *uv = y + out_w * out_h;
  409. int color_idx = r->label % 10;
  410. uint8_t R = BOX_COLORS[color_idx][0];
  411. uint8_t G = BOX_COLORS[color_idx][1];
  412. uint8_t B = BOX_COLORS[color_idx][2];
  413. uint8_t luma = (uint8_t)(0.299f * R + 0.587f * G + 0.114f * B);
  414. uint8_t Cb = (uint8_t)(128.0f - 0.169f * R - 0.331f * G + 0.500f * B);
  415. uint8_t Cr = (uint8_t)(128.0f + 0.500f * R - 0.419f * G - 0.081f * B);
  416. for (int x = dx1; x <= dx2; x++) {
  417. y[dy1 * out_w + x] = luma;
  418. y[dy2 * out_w + x] = luma;
  419. }
  420. for (int yc = dy1; yc <= dy2; yc++) {
  421. y[yc * out_w + dx1] = luma;
  422. y[yc * out_w + dx2] = luma;
  423. }
  424. int uv_x1 = dx1 & ~1;
  425. int uv_x2 = (dx2 + 1) & ~1;
  426. int uv_y1 = dy1 & ~1;
  427. int uv_y2 = (dy2 + 1) & ~1;
  428. for (int ux = uv_x1; ux < uv_x2; ux += 2) {
  429. uv[uv_y1 * out_w + ux] = Cb;
  430. uv[uv_y1 * out_w + ux + 1] = Cr;
  431. uv[uv_y2 * out_w + ux] = Cb;
  432. uv[uv_y2 * out_w + ux + 1] = Cr;
  433. }
  434. for (int uy = uv_y1; uy <= uv_y2; uy += 2) {
  435. uv[uy * out_w + uv_x1] = Cb;
  436. uv[uy * out_w + uv_x1 + 1] = Cr;
  437. if (uv_x2 < out_w) {
  438. uv[uy * out_w + uv_x2] = Cb;
  439. uv[uy * out_w + uv_x2 + 1] = Cr;
  440. }
  441. }
  442. }