The open source OpenXR runtime
at prediction-2 249 lines 5.8 kB view raw
1// Copyright 2019, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief HSV Picker Debugging code. 6 * @author Pete Black <pblack@collabora.com> 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @ingroup aux_tracking 9 */ 10 11#include "util/u_misc.h" 12#include "util/u_debug.h" 13#include "util/u_format.h" 14 15#include "tracking/t_tracking.h" 16 17#include <opencv2/opencv.hpp> 18 19 20/* 21 * 22 * Defines and structs 23 * 24 */ 25 26#define PICK_WIN "HSV Picker Debugger" 27 28#define max(a, b) (a > b ? a : b) 29#define min(a, b) (a < b ? a : b) 30 31/*! 32 * An @ref xrt_frame_sink that can be used to select HSV thresholds 33 * interactively. 34 * @implements xrt_frame_sink 35 * @implements xrt_frame_node 36 */ 37class DebugHSVPicker 38{ 39public: 40 struct xrt_frame_sink base = {}; 41 struct xrt_frame_node node = {}; 42 43 struct 44 { 45 cv::Mat hsv = {}; 46 cv::Mat threshold = {}; 47 } debug; 48 49 struct xrt_frame_sink *passthrough; 50 51 struct t_convert_table yuv_to_hsv; 52}; 53 54const int max_value_H = 360 / 2; 55const int max_value = 256; 56static int low_H = 0, low_S = 0, low_V = 0; 57static int high_H = max_value_H, high_S = max_value, high_V = max_value; 58 59 60/* 61 * 62 * Debug functions. 63 * 64 */ 65 66static void 67ensure_debug_is_allocated(class DebugHSVPicker &d, int rows, int cols) 68{ 69 if (d.debug.hsv.cols == cols && d.debug.hsv.rows == rows) { 70 return; 71 } 72 73 d.debug.threshold = cv::Mat(rows, cols, CV_8UC1); 74 d.debug.hsv = cv::Mat(rows, cols, CV_8UC3); 75} 76 77static void 78process_frame_yuv(class DebugHSVPicker &d, struct xrt_frame *xf) 79{ 80 for (uint32_t y = 0; y < xf->height; y++) { 81 uint8_t *src = (uint8_t *)xf->data + y * xf->stride; 82 auto *hsv = d.debug.hsv.ptr<uint8_t>(y); 83 for (uint32_t x = 0; x < xf->width; x++) { 84 uint8_t y = src[0]; 85 uint8_t cb = src[1]; 86 uint8_t cr = src[2]; 87 88 uint8_t *hsv1 = d.yuv_to_hsv.v[y][cb][cr]; 89 90 hsv[0] = hsv1[0]; 91 hsv[1] = hsv1[1]; 92 hsv[2] = hsv1[2]; 93 94 hsv += 3; 95 src += 3; 96 } 97 } 98 99 cv::inRange(d.debug.hsv, cv::Scalar(low_H, low_S, low_V), cv::Scalar(high_H, high_S, high_V), 100 d.debug.threshold); 101 cv::imshow(PICK_WIN, d.debug.threshold); 102} 103 104static void 105process_frame_yuyv(class DebugHSVPicker &d, struct xrt_frame *xf) 106{ 107 for (uint32_t y = 0; y < xf->height; y++) { 108 uint8_t *src = (uint8_t *)xf->data + y * xf->stride; 109 auto *hsv = d.debug.hsv.ptr<uint8_t>(y); 110 for (uint32_t x = 0; x < xf->width; x += 2) { 111 uint8_t y1 = src[0]; 112 uint8_t cb = src[1]; 113 uint8_t y2 = src[2]; 114 uint8_t cr = src[3]; 115 116 uint8_t *hsv1 = d.yuv_to_hsv.v[y1][cb][cr]; 117 uint8_t *hsv2 = d.yuv_to_hsv.v[y2][cb][cr]; 118 119 hsv[0] = hsv1[0]; 120 hsv[1] = hsv1[1]; 121 hsv[2] = hsv1[2]; 122 hsv[3] = hsv2[0]; 123 hsv[4] = hsv2[1]; 124 hsv[5] = hsv2[2]; 125 126 hsv += 6; 127 src += 4; 128 } 129 } 130 131 cv::inRange(d.debug.hsv, cv::Scalar(low_H, low_S, low_V), cv::Scalar(high_H, high_S, high_V), 132 d.debug.threshold); 133 cv::imshow(PICK_WIN, d.debug.threshold); 134} 135 136static void 137process_frame(class DebugHSVPicker &d, struct xrt_frame *xf) 138{ 139 ensure_debug_is_allocated(d, xf->height, xf->width); 140 141 switch (xf->format) { 142 case XRT_FORMAT_YUV888: process_frame_yuv(d, xf); break; 143 case XRT_FORMAT_YUYV422: process_frame_yuyv(d, xf); break; 144 default: U_LOG_E("Bad format '%s'", u_format_str(xf->format)); break; 145 } 146} 147 148static void 149on_low_H_thresh_trackbar(int /*unused*/, void * /*unused*/) 150{ 151 low_H = min(high_H - 1, low_H); 152 cv::setTrackbarPos("Low H", PICK_WIN, low_H); 153} 154 155static void 156on_high_H_thresh_trackbar(int /*unused*/, void * /*unused*/) 157{ 158 high_H = max(high_H, low_H + 1); 159 cv::setTrackbarPos("High H", PICK_WIN, high_H); 160} 161 162static void 163on_low_S_thresh_trackbar(int /*unused*/, void * /*unused*/) 164{ 165 low_S = min(high_S - 1, low_S); 166 cv::setTrackbarPos("Low S", PICK_WIN, low_S); 167} 168 169static void 170on_high_S_thresh_trackbar(int /*unused*/, void * /*unused*/) 171{ 172 high_S = max(high_S, low_S + 1); 173 cv::setTrackbarPos("High S", PICK_WIN, high_S); 174} 175 176static void 177on_low_V_thresh_trackbar(int /*unused*/, void * /*unused*/) 178{ 179 low_V = min(high_V - 1, low_V); 180 cv::setTrackbarPos("Low V", PICK_WIN, low_V); 181} 182 183static void 184on_high_V_thresh_trackbar(int /*unused*/, void * /*unused*/) 185{ 186 high_V = max(high_V, low_V + 1); 187 cv::setTrackbarPos("High V", PICK_WIN, high_V); 188} 189 190 191/* 192 * 193 * Exported functions. 194 * 195 */ 196 197extern "C" void 198t_debug_hsv_picker_frame(struct xrt_frame_sink *xsink, struct xrt_frame *xf) 199{ 200 auto &d = *(class DebugHSVPicker *)xsink; 201 202 process_frame(d, xf); 203 204 d.passthrough->push_frame(d.passthrough, xf); 205} 206 207extern "C" void 208t_debug_hsv_picker_break_apart(struct xrt_frame_node *node) 209{} 210 211extern "C" void 212t_debug_hsv_picker_destroy(struct xrt_frame_node *node) 213{ 214 auto *d = container_of(node, DebugHSVPicker, node); 215 delete d; 216} 217 218extern "C" int 219t_debug_hsv_picker_create(struct xrt_frame_context *xfctx, 220 struct xrt_frame_sink *passthrough, 221 struct xrt_frame_sink **out_sink) 222{ 223 auto &d = *(new DebugHSVPicker()); 224 225 cv::namedWindow(PICK_WIN); 226 227 d.base.push_frame = t_debug_hsv_picker_frame; 228 d.node.break_apart = t_debug_hsv_picker_break_apart; 229 d.node.destroy = t_debug_hsv_picker_destroy; 230 d.passthrough = passthrough; 231 232 // Trackbars to set thresholds for HSV values 233 cv::createTrackbar("Low H", PICK_WIN, &low_H, max_value_H, on_low_H_thresh_trackbar); 234 cv::createTrackbar("High H", PICK_WIN, &high_H, max_value_H, on_high_H_thresh_trackbar); 235 cv::createTrackbar("Low S", PICK_WIN, &low_S, max_value, on_low_S_thresh_trackbar); 236 cv::createTrackbar("High S", PICK_WIN, &high_S, max_value, on_high_S_thresh_trackbar); 237 cv::createTrackbar("Low V", PICK_WIN, &low_V, max_value, on_low_V_thresh_trackbar); 238 cv::createTrackbar("High V", PICK_WIN, &high_V, max_value, on_high_V_thresh_trackbar); 239 240 cv::startWindowThread(); 241 242 t_convert_make_y8u8v8_to_h8s8v8(&d.yuv_to_hsv); 243 244 xrt_frame_context_add(xfctx, &d.node); 245 246 *out_sink = &d.base; 247 248 return 0; 249}