mirror of
https://github.com/bububa/openvision.git
synced 2025-09-26 17:51:13 +08:00
feat(pose): add openpose
This commit is contained in:
@@ -33,7 +33,10 @@ cmake .. # optional -DNCNN_VULKAN=OFF -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COM
|
||||
- tracker (for face IOU calculation bettween frames)
|
||||
- hopenet (for head pose detection) [Google Drive](https://drive.google.com/drive/folders/1zLam-8s9ZMPDUxUEtNU2F9yFTDRM5fk-?usp=sharing)
|
||||
- pose
|
||||
- detector (for pose estimation)
|
||||
- detector (for pose detection/estimation)
|
||||
- ultralight [Google Drive](https://drive.google.com/drive/folders/15b-I5HDyGe2WLb-TO85SJYmnYONvGOKh?usp=sharing)
|
||||
- openpose [Google Drive](https://drive.google.com/drive/folders/1Q2mq7dOE-eHsvu4BYpBaWVLkU5roKsm5?usp=sharing)
|
||||
- estimator (for pose estimation)
|
||||
- ultralight [Google Drive](https://drive.google.com/drive/folders/15b-I5HDyGe2WLb-TO85SJYmnYONvGOKh?usp=sharing)
|
||||
- hand
|
||||
- detector (for hand detect)
|
||||
|
@@ -49,6 +49,7 @@ func (o ObjectInfo) ToCObjectInfo(w float64, h float64) *C.ObjectInfo {
|
||||
ret.rect.y = C.int(o.Rect.Y * h)
|
||||
ret.rect.width = C.int(o.Rect.Width * w)
|
||||
ret.rect.height = C.int(o.Rect.Height * h)
|
||||
return ret
|
||||
if len(o.Keypoints) > 0 {
|
||||
ret.pts = (*C.KeypointVector)(C.malloc(C.sizeof_KeypointVector))
|
||||
ret.pts.length = C.int(len(o.Keypoints))
|
||||
@@ -57,6 +58,7 @@ func (o ObjectInfo) ToCObjectInfo(w float64, h float64) *C.ObjectInfo {
|
||||
pt := C.Keypoint{
|
||||
C.Point2f{C.float(p.Point.X * w), C.float(p.Point.Y * h)},
|
||||
C.float(p.Score),
|
||||
C.int(0),
|
||||
}
|
||||
C.KeypointVectorSetValue(ret.pts, C.int(idx), &pt)
|
||||
}
|
||||
|
@@ -27,13 +27,20 @@ func main() {
|
||||
cpuCores := common.GetBigCPUCount()
|
||||
common.SetOMPThreads(cpuCores)
|
||||
log.Printf("CPU big cores:%d\n", cpuCores)
|
||||
d := ultralightDetector(modelPath)
|
||||
defer d.Destroy()
|
||||
common.SetEstimatorThreads(d, cpuCores)
|
||||
m := ultralightEstimator(modelPath)
|
||||
defer m.Destroy()
|
||||
common.SetEstimatorThreads(d, cpuCores)
|
||||
detect(d, m, imgPath, "ultralight-pose3.jpg")
|
||||
for did, d := range []detecter.Detecter{
|
||||
ultralightDetector(modelPath),
|
||||
openposeDetector(modelPath),
|
||||
} {
|
||||
defer d.Destroy()
|
||||
common.SetEstimatorThreads(d, cpuCores)
|
||||
for mid, m := range []estimator.Estimator{
|
||||
ultralightEstimator(modelPath),
|
||||
} {
|
||||
defer m.Destroy()
|
||||
common.SetEstimatorThreads(d, cpuCores)
|
||||
detect(d, m, imgPath, "ultralight-pose.jpg", did, mid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ultralightDetector(modelPath string) detecter.Detecter {
|
||||
@@ -45,6 +52,15 @@ func ultralightDetector(modelPath string) detecter.Detecter {
|
||||
return d
|
||||
}
|
||||
|
||||
func openposeDetector(modelPath string) detecter.Detecter {
|
||||
modelPath = filepath.Join(modelPath, "openpose")
|
||||
d := detecter.NewOpenPose()
|
||||
if err := d.LoadModel(modelPath); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func ultralightEstimator(modelPath string) estimator.Estimator {
|
||||
modelPath = filepath.Join(modelPath, "ultralight-pose/pose")
|
||||
d := estimator.NewUltralight()
|
||||
@@ -54,7 +70,7 @@ func ultralightEstimator(modelPath string) estimator.Estimator {
|
||||
return d
|
||||
}
|
||||
|
||||
func detect(d detecter.Detecter, m estimator.Estimator, imgPath string, filename string) {
|
||||
func detect(d detecter.Detecter, m estimator.Estimator, imgPath string, filename string, did int, mid int) {
|
||||
inPath := filepath.Join(imgPath, filename)
|
||||
imgSrc, err := loadImage(inPath)
|
||||
if err != nil {
|
||||
@@ -65,20 +81,25 @@ func detect(d detecter.Detecter, m estimator.Estimator, imgPath string, filename
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
for idx, roi := range rois {
|
||||
keypoints, err := m.ExtractKeypoints(img, roi.Rect)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
if !d.HasKeypoints() {
|
||||
for idx, roi := range rois {
|
||||
keypoints, err := m.ExtractKeypoints(img, roi.Rect)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
rois[idx].Keypoints = keypoints
|
||||
}
|
||||
rois[idx].Keypoints = keypoints
|
||||
}
|
||||
var useOpenPose bool
|
||||
if did == 1 {
|
||||
useOpenPose = true
|
||||
}
|
||||
|
||||
outPath := filepath.Join(imgPath, "./results", fmt.Sprintf("pose-%s", filename))
|
||||
outPath := filepath.Join(imgPath, "./results", fmt.Sprintf("pose-%d-%d-%s", did, mid, filename))
|
||||
|
||||
drawer := posedrawer.New()
|
||||
|
||||
out := drawer.Draw(img, rois, true)
|
||||
out := drawer.Draw(img, rois, true, useOpenPose)
|
||||
|
||||
if err := saveImage(out, outPath); err != nil {
|
||||
log.Fatalln(err)
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
// Detecter represents deteter interface
|
||||
type Detecter interface {
|
||||
common.Estimator
|
||||
HasKeypoints() bool
|
||||
Detect(img *common.Image) ([]common.ObjectInfo, error)
|
||||
}
|
||||
|
||||
|
@@ -1,2 +0,0 @@
|
||||
// Package detecter pose detecter
|
||||
package detecter
|
51
go/pose/detecter/openpose.go
Normal file
51
go/pose/detecter/openpose.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package detecter
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "openvision/common/common.h"
|
||||
#include "openvision/pose/detecter.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/bububa/openvision/go/common"
|
||||
)
|
||||
|
||||
// OpenPose represents utralight detecter
|
||||
type OpenPose struct {
|
||||
d C.IPoseDetecter
|
||||
}
|
||||
|
||||
// NewOpenPose returns a new OpenPose
|
||||
func NewOpenPose() *OpenPose {
|
||||
return &OpenPose{
|
||||
d: C.new_openpose(),
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy free detecter
|
||||
func (d *OpenPose) Destroy() {
|
||||
common.DestroyEstimator(d)
|
||||
}
|
||||
|
||||
// Pointer implement Estimator interface
|
||||
func (d *OpenPose) Pointer() unsafe.Pointer {
|
||||
return unsafe.Pointer(d.d)
|
||||
}
|
||||
|
||||
// HasKeypoints implement Detecter interface
|
||||
func (d *OpenPose) HasKeypoints() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// LoadModel load model for detecter
|
||||
func (d *OpenPose) LoadModel(modelPath string) error {
|
||||
return common.EstimatorLoadModel(d, modelPath)
|
||||
}
|
||||
|
||||
// Detect implement Detecter interface
|
||||
func (d *OpenPose) Detect(img *common.Image) ([]common.ObjectInfo, error) {
|
||||
return Detect(d, img)
|
||||
}
|
@@ -34,6 +34,11 @@ func (d *Ultralight) Pointer() unsafe.Pointer {
|
||||
return unsafe.Pointer(d.d)
|
||||
}
|
||||
|
||||
// HasKeypoints implement Detecter interface
|
||||
func (d *Ultralight) HasKeypoints() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// LoadModel load model for detecter
|
||||
func (d *Ultralight) LoadModel(modelPath string) error {
|
||||
return common.EstimatorLoadModel(d, modelPath)
|
||||
|
@@ -64,12 +64,21 @@ var (
|
||||
CocoPair = [16][2]CocoPart{
|
||||
{0, 1}, {1, 3}, {0, 2}, {2, 4}, {5, 6}, {5, 7}, {7, 9}, {6, 8}, {8, 10}, {5, 11}, {6, 12}, {11, 12}, {11, 13}, {12, 14}, {13, 15}, {14, 16},
|
||||
}
|
||||
|
||||
// OpenPosePair represents joints pair for openpose
|
||||
OpenPosePair = [17][2]int{
|
||||
{1, 2}, {1, 5}, {2, 3}, {3, 4}, {5, 6},
|
||||
{6, 7}, {1, 8}, {8, 9}, {9, 10}, {1, 11},
|
||||
{11, 12}, {12, 13}, {1, 0}, {0, 14}, {14, 16},
|
||||
{0, 15}, {15, 17},
|
||||
}
|
||||
|
||||
// CocoColors represents color for coco parts
|
||||
CocoColors = [17]string{
|
||||
CocoColors = [19]string{
|
||||
"#ff0000", "#ff5500", "#ffaa00", "#ffff00",
|
||||
"#aaff00", "#55ff00", "#00ff00", "#00ff55", "#00ffaa",
|
||||
"#00ffff", "#00aaff", "#0055ff",
|
||||
"#0000ff", "#aa00ff", "#ff00ff",
|
||||
"#ff00aa", "#ff0055",
|
||||
"#ff00aa", "#ff0055", "#ff55aa", "#aa0055",
|
||||
}
|
||||
)
|
||||
|
@@ -35,7 +35,7 @@ func New(options ...Option) *Drawer {
|
||||
}
|
||||
|
||||
// Draw draw rois
|
||||
func (d *Drawer) Draw(img image.Image, rois []common.ObjectInfo, drawBorder bool) image.Image {
|
||||
func (d *Drawer) Draw(img image.Image, rois []common.ObjectInfo, drawBorder bool, openPose bool) image.Image {
|
||||
imgW := float64(img.Bounds().Dx())
|
||||
imgH := float64(img.Bounds().Dy())
|
||||
out := image.NewRGBA(img.Bounds())
|
||||
@@ -53,13 +53,24 @@ func (d *Drawer) Draw(img image.Image, rois []common.ObjectInfo, drawBorder bool
|
||||
borderColor := d.BorderColor
|
||||
common.DrawRectangle(gc, rect, borderColor, "", d.BorderStrokeWidth)
|
||||
}
|
||||
|
||||
if len(roi.Keypoints) == 0 {
|
||||
return out
|
||||
}
|
||||
// draw joins
|
||||
for idx, pair := range CocoPair {
|
||||
pairs := CocoPair[:]
|
||||
if openPose {
|
||||
pairs = OpenPosePair[:]
|
||||
}
|
||||
for idx, pair := range pairs {
|
||||
p0 := roi.Keypoints[pair[0]]
|
||||
p1 := roi.Keypoints[pair[1]]
|
||||
if p0.Score < 0.2 || p1.Score < 0.2 {
|
||||
continue
|
||||
}
|
||||
if p0.Point.X < 0 || p0.Point.Y < 0 || p1.Point.Y < 0 || p1.Point.X < 0 {
|
||||
continue
|
||||
}
|
||||
cocoColor := CocoColors[idx]
|
||||
gc.SetLineWidth(d.BorderStrokeWidth)
|
||||
gc.SetStrokeColor(common.ColorFromHex(cocoColor))
|
||||
@@ -75,6 +86,9 @@ func (d *Drawer) Draw(img image.Image, rois []common.ObjectInfo, drawBorder bool
|
||||
if pt.Score < 0.2 {
|
||||
continue
|
||||
}
|
||||
if pt.Point.X < 0 || pt.Point.Y < 0 {
|
||||
continue
|
||||
}
|
||||
cocoColor := CocoColors[idx]
|
||||
common.DrawCircle(gc, common.Pt(pt.Point.X*imgW, pt.Point.Y*imgH), d.KeypointRadius, cocoColor, "", d.KeypointStrokeWidth)
|
||||
}
|
||||
|
@@ -66,6 +66,7 @@ target_include_directories(openvision
|
||||
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/detecter>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/estimator>
|
||||
)
|
||||
|
||||
#install(TARGETS openvision EXPORT openvision ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH})
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <iostream>
|
||||
#include "cpu.h"
|
||||
|
||||
#ifdef OV_VULKAN
|
||||
@@ -145,7 +146,6 @@ void Estimator::set_num_threads(int n) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int RatioAnchors(const Rect & anchor,
|
||||
const std::vector<float>& ratios,
|
||||
std::vector<Rect>* anchors, int threads_num) {
|
||||
|
@@ -8,6 +8,7 @@ extern "C" {
|
||||
|
||||
#ifdef __cplusplus
|
||||
typedef ov::Size Size;
|
||||
typedef ov::Size2f Size2f;
|
||||
typedef ov::Point Point;
|
||||
typedef ov::Point2f Point2f;
|
||||
typedef ov::Rect Rect;
|
||||
@@ -19,6 +20,12 @@ typedef struct Size {
|
||||
int width;
|
||||
int height;
|
||||
} Size;
|
||||
//
|
||||
// Wrapper for an individual cv::cvSize2f
|
||||
typedef struct Size2f {
|
||||
int width;
|
||||
int height;
|
||||
} Size2f;
|
||||
|
||||
// Wrapper for an individual cv::cvPoint
|
||||
typedef struct Point {
|
||||
@@ -41,12 +48,13 @@ typedef struct Rect {
|
||||
int height;
|
||||
} Rect;
|
||||
|
||||
|
||||
typedef struct Keypoint {
|
||||
Point2f p;
|
||||
float score;
|
||||
int id;
|
||||
} Keypoint;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
typedef void* IEstimator;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "config.h"
|
||||
#include "net.h"
|
||||
#ifdef OV_OPENMP
|
||||
@@ -24,31 +25,50 @@ protected:
|
||||
};
|
||||
|
||||
// Wrapper for an individual cv::cvSize
|
||||
typedef struct Size {
|
||||
struct Size {
|
||||
int width;
|
||||
int height;
|
||||
Size(int _width = 0, int _height = 0): width(_width), height(_height) {}
|
||||
} Size;
|
||||
};
|
||||
//
|
||||
// Wrapper for an individual cv::cvSize2f
|
||||
struct Size2f {
|
||||
float width;
|
||||
float height;
|
||||
Size2f(float _width = 0, float _height = 0): width(_width), height(_height) {}
|
||||
};
|
||||
|
||||
// Wrapper for an individual cv::cvPoint
|
||||
typedef struct Point {
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
Point(int _x = 0, int _y = 0): x(_x), y(_y) {}
|
||||
Point operator-(const Point &p2) {
|
||||
return Point(x - p2.x, y - p2.y);
|
||||
};
|
||||
} Point;
|
||||
};
|
||||
|
||||
// Wrapper for an individual cv::Point2f
|
||||
typedef struct Point2f {
|
||||
struct Point2f {
|
||||
float x;
|
||||
float y;
|
||||
Point2f(float _x = 0, float _y = 0): x(_x), y(_y) {}
|
||||
} Point2f;
|
||||
Point2f operator*(float f) const {
|
||||
return Point2f(x * f, y * f);
|
||||
};
|
||||
Point2f operator/(float f) const {
|
||||
return Point2f(x / f, y / f);
|
||||
};
|
||||
Point2f operator+(const Point2f &p2) const {
|
||||
return Point2f(x + p2.x, y + p2.y);
|
||||
};
|
||||
Point2f operator-(const Point2f &p2) const {
|
||||
return Point2f(x - p2.x, y - p2.y);
|
||||
};
|
||||
};
|
||||
|
||||
// Wrapper for an individual cv::Rect
|
||||
typedef struct Rect {
|
||||
struct Rect {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
@@ -79,23 +99,44 @@ typedef struct Rect {
|
||||
}
|
||||
return Rect(inter_x, inter_y, inter_width, inter_height);
|
||||
};
|
||||
} Rect;
|
||||
|
||||
struct ImageInfo {
|
||||
std::string label_;
|
||||
float score;
|
||||
};
|
||||
|
||||
struct Keypoint {
|
||||
Point2f p;
|
||||
float score;
|
||||
int id;
|
||||
Keypoint(){};
|
||||
Keypoint(const Point2f p_): p(p_){};
|
||||
};
|
||||
|
||||
struct ObjectInfo {
|
||||
Rect rect;
|
||||
float score;
|
||||
int label;
|
||||
std::vector<Point2f> pts;
|
||||
std::vector<Keypoint> pts;
|
||||
};
|
||||
|
||||
struct Image {
|
||||
std::vector<float> data;
|
||||
int width;
|
||||
int height;
|
||||
int channels;
|
||||
float at(const Point& p) const {
|
||||
return data.at((p.x + p.y * width) * channels);
|
||||
};
|
||||
float atChannel(const Point& p, int channel) const {
|
||||
return data.at((p.x + p.y * width) * channels + channel);
|
||||
};
|
||||
Image(){};
|
||||
Image(const ncnn::Mat& mat): width(mat.w), height(mat.h), channels(mat.c) {
|
||||
int data_size = mat.total();
|
||||
float* ptr = (float*)malloc(data_size * sizeof(float));
|
||||
memcpy(ptr, mat.data, data_size * sizeof(float));
|
||||
data.clear();
|
||||
data.resize(data_size);
|
||||
data.assign(ptr, ptr + data_size);
|
||||
free(ptr);
|
||||
};
|
||||
};
|
||||
|
||||
struct GridAndStride
|
||||
@@ -105,6 +146,20 @@ struct GridAndStride
|
||||
int stride;
|
||||
};
|
||||
|
||||
template<typename T, std::size_t N>
|
||||
constexpr std::size_t arraySize(const T (&)[N]) noexcept {
|
||||
return N;
|
||||
}
|
||||
|
||||
static inline int cvRound(double x) {
|
||||
int y;
|
||||
if(x >= (int)x+0.5)
|
||||
y = (int)x++;
|
||||
else
|
||||
y = (int)x;
|
||||
return y;
|
||||
};
|
||||
|
||||
int RatioAnchors(const Rect & anchor,
|
||||
const std::vector<float>& ratios, std::vector<Rect>* anchors, int threads_num);
|
||||
|
||||
|
@@ -239,8 +239,8 @@ int YoloFace::DetectFace(const unsigned char* rgbdata,
|
||||
|
||||
for (int j = 0; j < obj.pts.size(); j++)
|
||||
{
|
||||
float ptx = (obj.pts[j].x - (float(wpad) / 2)) / scale;
|
||||
float pty = (obj.pts[j].y - (float(hpad) / 2)) / scale;
|
||||
float ptx = (obj.pts[j].p.x - (float(wpad) / 2)) / scale;
|
||||
float pty = (obj.pts[j].p.y - (float(hpad) / 2)) / scale;
|
||||
obj.pts[j] = ov::Point2f(ptx, pty);
|
||||
}
|
||||
|
||||
@@ -258,8 +258,8 @@ int YoloFace::DetectFace(const unsigned char* rgbdata,
|
||||
FaceInfo info;
|
||||
info.rect = obj.rect;
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
info.keypoints_[k] = obj.pts[k].x;
|
||||
info.keypoints_[k + 5] = obj.pts[k].y;
|
||||
info.keypoints_[k] = obj.pts[k].p.x;
|
||||
info.keypoints_[k + 5] = obj.pts[k].p.y;
|
||||
}
|
||||
|
||||
faces->push_back(info);
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include "../pose.h"
|
||||
#include "handpose/handpose.hpp"
|
||||
#include <iostream>
|
||||
|
||||
IHandPoseEstimator new_handpose() {
|
||||
return new ovhand::HandPose();
|
||||
|
@@ -9,6 +9,7 @@ extern "C" {
|
||||
#endif
|
||||
typedef void* IPoseDetecter;
|
||||
IPoseDetecter new_ultralight();
|
||||
IPoseDetecter new_openpose();
|
||||
int detect_pose(IPoseDetecter d, const unsigned char* rgbdata,
|
||||
int img_width, int img_height,
|
||||
ObjectInfoVector* rois);
|
||||
|
@@ -1,10 +1,15 @@
|
||||
#include "../detecter.h"
|
||||
#include "ultralight/ultralight.hpp"
|
||||
#include "openpose/openpose.hpp"
|
||||
|
||||
IPoseDetecter new_ultralight() {
|
||||
return new ovpose::Ultralight();
|
||||
}
|
||||
|
||||
IPoseDetecter new_openpose() {
|
||||
return new ovpose::OpenPose();
|
||||
}
|
||||
|
||||
int detect_pose(IPoseDetecter d, const unsigned char* rgbdata, int img_width, int img_height, ObjectInfoVector* rois) {
|
||||
std::vector<ov::ObjectInfo> detected;
|
||||
int ret = static_cast<ovpose::Detecter*>(d)->Detect(rgbdata, img_width, img_height, &detected);
|
||||
@@ -16,12 +21,20 @@ int detect_pose(IPoseDetecter d, const unsigned char* rgbdata, int img_width, in
|
||||
rois->items = (ObjectInfo*)malloc(rois->length * sizeof(ObjectInfo));
|
||||
for (size_t i = 0; i < detected.size(); ++i) {
|
||||
ov::ObjectInfo o = detected[i];
|
||||
rois->items[i] = ObjectInfo{
|
||||
o.rect,
|
||||
o.score,
|
||||
o.label,
|
||||
NULL
|
||||
};
|
||||
rois->items[i].rect = o.rect;
|
||||
rois->items[i].score = o.score;
|
||||
rois->items[i].label = o.label;
|
||||
if (o.pts.size() > 0) {
|
||||
rois->items[i].pts = (KeypointVector*)malloc(sizeof(KeypointVector));
|
||||
rois->items[i].pts->length = o.pts.size();
|
||||
rois->items[i].pts->points = (Keypoint*)malloc(o.pts.size() * sizeof(Keypoint));
|
||||
for (size_t j=0; j < o.pts.size(); ++j) {
|
||||
ov::Keypoint pt = o.pts.at(j);
|
||||
rois->items[i].pts->points[j] = pt;
|
||||
}
|
||||
} else {
|
||||
rois->items[i].pts = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -30,4 +43,7 @@ namespace ovpose {
|
||||
Detecter* UltralightFactory::CreateDetecter() {
|
||||
return new Ultralight();
|
||||
}
|
||||
Detecter* OpenPoseFactory::CreateDetecter() {
|
||||
return new OpenPose();
|
||||
}
|
||||
}
|
||||
|
@@ -24,5 +24,12 @@ public:
|
||||
~UltralightFactory() {}
|
||||
Detecter* CreateDetecter();
|
||||
};
|
||||
|
||||
class OpenPoseFactory: public DetecterFactory {
|
||||
public:
|
||||
OpenPoseFactory() {}
|
||||
~OpenPoseFactory() {}
|
||||
Detecter* CreateDetecter();
|
||||
};
|
||||
}
|
||||
#endif // !_POSE_DETECTER_H
|
||||
|
424
src/pose/detecter/openpose/openpose.cpp
Normal file
424
src/pose/detecter/openpose/openpose.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
#include "openpose.hpp"
|
||||
#include "mat.h"
|
||||
|
||||
#ifdef OV_VULKAN
|
||||
#include "gpu.h"
|
||||
#endif // OV_VULKAN
|
||||
|
||||
namespace ovpose {
|
||||
|
||||
static const std::pair<int, int> limbIdsHeatmap[] = {
|
||||
{1, 2}, {1, 5}, {2, 3}, {3, 4}, {5, 6},
|
||||
{6, 7}, {1, 8}, {8, 9}, {9, 10}, {1, 11},
|
||||
{11, 12}, {12, 13}, {1, 0}, {0, 14}, {14, 16},
|
||||
{0, 15}, {15, 17}, {2, 16}, {5, 17}
|
||||
};
|
||||
static const std::pair<int, int> limbIdsPaf[] = {
|
||||
{12, 13}, {20, 21}, {14, 15}, {16, 17}, {22, 23},
|
||||
{24, 25}, {0, 1}, {2, 3}, {4, 5}, {6, 7},
|
||||
{8, 9}, {10, 11}, {28, 29}, {30, 31}, {34, 35},
|
||||
{32, 33}, {36, 37}, {18, 19}, {26, 27}
|
||||
};
|
||||
|
||||
int OpenPose::Detect(const unsigned char* rgbdata,
|
||||
int img_width, int img_height,
|
||||
std::vector<ov::ObjectInfo>* rois) {
|
||||
if (!initialized_) {
|
||||
return 10000;
|
||||
}
|
||||
if (rgbdata == 0){
|
||||
return 10001;
|
||||
}
|
||||
int w = img_width;
|
||||
int h = img_height;
|
||||
int net_w = 456;
|
||||
int net_h = 456;
|
||||
float scale = 1.0f;
|
||||
if (w > h) {
|
||||
scale = (float) net_w / w;
|
||||
w = net_w;
|
||||
h = h * scale;
|
||||
} else {
|
||||
scale = (float) net_h / h;
|
||||
h = net_h;
|
||||
w = w * scale;
|
||||
}
|
||||
|
||||
ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, img_width, img_height, w, h);
|
||||
in.substract_mean_normalize(mean_vals, norm_vals);
|
||||
|
||||
// forward
|
||||
ncnn::Mat pafs;
|
||||
ncnn::Mat heatmaps;
|
||||
ncnn::Extractor ex = net_->create_extractor();
|
||||
ex.input("data", in);
|
||||
ex.extract("stage_1_output_1_heatmaps", heatmaps); // or stage_0_output_1_heatmaps
|
||||
ex.extract("stage_1_output_0_pafs", pafs); // or stage_0_output_0_pafs
|
||||
|
||||
// postprocess
|
||||
this->postProcess(pafs, heatmaps, *rois, img_height, img_width, h, w);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OpenPose::findPeaks(const std::vector<ov::Image> &heatMaps,
|
||||
const float minPeaksDistance,
|
||||
std::vector<std::vector<ov::Keypoint> > &allPeaks,
|
||||
int heatMapId) {
|
||||
const float threshold = 0.1f;
|
||||
std::vector<ov::Point2f> peaks;
|
||||
const ov::Image &heatMap = heatMaps[heatMapId];
|
||||
int heatMapStep = heatMap.channels * heatMap.width;
|
||||
for (int y = -1; y < heatMap.height + 1; y++) {
|
||||
for (int x = -1; x < heatMap.width + 1; x++) {
|
||||
float val = 0;
|
||||
if (x >= 0
|
||||
&& y >= 0
|
||||
&& x < heatMap.width
|
||||
&& y < heatMap.height) {
|
||||
val = heatMap.data[y * heatMapStep + x];
|
||||
val = val >= threshold ? val : 0;
|
||||
}
|
||||
|
||||
float left_val = 0;
|
||||
if (y >= 0
|
||||
&& x < (heatMap.width- 1)
|
||||
&& y < heatMap.height) {
|
||||
left_val = heatMap.data[y * heatMapStep + x + 1];
|
||||
left_val = left_val >= threshold ? left_val : 0;
|
||||
}
|
||||
|
||||
float right_val = 0;
|
||||
if (x > 0
|
||||
&& y >= 0
|
||||
&& y < heatMap.height) {
|
||||
right_val = heatMap.data[y * heatMapStep + x - 1];
|
||||
right_val = right_val >= threshold ? right_val : 0;
|
||||
}
|
||||
|
||||
float top_val = 0;
|
||||
if (x >= 0
|
||||
&& x < heatMap.width
|
||||
&& y < (heatMap.height- 1)) {
|
||||
top_val = heatMap.data[(y + 1) * heatMapStep + x];
|
||||
top_val = top_val >= threshold ? top_val : 0;
|
||||
}
|
||||
|
||||
float bottom_val = 0;
|
||||
if (x >= 0
|
||||
&& y > 0
|
||||
&& x < heatMap.width) {
|
||||
bottom_val = heatMap.data[(y - 1) * heatMapStep + x];
|
||||
bottom_val = bottom_val >= threshold ? bottom_val : 0;
|
||||
}
|
||||
|
||||
if ((val > left_val)
|
||||
&& (val > right_val)
|
||||
&& (val > top_val)
|
||||
&& (val > bottom_val)) {
|
||||
peaks.push_back(ov::Point2f(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(peaks.begin(), peaks.end(), [](const ov::Point2f &a, const ov::Point2f &b) {
|
||||
return a.x < b.x;
|
||||
});
|
||||
std::vector<bool> isActualPeak(peaks.size(), true);
|
||||
int peakCounter = 0;
|
||||
std::vector<ov::Keypoint> &peaksWithScoreAndID = allPeaks[heatMapId];
|
||||
for (size_t i = 0; i < peaks.size(); i++) {
|
||||
if (isActualPeak[i]) {
|
||||
for (size_t j = i + 1; j < peaks.size(); j++) {
|
||||
if (sqrt((peaks[i].x - peaks[j].x) * (peaks[i].x - peaks[j].x) +
|
||||
(peaks[i].y - peaks[j].y) * (peaks[i].y - peaks[j].y)) < minPeaksDistance) {
|
||||
isActualPeak[j] = false;
|
||||
}
|
||||
}
|
||||
ov::Keypoint pt;
|
||||
pt.id = peakCounter++;
|
||||
pt.p = peaks[i];
|
||||
pt.score = heatMap.data[peaks[i].x + peaks[i].y * heatMapStep];
|
||||
peaksWithScoreAndID.push_back(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenPose::groupPeaksToPoses(const std::vector<std::vector<ov::Keypoint> > &allPeaks,
|
||||
const std::vector<ov::Image> &pafs,
|
||||
std::vector<ov::ObjectInfo>& poses,
|
||||
const size_t keypointsNumber,
|
||||
const float midPointsScoreThreshold,
|
||||
const float foundMidPointsRatioThreshold,
|
||||
const int minJointsNumber,
|
||||
const float minSubsetScore) {
|
||||
std::vector<ov::Keypoint> candidates;
|
||||
for (const auto &peaks : allPeaks) {
|
||||
candidates.insert(candidates.end(), peaks.begin(), peaks.end());
|
||||
}
|
||||
std::vector<HumanPoseByPeaksIndices> subset(0, HumanPoseByPeaksIndices(keypointsNumber));
|
||||
for (size_t k = 0; k < ov::arraySize(limbIdsPaf); k++) {
|
||||
std::vector<TwoJointsConnection> connections;
|
||||
const int mapIdxOffset = 0; // keypointsNumber + 1;
|
||||
std::pair<ov::Image, ov::Image> scoreMid = {pafs[limbIdsPaf[k].first - mapIdxOffset],
|
||||
pafs[limbIdsPaf[k].second - mapIdxOffset]};
|
||||
const int idxJointA = limbIdsHeatmap[k].first; // first - 1;
|
||||
const int idxJointB = limbIdsHeatmap[k].second; // second - 1;
|
||||
const std::vector<ov::Keypoint> &candA = allPeaks[idxJointA];
|
||||
const std::vector<ov::Keypoint> &candB = allPeaks[idxJointB];
|
||||
const size_t nJointsA = candA.size();
|
||||
const size_t nJointsB = candB.size();
|
||||
if (nJointsA == 0 && nJointsB == 0) {
|
||||
continue;
|
||||
} else if (nJointsA == 0) {
|
||||
for (size_t i = 0; i < nJointsB; i++) {
|
||||
int num = 0;
|
||||
for (size_t j = 0; j < subset.size(); j++) {
|
||||
if (subset[j].peaksIndices[idxJointB] == candB[i].id) {
|
||||
num++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (num == 0) {
|
||||
HumanPoseByPeaksIndices personKeypoints(keypointsNumber);
|
||||
personKeypoints.peaksIndices[idxJointB] = candB[i].id;
|
||||
personKeypoints.nJoints = 1;
|
||||
personKeypoints.score = candB[i].score;
|
||||
subset.push_back(personKeypoints);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if (nJointsB == 0) {
|
||||
for (size_t i = 0; i < nJointsA; i++) {
|
||||
int num = 0;
|
||||
for (size_t j = 0; j < subset.size(); j++) {
|
||||
if (subset[j].peaksIndices[idxJointA] == candA[i].id) {
|
||||
num++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (num == 0) {
|
||||
HumanPoseByPeaksIndices personKeypoints(keypointsNumber);
|
||||
personKeypoints.peaksIndices[idxJointA] = candA[i].id;
|
||||
personKeypoints.nJoints = 1;
|
||||
personKeypoints.score = candA[i].score;
|
||||
subset.push_back(personKeypoints);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<TwoJointsConnection> tempJointConnections;
|
||||
for (size_t i = 0; i < nJointsA; i++) {
|
||||
for (size_t j = 0; j < nJointsB; j++) {
|
||||
ov::Point2f pt = candA[i].p * 0.5 + candB[j].p * 0.5;
|
||||
ov::Point mid = ov::Point(ov::cvRound(pt.x), ov::cvRound(pt.y));
|
||||
ov::Point2f vec = candB[j].p - candA[i].p;
|
||||
double norm_vec = sqrt(vec.x * vec.x + vec.y * vec.y);
|
||||
if (norm_vec == 0) {
|
||||
continue;
|
||||
}
|
||||
vec = vec / norm_vec;
|
||||
float score = vec.x * scoreMid.first.at(mid) + vec.y * scoreMid.second.at(mid);
|
||||
int height_n = pafs[0].height/ 2;
|
||||
float suc_ratio = 0.0f;
|
||||
float mid_score = 0.0f;
|
||||
const int mid_num = 10;
|
||||
const float scoreThreshold = -100.0f;
|
||||
if (score > scoreThreshold) {
|
||||
float p_sum = 0;
|
||||
float p_count = 0;
|
||||
ov::Size2f step((candB[j].p.x - candA[i].p.x) / (mid_num - 1),
|
||||
(candB[j].p.y - candA[i].p.y) / (mid_num - 1));
|
||||
for (int n = 0; n < mid_num; n++) {
|
||||
ov::Point midPoint(ov::cvRound(candA[i].p.x + n * step.width),
|
||||
ov::cvRound(candA[i].p.y + n * step.height));
|
||||
ov::Point2f pred(scoreMid.first.at(midPoint),
|
||||
scoreMid.second.at(midPoint));
|
||||
score = vec.x * pred.x + vec.y * pred.y;
|
||||
if (score > midPointsScoreThreshold) {
|
||||
p_sum += score;
|
||||
p_count++;
|
||||
}
|
||||
}
|
||||
suc_ratio = static_cast<float>(p_count / mid_num);
|
||||
float ratio = p_count > 0 ? p_sum / p_count : 0.0f;
|
||||
mid_score = ratio + static_cast<float>(std::min(height_n / norm_vec - 1, 0.0));
|
||||
}
|
||||
if (mid_score > 0
|
||||
&& suc_ratio > foundMidPointsRatioThreshold) {
|
||||
tempJointConnections.push_back(TwoJointsConnection(i, j, mid_score));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!tempJointConnections.empty()) {
|
||||
std::sort(tempJointConnections.begin(), tempJointConnections.end(),
|
||||
[](const TwoJointsConnection &a,
|
||||
const TwoJointsConnection &b) {
|
||||
return (a.score > b.score);
|
||||
});
|
||||
}
|
||||
size_t num_limbs = std::min(nJointsA, nJointsB);
|
||||
size_t cnt = 0;
|
||||
std::vector<int> occurA(nJointsA, 0);
|
||||
std::vector<int> occurB(nJointsB, 0);
|
||||
for (size_t row = 0; row < tempJointConnections.size(); row++) {
|
||||
if (cnt == num_limbs) {
|
||||
break;
|
||||
}
|
||||
const int &indexA = tempJointConnections[row].firstJointIdx;
|
||||
const int &indexB = tempJointConnections[row].secondJointIdx;
|
||||
const float &score = tempJointConnections[row].score;
|
||||
if (occurA[indexA] == 0
|
||||
&& occurB[indexB] == 0) {
|
||||
connections.push_back(TwoJointsConnection(candA[indexA].id, candB[indexB].id, score));
|
||||
cnt++;
|
||||
occurA[indexA] = 1;
|
||||
occurB[indexB] = 1;
|
||||
}
|
||||
}
|
||||
if (connections.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool extraJointConnections = (k == 17 || k == 18);
|
||||
if (k == 0) {
|
||||
subset = std::vector<HumanPoseByPeaksIndices>(
|
||||
connections.size(), HumanPoseByPeaksIndices(keypointsNumber));
|
||||
for (size_t i = 0; i < connections.size(); i++) {
|
||||
const int &indexA = connections[i].firstJointIdx;
|
||||
const int &indexB = connections[i].secondJointIdx;
|
||||
subset[i].peaksIndices[idxJointA] = indexA;
|
||||
subset[i].peaksIndices[idxJointB] = indexB;
|
||||
subset[i].nJoints = 2;
|
||||
subset[i].score = candidates[indexA].score + candidates[indexB].score + connections[i].score;
|
||||
}
|
||||
} else if (extraJointConnections) {
|
||||
for (size_t i = 0; i < connections.size(); i++) {
|
||||
const int &indexA = connections[i].firstJointIdx;
|
||||
const int &indexB = connections[i].secondJointIdx;
|
||||
for (size_t j = 0; j < subset.size(); j++) {
|
||||
if (subset[j].peaksIndices[idxJointA] == indexA
|
||||
&& subset[j].peaksIndices[idxJointB] == -1) {
|
||||
subset[j].peaksIndices[idxJointB] = indexB;
|
||||
} else if (subset[j].peaksIndices[idxJointB] == indexB
|
||||
&& subset[j].peaksIndices[idxJointA] == -1) {
|
||||
subset[j].peaksIndices[idxJointA] = indexA;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
for (size_t i = 0; i < connections.size(); i++) {
|
||||
const int &indexA = connections[i].firstJointIdx;
|
||||
const int &indexB = connections[i].secondJointIdx;
|
||||
bool num = false;
|
||||
for (size_t j = 0; j < subset.size(); j++) {
|
||||
if (subset[j].peaksIndices[idxJointA] == indexA) {
|
||||
subset[j].peaksIndices[idxJointB] = indexB;
|
||||
subset[j].nJoints++;
|
||||
subset[j].score += candidates[indexB].score + connections[i].score;
|
||||
num = true;
|
||||
}
|
||||
}
|
||||
if (!num) {
|
||||
HumanPoseByPeaksIndices hpWithScore(keypointsNumber);
|
||||
hpWithScore.peaksIndices[idxJointA] = indexA;
|
||||
hpWithScore.peaksIndices[idxJointB] = indexB;
|
||||
hpWithScore.nJoints = 2;
|
||||
hpWithScore.score = candidates[indexA].score + candidates[indexB].score + connections[i].score;
|
||||
subset.push_back(hpWithScore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &subsetI : subset) {
|
||||
if (subsetI.nJoints < minJointsNumber || subsetI.score / subsetI.nJoints < minSubsetScore) {
|
||||
continue;
|
||||
}
|
||||
int position = -1;
|
||||
ov::ObjectInfo pose;
|
||||
pose.pts = std::vector<ov::Keypoint>(
|
||||
keypointsNumber,
|
||||
ov::Keypoint(ov::Point2f(-1.0f, -1.0f))
|
||||
);
|
||||
pose.score = subsetI.score * std::max(0, subsetI.nJoints - 1);
|
||||
for (const auto &peakIdx : subsetI.peaksIndices) {
|
||||
position++;
|
||||
if (peakIdx >= 0) {
|
||||
pose.pts[position] = candidates[peakIdx];
|
||||
pose.pts[position].p.x += 0.5;
|
||||
pose.pts[position].p.y += 0.5;
|
||||
}
|
||||
}
|
||||
poses.push_back(pose);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenPose::postProcess(const ncnn::Mat &pafs, const ncnn::Mat &heatmaps,
|
||||
std::vector<ov::ObjectInfo>& poses,
|
||||
int img_h, int img_w,
|
||||
int net_h, int net_w) {
|
||||
|
||||
float upsample_ratio = 4;
|
||||
// heatmaps
|
||||
std::vector<ov::Image> cv_heatmaps_upsample(heatmaps.c);
|
||||
for (int p = 0; p < heatmaps.c; p++) {
|
||||
ncnn::Mat resizedMat;
|
||||
int w = heatmaps.channel(p).w * upsample_ratio;
|
||||
int h = heatmaps.channel(p).h * upsample_ratio;
|
||||
ncnn::resize_bicubic(heatmaps.channel(p), resizedMat, w, h);
|
||||
cv_heatmaps_upsample[p] = ov::Image(resizedMat);
|
||||
}
|
||||
|
||||
// pafs
|
||||
std::vector<ov::Image> cv_pafs_upsample(pafs.c);
|
||||
for (int p = 0; p < pafs.c; p++) {
|
||||
ncnn::Mat resizedMat;
|
||||
int w = pafs.channel(p).w * upsample_ratio;
|
||||
int h = pafs.channel(p).h * upsample_ratio;
|
||||
ncnn::resize_bicubic(pafs.channel(p), resizedMat, w, h);
|
||||
cv_pafs_upsample[p] = ov::Image(resizedMat);
|
||||
}
|
||||
|
||||
// postprocess
|
||||
|
||||
std::vector<std::vector<ov::Keypoint> > peaksFromHeatMap(cv_heatmaps_upsample.size());
|
||||
|
||||
// #if defined(_OPENMP)
|
||||
// #pragma omp parallel for num_threads(num_threads)
|
||||
// #endif
|
||||
for (int i = 0; i < cv_heatmaps_upsample.size(); i++) {
|
||||
this->findPeaks(cv_heatmaps_upsample, minPeaksDistance, peaksFromHeatMap, i);
|
||||
}
|
||||
|
||||
int peaksBefore = 0;
|
||||
for (size_t heatmapId = 1; heatmapId < cv_heatmaps_upsample.size(); heatmapId++) {
|
||||
peaksBefore += static_cast<int>(peaksFromHeatMap[heatmapId - 1].size());
|
||||
for (auto &peak : peaksFromHeatMap[heatmapId]) {
|
||||
peak.id += peaksBefore;
|
||||
}
|
||||
}
|
||||
groupPeaksToPoses(
|
||||
peaksFromHeatMap, cv_pafs_upsample, poses, keypointsNumber, midPointsScoreThreshold,
|
||||
foundMidPointsRatioThreshold, minJointsNumber, minSubsetScore);
|
||||
|
||||
|
||||
// scale keypoint
|
||||
float scale_x = 1.0f * net_w / img_w;
|
||||
float scale_y = 1.0f * net_h / img_h;
|
||||
float stride = 8.0f;
|
||||
float upsample = upsample_ratio;
|
||||
|
||||
for (int i = 0; i < poses.size(); i++) {
|
||||
ov::ObjectInfo pose = poses[i];
|
||||
for (int j = 0; j < keypointsNumber; j++) {
|
||||
if (pose.pts[j].p.x == -1 || pose.pts[j].p.y == -1) {
|
||||
continue;
|
||||
}
|
||||
poses[i].pts[j].p.x = stride / upsample * pose.pts[j].p.x / scale_x;
|
||||
poses[i].pts[j].p.y = stride / upsample * pose.pts[j].p.y / scale_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
65
src/pose/detecter/openpose/openpose.hpp
Normal file
65
src/pose/detecter/openpose/openpose.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef _POSE_OPENPOSE_H_
|
||||
#define _POSE_OPENPOSE_H_
|
||||
|
||||
#include "../detecter.hpp"
|
||||
#include <vector>
|
||||
#include "net.h"
|
||||
|
||||
namespace ovpose {
|
||||
|
||||
struct HumanPoseByPeaksIndices {
|
||||
std::vector<int> peaksIndices;
|
||||
int nJoints;
|
||||
float score;
|
||||
explicit HumanPoseByPeaksIndices(const int keypointsNumber) : peaksIndices(std::vector<int>(keypointsNumber, -1)),
|
||||
nJoints(0),
|
||||
score(0.0f) {};
|
||||
};
|
||||
|
||||
struct TwoJointsConnection {
|
||||
int firstJointIdx;
|
||||
int secondJointIdx;
|
||||
float score;
|
||||
TwoJointsConnection(const int firstJointIdx_,
|
||||
const int secondJointIdx_,
|
||||
const float score_): firstJointIdx(firstJointIdx_), secondJointIdx(secondJointIdx_), score(score_) {};
|
||||
};
|
||||
|
||||
class OpenPose : public Detecter {
|
||||
public:
|
||||
int Detect(const unsigned char* rgbadata,
|
||||
int img_width, int img_height,
|
||||
std::vector<ov::ObjectInfo>* rois);
|
||||
|
||||
private:
|
||||
const float mean_vals[3] = {127.5f, 127.5f, 127.5f};
|
||||
const float norm_vals[3] = {1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f};
|
||||
const float minPeaksDistance = 3.0f;
|
||||
const int keypointsNumber = 18;
|
||||
const float midPointsScoreThreshold = 0.05f;
|
||||
const float foundMidPointsRatioThreshold = 0.8f;
|
||||
const int minJointsNumber = 3;
|
||||
const float minSubsetScore = 0.2f;
|
||||
|
||||
void postProcess(const ncnn::Mat &pafs, const ncnn::Mat &heatmaps,
|
||||
std::vector<ov::ObjectInfo>& poses,
|
||||
int img_h, int img_w,
|
||||
int net_h, int net_w);
|
||||
void findPeaks(const std::vector<ov::Image> &heatMaps,
|
||||
const float minPeaksDistance,
|
||||
std::vector<std::vector<ov::Keypoint> > &allPeaks,
|
||||
int heatMapId);
|
||||
void groupPeaksToPoses(const std::vector<std::vector<ov::Keypoint> > &allPeaks,
|
||||
const std::vector<ov::Image> &pafs,
|
||||
std::vector<ov::ObjectInfo> &poses,
|
||||
const size_t keypointsNumber,
|
||||
const float midPointsScoreThreshold,
|
||||
const float foundMidPointsRatioThreshold,
|
||||
const int minJointsNumber,
|
||||
const float minSubsetScore);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // !_POSE_OPENPOSE_H_
|
||||
|
@@ -14,7 +14,8 @@ int extract_pose_keypoints(IPoseEstimator d, const unsigned char* rgbdata, int i
|
||||
keypoints->length = points.size();
|
||||
keypoints->points = (Keypoint*)malloc(keypoints->length * sizeof(Keypoint));
|
||||
for (size_t i = 0; i < points.size(); ++i) {
|
||||
keypoints->points[i] = points[i];
|
||||
keypoints->points[i].p = points[i].p;
|
||||
keypoints->points[i].score = points[i].score;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user