Commit 06ac1811 authored by Jakob Bornecrantz's avatar Jakob Bornecrantz

HACK

parent 06574388
......@@ -19,6 +19,9 @@ set(OS_SOURCE_FILES
set(TRACKING_SOURCE_FILES
tracking/t_calibration.cpp
tracking/t_calibration.h
tracking/t_convert.cpp
tracking/t_debug_hsv_viewer.cpp
tracking/t_hsv_filter.c
)
set(UTIL_SOURCE_FILES
......
......@@ -13,6 +13,7 @@
#include "tracking/t_calibration.h"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
DEBUG_GET_ONCE_BOOL_OPTION(show_channels, "CALI_SHOW_CHANNELS", false)
......@@ -30,15 +31,32 @@ public:
struct
{
struct xrt_fs_sink *sink = {};
cv::Mat rgb = {};
} debug;
cv::Mat data[3] = {};
struct
{
cv::Mat rgb = {};
struct xrt_fs_sink *sink = {};
} gui;
cv::Mat rpb;
char text[512];
};
/*!
* Holds `cv::Mat`s used during frame processing when processing a yuyv frame.
*/
struct t_frame_yuyv
{
public:
//! Full frame size, each block is split across two cols.
cv::Mat data_full = {};
//! Half horizontal width covering a complete block of two pixels.
cv::Mat data_half = {};
};
/*
*
......@@ -46,6 +64,20 @@ public:
*
*/
static struct t_convert_table yuv_to_rgb_table = {};
static struct t_convert_table yuv_to_hsv_table = {};
static struct t_convert_table hsv_to_rgb_table = {};
static struct t_convert_table yuv_to_rpb_table = {};
static void
setup_tables(void)
{
t_convert_make_y8u8v8_to_r8g8b8(&yuv_to_rgb_table);
t_convert_make_y8u8v8_to_h8s8v8(&yuv_to_hsv_table);
t_convert_make_h8s8v8_to_r8g8b8(&hsv_to_rgb_table);
t_hsv_build_table(&yuv_to_rpb_table);
}
static void
send_rgb_frame(struct xrt_fs_sink *xsink, cv::Mat &rgb)
{
......@@ -63,29 +95,32 @@ send_rgb_frame(struct xrt_fs_sink *xsink, cv::Mat &rgb)
}
static void
send_debug_rgb_frame(class t_calibration &c)
send_gui_rgb_frame(class t_calibration &c)
{
send_rgb_frame(c.debug.sink, c.debug.rgb);
send_rgb_frame(c.gui.sink, c.gui.rgb);
}
static void
ensure_data_is_allocated(class t_calibration &c, struct xrt_fs_frame *xf)
{
int w = (int)xf->width;
int half_w = w / 2;
int h = (int)xf->height;
if (c.data[0].cols == w || c.data[0].rows == h) {
if (c.rpb.cols == w || c.rpb.rows == h) {
return;
}
#if 0
c.data[0] = cv::Mat(h, w, CV_8UC1, cv::Scalar(0, 0, 0));
c.data[1] = cv::Mat(h, half_w, CV_8UC1, cv::Scalar(0, 0, 0));
c.data[2] = cv::Mat(h, half_w, CV_8UC1, cv::Scalar(0, 0, 0));
#endif
c.rpb = cv::Mat(h, w, CV_8UC3, cv::Scalar(0, 0, 0));
}
static void
ensure_rgb_is_allocated(class t_calibration &c, int rows, int cols)
ensure_debug_rgb_is_allocated(class t_calibration &c, int rows, int cols)
{
if (c.debug.rgb.cols == cols && c.debug.rgb.rows == rows) {
return;
......@@ -94,6 +129,16 @@ ensure_rgb_is_allocated(class t_calibration &c, int rows, int cols)
c.debug.rgb = cv::Mat(rows, cols, CV_8UC3, cv::Scalar(0, 0, 0));
}
static void
ensure_gui_rgb_is_allocated(class t_calibration &c, int rows, int cols)
{
if (c.gui.rgb.cols == cols && c.gui.rgb.rows == rows) {
return;
}
c.gui.rgb = cv::Mat(rows, cols, CV_8UC3, cv::Scalar(0, 0, 0));
}
static void
print_txt(cv::Mat &rgb, const char *text, double fontScale)
{
......@@ -109,62 +154,78 @@ print_txt(cv::Mat &rgb, const char *text, double fontScale)
}
static void
make_debug_str(class t_calibration &c)
make_gui_str(class t_calibration &c)
{
auto &rgb = c.debug.rgb;
int cols = 800;
int rows = 100;
ensure_rgb_is_allocated(c, rows, cols);
ensure_gui_rgb_is_allocated(c, rows, cols);
cv::rectangle(c.debug.rgb, cv::Point2f(0, 0), cv::Point2f(cols, rows),
cv::Scalar(0, 0, 0), -1, 0);
print_txt(rgb, c.text, 1.0);
send_rgb_frame(c.debug.sink, c.debug.rgb);
send_rgb_frame(c.gui.sink, c.gui.rgb);
}
static void
make_debug_channels(class t_calibration &c, cv::Mat &data)
XRT_MAYBE_UNUSED static void
make_debug_channels(class t_calibration &c)
{
#if 0
cv::Mat temp1 = {};
cv::Mat temp2 = {};
hconcat(c.data[1], c.data[2], temp1);
vconcat(c.data[0], temp1, temp1);
cv::cvtColor(temp1, temp1, CV_GRAY2BGR);
cv::cvtColor(data, temp2, CV_YUV2RGB_YUYV);
//hconcat(c.data[1], c.data[2], temp1);
//cv::cvtColor(temp1, temp1, CV_GRAY2BGR);
//vconcat(temp1, temp2, c.debug.rgb);
#endif
ensure_gui_rgb_is_allocated(c, c.debug.rgb.rows + c.rpb.rows,
c.debug.rgb.cols + c.rpb.cols);
ensure_rgb_is_allocated(c, temp1.rows + temp2.rows, temp1.cols);
vconcat(c.rpb, c.debug.rgb, c.gui.rgb);
vconcat(temp1, temp2, c.debug.rgb);
send_gui_rgb_frame(c);
}
#if 0
XRT_MAYBE_UNUSED static void
make_debug_grey_scale(class t_calibration &c, cv::Mat &data)
{
auto &rgb = c.debug.rgb;
ensure_rgb_is_allocated(c, data.rows, data.cols);
cv::cvtColor(data, rgb, CV_GRAY2BGR);
print_txt(rgb, "GRAY", 1.5);
send_debug_rgb_frame(c);
}
#endif
static void
make_calibration_frame(class t_calibration &c, cv::Mat &data)
make_calibration_frame(class t_calibration &c)
{
auto &rgb = c.debug.rgb;
auto &data = c.debug.rgb;
cv::Mat *rgb = NULL;
if (data.rows == 0 || data.cols == 0) {
ensure_rgb_is_allocated(c, 480, 640);
cv::rectangle(c.debug.rgb, cv::Point2f(0, 0),
ensure_gui_rgb_is_allocated(c, 480, 640);
cv::rectangle(c.gui.rgb, cv::Point2f(0, 0),
cv::Point2f(c.debug.rgb.cols, c.debug.rgb.rows),
cv::Scalar(0, 0, 0), -1, 0);
} else {
ensure_rgb_is_allocated(c, data.rows, data.cols);
cv::cvtColor(data, rgb, CV_YUV2RGB_YUYV);
rgb = &c.gui.rgb;
} else {
rgb = &data;
}
/*
* Draw text
*/
print_txt(rgb, "CALIBRATION MODE", 1.5);
print_txt(*rgb, "CALIBRATION MODE", 1.5);
send_rgb_frame(c.debug.sink, c.debug.rgb);
send_rgb_frame(c.gui.sink, *rgb);
}
......@@ -174,25 +235,20 @@ make_calibration_frame(class t_calibration &c, cv::Mat &data)
*
*/
static void
process_frame(class t_calibration &c, struct xrt_fs_frame *xf)
static inline void
process_sample(uint8_t *dst, uint8_t y, uint8_t cb, uint8_t cr)
{
if (xf->format != XRT_FORMAT_YUV422) {
snprintf(c.text, sizeof(c.text), "ERROR: Bad format '%s'",
u_format_str(xf->format));
make_debug_str(c);
return;
}
if (xf->stereo_format != XRT_FS_STEREO_SBS) {
snprintf(c.text, sizeof(c.text),
"ERROR: Not side by side stereo!");
make_debug_str(c);
return;
}
ensure_data_is_allocated(c, xf);
uint8_t *src = yuv_to_rpb_table.v[y][cb][cr];
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
}
static void
process_frame_yuyv(class t_calibration &c,
struct xrt_fs_frame *xf,
bool make_rgb)
{
/*
* Cleverly extract the different channels.
* Cr/Cb are extracted at half width.
......@@ -201,25 +257,62 @@ process_frame(class t_calibration &c, struct xrt_fs_frame *xf)
int half_w = w / 2;
int h = (int)xf->height;
// Half size covering a complete block of two pixels.
cv::Mat tmp_half(h, half_w, CV_8UC4, xf->data, xf->stride);
// Full size covering half a block of two pixels.
cv::Mat tmp_full(h, w, CV_8UC2, xf->data, xf->stride);
class t_frame_yuyv f = {};
f.data_half = cv::Mat(h, half_w, CV_8UC4, xf->data, xf->stride);
f.data_full = cv::Mat(h, w, CV_8UC2, xf->data, xf->stride);
for (uint32_t y = 0; y < xf->height; y++) {
uint8_t *src = (uint8_t *)xf->data + y * xf->stride;
auto dst = c.rpb.ptr<uint8_t>(y);
for (uint32_t x = 0; x < xf->width; x += 2) {
uint8_t y1 = src[0];
uint8_t cb = src[1];
uint8_t y2 = src[2];
uint8_t cr = src[3];
src += 4;
process_sample(dst, y1, cb, cr);
dst += 3;
process_sample(dst, y2, cb, cr);
dst += 3;
}
}
if (make_rgb) {
ensure_debug_rgb_is_allocated(c, f.data_full.rows,
f.data_full.cols);
cv::cvtColor(f.data_full, c.debug.rgb, CV_YUV2RGB_YUYV);
}
}
cv::Mat chans_4[4] = {};
cv::Mat chans_2[2] = {};
static void
process_frame(class t_calibration &c, struct xrt_fs_frame *xf)
{
#if 0
if (xf->stereo_format != XRT_FS_STEREO_SBS) {
snprintf(c.text, sizeof(c.text),
"ERROR: Not side by side stereo!");
make_debug_str(c);
return;
}
#endif
chans_2[0] = c.data[0];
chans_4[1] = c.data[1];
chans_4[3] = c.data[2];
ensure_data_is_allocated(c, xf);
cv::split(tmp_half, chans_4);
cv::split(tmp_full, chans_2);
switch (xf->format) {
case XRT_FORMAT_YUV422: process_frame_yuyv(c, xf, true); break;
default:
snprintf(c.text, sizeof(c.text), "ERROR: Bad format '%s'",
u_format_str(xf->format));
make_gui_str(c);
return;
}
if (debug_get_bool_option_show_channels()) {
make_debug_channels(c, tmp_full);
make_debug_channels(c);
} else {
make_calibration_frame(c, tmp_full);
make_calibration_frame(c);
}
}
......@@ -249,16 +342,21 @@ extern "C" int
t_calibration_create(struct xrt_fs_sink *debug_out,
struct xrt_fs_sink **out_sink)
{
if (true) {
return t_debug_create_hsv_viewer(debug_out, out_sink);
}
auto c = new t_calibration();
c->debug.sink = debug_out;
setup_tables();
c->gui.sink = debug_out;
c->base.push_frame = t_calibration_frame;
*out_sink = &c->base;
cv::Mat empty = {};
make_calibration_frame(*c, empty);
make_calibration_frame(*c);
return 0;
}
......@@ -16,10 +16,52 @@ extern "C" {
#endif
struct t_convert_table
{
uint8_t v[256][256][256][3];
};
int
t_calibration_create(struct xrt_fs_sink *debug_out,
struct xrt_fs_sink **out_sink);
int
t_debug_create_hsv_viewer(struct xrt_fs_sink *debug_out,
struct xrt_fs_sink **out_sink);
void
t_hsv_build_table(struct t_convert_table *t);
void
t_convert_fill_table(struct t_convert_table *t);
void
t_convert_make_y8u8v8_to_r8g8b8(struct t_convert_table *t);
void
t_convert_make_y8u8v8_to_h8s8v8(struct t_convert_table *t);
void
t_convert_make_h8s8v8_to_r8g8b8(struct t_convert_table *t);
void
t_convert_in_place_y8u8v8_to_r8g8b8(uint32_t width,
uint32_t height,
size_t stride,
void *data_ptr);
void
t_convert_in_place_y8u8v8_to_h8s8v8(uint32_t width,
uint32_t height,
size_t stride,
void *data_ptr);
void
t_convert_in_place_h8s8v8_to_r8g8b8(uint32_t width,
uint32_t height,
size_t stride,
void *data_ptr);
#ifdef __cplusplus
}
......
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Code to build conversion tables and convert images.
* @author Jakob Bornecrantz <jakob@collabora.com>
*/
#include "tracking/t_calibration.h"
#include <opencv2/opencv.hpp>
/*
*
* 'Exported' functions.
*
*/
extern "C" void
t_convert_fill_table(struct t_convert_table *t)
{
for (int y = 0; y < 256; y++) {
for (int u = 0; u < 256; u++) {
uint8_t *dst = &t->v[y][u][0][0];
for (int v = 0; v < 256; v++) {
dst[0] = y;
dst[1] = u;
dst[2] = v;
dst += 3;
}
}
}
}
extern "C" void
t_convert_make_y8u8v8_to_r8g8b8(struct t_convert_table *t)
{
size_t size = 256 * 256 * 256;
t_convert_fill_table(t);
t_convert_in_place_y8u8v8_to_r8g8b8(size, 1, 0, t);
}
extern "C" void
t_convert_make_y8u8v8_to_h8s8v8(struct t_convert_table *t)
{
size_t size = 256 * 256 * 256;
t_convert_fill_table(t);
t_convert_in_place_y8u8v8_to_h8s8v8(size, 1, 0, &t->v);
}
extern "C" void
t_convert_make_h8s8v8_to_r8g8b8(struct t_convert_table *t)
{
size_t size = 256 * 256 * 256;
t_convert_fill_table(t);
t_convert_in_place_h8s8v8_to_r8g8b8(size, 1, 0, &t->v);
}
extern "C" void
t_convert_in_place_y8u8v8_to_r8g8b8(uint32_t width,
uint32_t height,
size_t stride,
void *data_ptr)
{
cv::Mat data(height, width, CV_8UC3, data_ptr, stride);
cv::cvtColor(data, data, CV_YUV2RGB);
}
extern "C" void
t_convert_in_place_y8u8v8_to_h8s8v8(uint32_t width,
uint32_t height,
size_t stride,
void *data_ptr)
{
cv::Mat data(height, width, CV_8UC3, data_ptr, stride);
cv::Mat temp(height, width, CV_32FC3);
cv::cvtColor(data, temp, CV_YUV2RGB);
cv::cvtColor(temp, data, CV_RGB2HSV);
}
extern "C" void
t_convert_in_place_h8s8v8_to_r8g8b8(uint32_t width,
uint32_t height,
size_t stride,
void *data_ptr)
{
cv::Mat data(height, width, CV_8UC3, data_ptr, stride);
cv::cvtColor(data, data, CV_YUV2RGB);
}
This diff is collapsed.
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief HSV debug viewer code.
* @author Jakob Bornecrantz <jakob@collabora.com>
*/
#include "util/u_misc.h"
#include "util/u_debug.h"
#include "util/u_format.h"
#include "tracking/t_calibration.h"
#include <opencv2/opencv.hpp>
#define min(a, b) (a < b ? a : b)
#define HSV_WIN "HSV Filter Tester"
class DebugHSV
{
public:
struct xrt_fs_sink base = {};
struct xrt_fs_sink *gui;
cv::Mat rpb;
};
static int lum_value = 0;
static struct t_convert_table yuv_to_rgb_table = {};
static struct t_convert_table yuv_to_rpb_table = {};
static void
setup_tables(void)
{
t_convert_make_y8u8v8_to_r8g8b8(&yuv_to_rgb_table);
t_hsv_build_table(&yuv_to_rpb_table);
}
static void
process_frame(DebugHSV &d, struct xrt_fs_frame *xf)
{
uint32_t width = 256;
uint32_t height = 256;
cv::Mat frame_hsv(height * 2, width * 2, CV_8UC3);
for (uint32_t y = 0; y < height; y++) {
auto hsv1 = frame_hsv.ptr<uint8_t>(y);
auto hsv2 = frame_hsv.ptr<uint8_t>(y + 256);
auto hsv3 = frame_hsv.ptr<uint8_t>(y) + 256 * 3;
auto hsv4 = frame_hsv.ptr<uint8_t>(y + 256) + 256 * 3;
for (uint32_t x = 0; x < width; x++) {
int n_y = lum_value;
int n_u = y;
int n_v = x;
#if 0
int c_y = min(n_y + 4, 255) & 0xf8;
int c_u = min(n_u + 4, 255) & 0xf8;
int c_v = min(n_v + 4, 255) & 0xf8;
#else
int c_y = (n_y & 0xf0) + 7;
int c_u = (n_u & 0xf8) + 3;
int c_v = (n_v & 0xf8) + 3;
#endif
uint8_t *rgb = yuv_to_rgb_table.v[n_y][n_u][n_v];
uint8_t *n = yuv_to_rpb_table.v[n_y][n_u][n_v];
uint8_t *c = yuv_to_rpb_table.v[c_y][c_u][c_v];
hsv1[0] = n[0] > 120 ? 0xff : 0x00;
hsv1[1] = n[1] > 120 ? 0xff : 0x00;
hsv1[2] = n[2] > 120 ? 0xff : 0x00;
hsv2[0] = c[0] > 120 ? 0xff : 0x00;
hsv2[1] = c[1] > 120 ? 0xff : 0x00;
hsv2[2] = c[2] > 120 ? 0xff : 0x00;
hsv3[0] = hsv1[0] != hsv2[0] ? 0xff : 0x00;
hsv3[1] = hsv1[1] != hsv2[1] ? 0xff : 0x00;
hsv3[2] = hsv1[2] != hsv2[2] ? 0xff : 0x00;
hsv4[0] = rgb[0];
hsv4[1] = rgb[1];
hsv4[2] = rgb[2];
hsv1 += 3;
hsv2 += 3;
hsv3 += 3;
hsv4 += 3;
}
}
cv::imshow(HSV_WIN, frame_hsv);
}
extern "C" void
t_debug_hsv_frame(struct xrt_fs_sink *xsink, struct xrt_fs_frame *xf)
{
auto &d = *(struct DebugHSV *)xsink;
process_frame(d, xf);
}
extern "C" int
t_debug_create_hsv_viewer(struct xrt_fs_sink *debug_out,
struct xrt_fs_sink **out_sink)
{
auto d = new DebugHSV();
cv::namedWindow(HSV_WIN);
cv::createTrackbar("Luma", HSV_WIN, &lum_value, 255, NULL);
cv::startWindowThread();
setup_tables();
d->gui = debug_out;
d->base.push_frame = t_debug_hsv_frame;
*out_sink = &d->base;
return 0;
}
// Copyright 2019, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief A simple HSV filter.
* @author Jakob Bornecrantz <jakob@collabora.com>
*/
#include "util/u_misc.h"
#include "util/u_debug.h"
#include "util/u_format.h"
#include "tracking/t_calibration.h"
#define MOD_180(v) ((uint32_t)(v) % 180)
#define R_RANGE (30)
#define R_MAX (5)
#define R_MIN (R_MAX - R_RANGE)
#define P_RANGE (20)
#define P_MAX (155)
#define P_MIN (P_MAX - P_RANGE)
#define B_RANGE (30)
#define B_MAX (125)
#define B_MIN (B_MAX - B_RANGE)
static inline bool
check_range(uint32_t min, uint32_t range, uint32_t h)
{
return MOD_180(h + (360 - min)) < range;
}
void
t_hsv_build_table(struct t_convert_table *t)
{
struct t_convert_table *temp = U_TYPED_CALLOC(struct t_convert_table);
t_convert_make_y8u8v8_to_h8s8v8(temp);
uint8_t *dst = &t->v[0][0][0][0];
for (int y = 0; y < 256; y++) {
for (int u = 0; u < 256; u++) {
for (int v = 0; v < 256; v++) {
uint32_t h = temp->v[y][u][v][0];
uint8_t s = temp->v[y][u][v][1];
uint8_t v2 = temp->v[y][u][v][2];
if (s < 160) {
dst += 3;
continue;
}
if (check_range(R_MIN, R_RANGE, h)) {
dst[0] = v2;
} else {
dst[0] = 0;
}
if (check_range(P_MIN, P_RANGE, h)) {
dst[1] = v2;
} else {
dst[1] = 0;
}
if (check_range(B_MIN, B_RANGE, h)) {
dst[2] = v2;
} else {
dst[2] = 0;
}