??现在市面上很多人体追踪产品都有实时展示人体骨骼线的需求,绝大部分的骨骼线和骨骼点都是使用 line() 和 circle() 来解决的。这种方式简单明了,只需要知道两个骨骼点的位置就可以实现。实现的效果基本和下图类似: ????
??但是这种单一的线条缺乏视觉上的冲突感。所以希望利用同样的骨骼点信息画出更有“感觉”的骨格线。这里介绍一种实现方式,希望能给到大家一些启发。
??首先确定骨格线需要是什么形状的。这里介绍一种菱形骨格线。 ???????????????????????? ??按照原本的画线,最直观的信息就是两个骨骼点的坐标,通过坐标就可以计算向量以指定骨格线的方向,还可以计算骨骼点之间的距离,利用这两个点的坐标可以计算出两点连线上任意点的坐标。这里定义连线上距离起点 1/8 处的坐标为中间点并计算骨骼点连线的法向量,可以获得经过中间点并且与骨骼点连线垂直的直线上任意点的坐标。这样菱形的4个顶点坐标就都能计算出来了。
#pragma once
#include <memory>
#include <string>
struct else_two_point
{
double left_point_x;
double left_point_y;
double right_point_x;
double right_point_y;
};
else_two_point calculate_else_two_point(double point1_x, double point1_y, double point2_x, double point2_y) {
k4a_float2_t center_point;
double distance4p1p2 = sqrt(pow(point1_x - point2_x, 2) + pow(point1_y - point2_y, 2));
center_point.xy.x = point1_x - (point1_x - point2_x) / 8;
center_point.xy.y = point1_y - (point1_y - point2_y) / 8;
else_two_point else_two;
else_two.left_point_x = center_point.xy.x + ((distance4p1p2 / 8) * ((point2_y - point1_y) / distance4p1p2));
else_two.left_point_y = center_point.xy.y - ((distance4p1p2 / 8) * ((point2_x - point1_x) / distance4p1p2));
else_two.right_point_x = center_point.xy.x - ((distance4p1p2 / 8) * ((point2_y - point1_y) / distance4p1p2));
else_two.right_point_y = center_point.xy.y + ((distance4p1p2 / 8) * ((point2_x - point1_x) / distance4p1p2));
return else_two;
}
??利用比例关系还能让这种菱形在固定形状的同时可以随骨骼点距离和位置改变大小和方向。 ?????????????????????? 上面知道了如何获取菱形的其他两个顶点,下面介绍如何画出图形。主要是利用openCV中的fillPoly()函数。
CV_EXPORTS void fillPoly(Mat& img, const Point** pts,
const int* npts, int ncontours,
const Scalar& color, int lineType = LINE_8, int shift = 0,
Point offset = Point() );
先看代码比较枯燥,所以先看看效果吧。 ???????????????????????? 然后上完整代码,下面代码能画出一条骨骼线,在需要画线的骨骼点之间调用 draw_bone() 即可达到上图效果。
void drawPoly(Mat& src, Point** pts, int npts)
{
const Point* ppt[1] = { pts[0] };
int npt[] = { npts };
int lineType = LINE_AA;
fillPoly(src, ppt, npt, 1, Scalar(255, 255, 85), lineType);
}
else_two_point calculate_else_two_point(double point1_x, double point1_y, double point2_x, double point2_y) {
k4a_float2_t center_point;
double distance4p1p2 = sqrt(pow(point1_x - point2_x, 2) + pow(point1_y - point2_y, 2));
center_point.xy.x = point1_x - (point1_x - point2_x) / 8;
center_point.xy.y = point1_y - (point1_y - point2_y) / 8;
else_two_point else_two;
else_two.left_point_x = center_point.xy.x + ((distance4p1p2 / 8) * ((point2_y - point1_y) / distance4p1p2));
else_two.left_point_y = center_point.xy.y - ((distance4p1p2 / 8) * ((point2_x - point1_x) / distance4p1p2));
else_two.right_point_x = center_point.xy.x - ((distance4p1p2 / 8) * ((point2_y - point1_y) / distance4p1p2));
else_two.right_point_y = center_point.xy.y + ((distance4p1p2 / 8) * ((point2_x - point1_x) / distance4p1p2));
return else_two;
}
void draw_bone(Mat& src, double point1_x, double point1_y, double point2_x, double point2_y) {
Point** rook_points = new Point * [1];
rook_points[0] = new Point[4];
rook_points[0][0] = Point(point1_x, point1_y);
rook_points[0][2] = Point(point2_x, point2_y);
else_two_point else_two = calculate_else_two_point(point1_x, point1_y, point2_x, point2_y);
rook_points[0][1] = Point(else_two.left_point_x, else_two.left_point_y);
rook_points[0][3] = Point(else_two.right_point_x, else_two.right_point_y);
drawPoly(src, rook_points, 4);
imshow("菱形骨格线", src);
}
大家可以开放脑洞,尝试绘制其他图形。
|