mirror of
https://github.com/bububa/openvision.git
synced 2025-10-05 13:46:52 +08:00
feat(pose): add pose segmentor
This commit is contained in:
@@ -40,6 +40,9 @@ cmake .. # optional -DNCNN_VULKAN=OFF -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COM
|
|||||||
- estimator (for pose estimation)
|
- estimator (for pose estimation)
|
||||||
- ultralight [Google Drive](https://drive.google.com/drive/folders/15b-I5HDyGe2WLb-TO85SJYmnYONvGOKh?usp=sharing)
|
- ultralight [Google Drive](https://drive.google.com/drive/folders/15b-I5HDyGe2WLb-TO85SJYmnYONvGOKh?usp=sharing)
|
||||||
- movenet [Google Drive](https://drive.google.com/drive/folders/14zgKk0tro1kjRrSTs0EAlEKrV8Q4XA34?usp=sharing)
|
- movenet [Google Drive](https://drive.google.com/drive/folders/14zgKk0tro1kjRrSTs0EAlEKrV8Q4XA34?usp=sharing)
|
||||||
|
- segmentor (for pose segmentation)
|
||||||
|
- deeplabv3plus [Google Drive](https://drive.google.com/drive/folders/1BjiK0IiVAfyX30OoyQzoe1YBzvSudghG?usp=sharing)
|
||||||
|
- erdnet [Google Drive](https://drive.google.com/drive/folders/1WkQqYT9D4oGL6Gubu0SOeqcZmrdZ5cNw?usp=sharing)
|
||||||
- hand
|
- hand
|
||||||
- detector (for hand detect)
|
- detector (for hand detect)
|
||||||
- yolox [Google Drive](https://drive.google.com/drive/folders/1lNm5X6DJ1ZXVaqg54rXnRhvPfC5lAxlH?usp=sharing)
|
- yolox [Google Drive](https://drive.google.com/drive/folders/1lNm5X6DJ1ZXVaqg54rXnRhvPfC5lAxlH?usp=sharing)
|
||||||
|
@@ -92,7 +92,11 @@ func NewImageFromBytes(data []byte, w int, h int, channels int) (image.Image, er
|
|||||||
for y := 0; y < h; y++ {
|
for y := 0; y < h; y++ {
|
||||||
for x := 0; x < w; x++ {
|
for x := 0; x < w; x++ {
|
||||||
pos := (y*w + x) * channels
|
pos := (y*w + x) * channels
|
||||||
img.SetRGBA(x, y, color.RGBA{uint8(data[pos]), uint8(data[pos+1]), uint8(data[pos+2]), 255})
|
var alpha byte = 255
|
||||||
|
if channels == 4 {
|
||||||
|
alpha = data[pos+3]
|
||||||
|
}
|
||||||
|
img.SetRGBA(x, y, color.RGBA{uint8(data[pos]), uint8(data[pos+1]), uint8(data[pos+2]), uint8(alpha)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return img, nil
|
return img, nil
|
||||||
|
135
go/examples/poseseg/main.go
Normal file
135
go/examples/poseseg/main.go
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/bububa/openvision/go/common"
|
||||||
|
"github.com/bububa/openvision/go/pose/segmentor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
dataPath := cleanPath(wd, "~/go/src/github.com/bububa/openvision/data")
|
||||||
|
imgPath := filepath.Join(dataPath, "./images")
|
||||||
|
modelPath := filepath.Join(dataPath, "./models")
|
||||||
|
common.CreateGPUInstance()
|
||||||
|
defer common.DestroyGPUInstance()
|
||||||
|
cpuCores := common.GetBigCPUCount()
|
||||||
|
common.SetOMPThreads(cpuCores)
|
||||||
|
log.Printf("CPU big cores:%d\n", cpuCores)
|
||||||
|
for idx, seg := range []segmentor.Segmentor{
|
||||||
|
deeplabv3(modelPath),
|
||||||
|
erdnet(modelPath),
|
||||||
|
} {
|
||||||
|
defer seg.Destroy()
|
||||||
|
common.SetEstimatorThreads(seg, cpuCores)
|
||||||
|
matting(seg, imgPath, "ultralight-pose2.jpg", idx)
|
||||||
|
merge(seg, imgPath, "ultralight-pose2.jpg", "bg2.jpg", idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func deeplabv3(modelPath string) segmentor.Segmentor {
|
||||||
|
modelPath = filepath.Join(modelPath, "deeplabv3plus")
|
||||||
|
d := segmentor.NewDeeplabv3plus()
|
||||||
|
if err := d.LoadModel(modelPath); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func erdnet(modelPath string) segmentor.Segmentor {
|
||||||
|
modelPath = filepath.Join(modelPath, "erdnet")
|
||||||
|
d := segmentor.NewERDNet()
|
||||||
|
if err := d.LoadModel(modelPath); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func matting(seg segmentor.Segmentor, imgPath string, filename string, idx int) {
|
||||||
|
inPath := filepath.Join(imgPath, filename)
|
||||||
|
imgLoaded, err := loadImage(inPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("load image failed,", err)
|
||||||
|
}
|
||||||
|
img := common.NewImage(imgLoaded)
|
||||||
|
out, err := seg.Matting(img)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
outPath := filepath.Join(imgPath, "./results", fmt.Sprintf("poseseg-matting-%d-%s", idx, filename))
|
||||||
|
if err := saveImage(out, outPath); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func merge(seg segmentor.Segmentor, imgPath string, filename string, bgFilename string, idx int) {
|
||||||
|
inPath := filepath.Join(imgPath, filename)
|
||||||
|
imgLoaded, err := loadImage(inPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("load image failed,", err)
|
||||||
|
}
|
||||||
|
img := common.NewImage(imgLoaded)
|
||||||
|
bgPath := filepath.Join(imgPath, bgFilename)
|
||||||
|
bgLoaded, err := loadImage(bgPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("load bg image failed,", err)
|
||||||
|
}
|
||||||
|
bg := common.NewImage(bgLoaded)
|
||||||
|
out, err := seg.Merge(img, bg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
outPath := filepath.Join(imgPath, "./results", fmt.Sprintf("poseseg-merge-%d-%s", idx, filename))
|
||||||
|
if err := saveImage(out, outPath); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadImage(filePath string) (image.Image, error) {
|
||||||
|
fn, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer fn.Close()
|
||||||
|
img, _, err := image.Decode(fn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return img, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveImage(img image.Image, filePath string) error {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := jpeg.Encode(buf, img, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fn, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fn.Close()
|
||||||
|
fn.Write(buf.Bytes())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanPath(wd string, path string) string {
|
||||||
|
usr, _ := user.Current()
|
||||||
|
dir := usr.HomeDir
|
||||||
|
if path == "~" {
|
||||||
|
return dir
|
||||||
|
} else if strings.HasPrefix(path, "~/") {
|
||||||
|
return filepath.Join(dir, path[2:])
|
||||||
|
}
|
||||||
|
return filepath.Join(wd, path)
|
||||||
|
}
|
11
go/pose/segmentor/cgo.go
Normal file
11
go/pose/segmentor/cgo.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// +build !vulkan
|
||||||
|
|
||||||
|
package segmentor
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CXXFLAGS: --std=c++11 -fopenmp
|
||||||
|
#cgo CPPFLAGS: -I ${SRCDIR}/../../../include -I /usr/local/include
|
||||||
|
#cgo LDFLAGS: -lstdc++ -lncnn -lomp -lopenvision
|
||||||
|
#cgo LDFLAGS: -L /usr/local/lib -L ${SRCDIR}/../../../lib
|
||||||
|
*/
|
||||||
|
import "C"
|
11
go/pose/segmentor/cgo_vulkan.go
Normal file
11
go/pose/segmentor/cgo_vulkan.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// +build vulkan
|
||||||
|
|
||||||
|
package segmentor
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CXXFLAGS: --std=c++11 -fopenmp
|
||||||
|
#cgo CPPFLAGS: -I ${SRCDIR}/../../../include -I /usr/local/include
|
||||||
|
#cgo LDFLAGS: -lstdc++ -lncnn -lomp -lopenvision -lglslang -lvulkan -lSPIRV -lOGLCompiler -lMachineIndependent -lGenericCodeGen -lOSDependent
|
||||||
|
#cgo LDFLAGS: -L /usr/local/lib -L ${SRCDIR}/../../../lib
|
||||||
|
*/
|
||||||
|
import "C"
|
51
go/pose/segmentor/deeplabv3plus.go
Normal file
51
go/pose/segmentor/deeplabv3plus.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package segmentor
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "openvision/pose/segmentor.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/bububa/openvision/go/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deeplabv3plus represents deeplabv3plus segmentor
|
||||||
|
type Deeplabv3plus struct {
|
||||||
|
d C.IPoseSegmentor
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDeeplabv3plus returns a new Deeplabv3plus
|
||||||
|
func NewDeeplabv3plus() *Deeplabv3plus {
|
||||||
|
return &Deeplabv3plus{
|
||||||
|
d: C.new_deeplabv3plus_pose_segmentor(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy free segmentor
|
||||||
|
func (d *Deeplabv3plus) Destroy() {
|
||||||
|
common.DestroyEstimator(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer implement Estimator interface
|
||||||
|
func (d *Deeplabv3plus) Pointer() unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(d.d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadModel load model for detecter
|
||||||
|
func (d *Deeplabv3plus) LoadModel(modelPath string) error {
|
||||||
|
return common.EstimatorLoadModel(d, modelPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matting implement Segmentor interface
|
||||||
|
func (d *Deeplabv3plus) Matting(img *common.Image) (image.Image, error) {
|
||||||
|
return Matting(d, img)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge implement Segmentor interface
|
||||||
|
func (d *Deeplabv3plus) Merge(img *common.Image, bg *common.Image) (image.Image, error) {
|
||||||
|
return Merge(d, img, bg)
|
||||||
|
}
|
2
go/pose/segmentor/doc.go
Normal file
2
go/pose/segmentor/doc.go
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Package segmentor pose estimator
|
||||||
|
package segmentor
|
51
go/pose/segmentor/erdnet.go
Normal file
51
go/pose/segmentor/erdnet.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package segmentor
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "openvision/pose/segmentor.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/bububa/openvision/go/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ERDNet represents erdnet segmentor
|
||||||
|
type ERDNet struct {
|
||||||
|
d C.IPoseSegmentor
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewERDNet returns a new ERDNet
|
||||||
|
func NewERDNet() *ERDNet {
|
||||||
|
return &ERDNet{
|
||||||
|
d: C.new_erdnet_pose_segmentor(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy free segmentor
|
||||||
|
func (d *ERDNet) Destroy() {
|
||||||
|
common.DestroyEstimator(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer implement Estimator interface
|
||||||
|
func (d *ERDNet) Pointer() unsafe.Pointer {
|
||||||
|
return unsafe.Pointer(d.d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadModel load model for detecter
|
||||||
|
func (d *ERDNet) LoadModel(modelPath string) error {
|
||||||
|
return common.EstimatorLoadModel(d, modelPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matting implement Segmentor interface
|
||||||
|
func (d *ERDNet) Matting(img *common.Image) (image.Image, error) {
|
||||||
|
return Matting(d, img)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge implement Segmentor interface
|
||||||
|
func (d *ERDNet) Merge(img *common.Image, bg *common.Image) (image.Image, error) {
|
||||||
|
return Merge(d, img, bg)
|
||||||
|
}
|
65
go/pose/segmentor/segmentor.go
Normal file
65
go/pose/segmentor/segmentor.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package segmentor
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "openvision/common/common.h"
|
||||||
|
#include "openvision/pose/segmentor.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
openvision "github.com/bububa/openvision/go"
|
||||||
|
"github.com/bububa/openvision/go/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Segmentor represents segmentor interface
|
||||||
|
type Segmentor interface {
|
||||||
|
common.Estimator
|
||||||
|
Matting(img *common.Image) (image.Image, error)
|
||||||
|
Merge(img *common.Image, bg *common.Image) (image.Image, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matting returns pose segment matting image
|
||||||
|
func Matting(d Segmentor, img *common.Image) (image.Image, error) {
|
||||||
|
imgWidth := img.WidthF64()
|
||||||
|
imgHeight := img.HeightF64()
|
||||||
|
data := img.Bytes()
|
||||||
|
outImgC := common.NewCImage()
|
||||||
|
defer common.FreeCImage(outImgC)
|
||||||
|
errCode := C.pose_segment_matting(
|
||||||
|
(C.IPoseSegmentor)(d.Pointer()),
|
||||||
|
(*C.uchar)(unsafe.Pointer(&data[0])),
|
||||||
|
C.int(imgWidth),
|
||||||
|
C.int(imgHeight),
|
||||||
|
(*C.Image)(unsafe.Pointer(outImgC)))
|
||||||
|
if errCode != 0 {
|
||||||
|
return nil, openvision.DetectPoseError(int(errCode))
|
||||||
|
}
|
||||||
|
return common.GoImage(outImgC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merge pose with background
|
||||||
|
func Merge(d Segmentor, img *common.Image, bg *common.Image) (image.Image, error) {
|
||||||
|
imgWidth := img.WidthF64()
|
||||||
|
imgHeight := img.HeightF64()
|
||||||
|
data := img.Bytes()
|
||||||
|
bgWidth := bg.Width()
|
||||||
|
bgHeight := bg.Height()
|
||||||
|
bgdata := bg.Bytes()
|
||||||
|
outImgC := common.NewCImage()
|
||||||
|
defer common.FreeCImage(outImgC)
|
||||||
|
errCode := C.pose_segment_merge(
|
||||||
|
(C.IPoseSegmentor)(d.Pointer()),
|
||||||
|
(*C.uchar)(unsafe.Pointer(&data[0])),
|
||||||
|
C.int(imgWidth), C.int(imgHeight),
|
||||||
|
(*C.uchar)(unsafe.Pointer(&bgdata[0])),
|
||||||
|
C.int(bgWidth), C.int(bgHeight),
|
||||||
|
(*C.Image)(unsafe.Pointer(outImgC)))
|
||||||
|
if errCode != 0 {
|
||||||
|
return nil, openvision.DetectPoseError(int(errCode))
|
||||||
|
}
|
||||||
|
return common.GoImage(outImgC)
|
||||||
|
}
|
@@ -68,6 +68,7 @@ target_include_directories(openvision
|
|||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose>
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/detecter>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/detecter>
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/estimator>
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/estimator>
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/pose/segmentor>
|
||||||
)
|
)
|
||||||
|
|
||||||
#install(TARGETS openvision EXPORT openvision ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH})
|
#install(TARGETS openvision EXPORT openvision ARCHIVE DESTINATION ${LIBRARY_OUTPUT_PATH})
|
||||||
@@ -96,6 +97,7 @@ file(COPY
|
|||||||
file(COPY
|
file(COPY
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/pose/detecter.h
|
${CMAKE_CURRENT_SOURCE_DIR}/pose/detecter.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/pose/estimator.h
|
${CMAKE_CURRENT_SOURCE_DIR}/pose/estimator.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/pose/segmentor.h
|
||||||
DESTINATION ${INCLUDE_OUTPUT_PATH}/openvision/pose
|
DESTINATION ${INCLUDE_OUTPUT_PATH}/openvision/pose
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -130,6 +130,8 @@ Estimator::Estimator() : EstimatorBase() {
|
|||||||
if (num_threads > 0) {
|
if (num_threads > 0) {
|
||||||
net_->opt.num_threads = num_threads;
|
net_->opt.num_threads = num_threads;
|
||||||
}
|
}
|
||||||
|
net_->opt.blob_allocator = &blob_allocator_;
|
||||||
|
net_->opt.workspace_allocator = &workspace_allocator_;
|
||||||
#ifdef OV_VULKAN
|
#ifdef OV_VULKAN
|
||||||
net_->opt.use_vulkan_compute = true;
|
net_->opt.use_vulkan_compute = true;
|
||||||
#endif // OV_VULKAN
|
#endif // OV_VULKAN
|
||||||
@@ -139,6 +141,8 @@ Estimator::~Estimator() {
|
|||||||
if (net_) {
|
if (net_) {
|
||||||
net_->clear();
|
net_->clear();
|
||||||
}
|
}
|
||||||
|
workspace_allocator_.clear();
|
||||||
|
blob_allocator_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Estimator::LoadModel(const char * root_path) {
|
int Estimator::LoadModel(const char * root_path) {
|
||||||
|
@@ -30,6 +30,8 @@ public:
|
|||||||
virtual void set_light_mode(bool mode);
|
virtual void set_light_mode(bool mode);
|
||||||
protected:
|
protected:
|
||||||
ncnn::Net* net_;
|
ncnn::Net* net_;
|
||||||
|
ncnn::PoolAllocator workspace_allocator_;
|
||||||
|
ncnn::UnlockedPoolAllocator blob_allocator_;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
bool light_mode_ = true;
|
bool light_mode_ = true;
|
||||||
};
|
};
|
||||||
|
@@ -30,7 +30,4 @@ Estimator* UltralightEstimatorFactory::CreateEstimator() {
|
|||||||
return new UltralightEstimator();
|
return new UltralightEstimator();
|
||||||
}
|
}
|
||||||
|
|
||||||
Estimator* MoveNetFactory::CreateEstimator(const int model_type) {
|
|
||||||
return new MoveNet(model_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -25,11 +25,5 @@ public:
|
|||||||
Estimator* CreateEstimator();
|
Estimator* CreateEstimator();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MoveNetFactory: public EstimatorFactory {
|
|
||||||
public:
|
|
||||||
MoveNetFactory(const int model_type) {}
|
|
||||||
~MoveNetFactory() {}
|
|
||||||
Estimator* CreateEstimator(const int model_type);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
#endif // !_POSE_ESTIMATOR_H
|
#endif // !_POSE_ESTIMATOR_H
|
||||||
|
24
src/pose/segmentor.h
Normal file
24
src/pose/segmentor.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _POSE_SEGMENTOR_C_H_
|
||||||
|
#define _POSE_SEGMENTOR_C_H_
|
||||||
|
|
||||||
|
#include "../common/common.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include "segmentor/segmentor.hpp"
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
typedef void* IPoseSegmentor;
|
||||||
|
IPoseSegmentor new_deeplabv3plus_pose_segmentor();
|
||||||
|
IPoseSegmentor new_erdnet_pose_segmentor();
|
||||||
|
int pose_segment_matting(IPoseSegmentor s, const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out);
|
||||||
|
int pose_segment_merge(IPoseSegmentor s, const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char* bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // !_POSE_SEGMENTOR_C_H_
|
87
src/pose/segmentor/deeplabv3plus/deeplabv3plus.cpp
Normal file
87
src/pose/segmentor/deeplabv3plus/deeplabv3plus.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "deeplabv3plus.hpp"
|
||||||
|
|
||||||
|
#ifdef OV_VULKAN
|
||||||
|
#include "gpu.h"
|
||||||
|
#endif // OV_VULKAN
|
||||||
|
|
||||||
|
namespace ovpose {
|
||||||
|
|
||||||
|
int Deeplabv3plusSegmentor::Matting(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out) {
|
||||||
|
|
||||||
|
ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, img_width, img_height, target_size, target_size);
|
||||||
|
ncnn::Mat matting = ncnn::Mat(target_size, target_size, 3);
|
||||||
|
|
||||||
|
in.substract_mean_normalize(mean_vals, norm_vals);
|
||||||
|
ncnn::Extractor ex = net_->create_extractor();
|
||||||
|
ex.set_light_mode(light_mode_);
|
||||||
|
ex.set_num_threads(num_threads);
|
||||||
|
|
||||||
|
ex.input("input", in);
|
||||||
|
ncnn::Mat output;
|
||||||
|
ex.extract("output", output);
|
||||||
|
|
||||||
|
const float* pCls0 = output.channel(0);
|
||||||
|
const float* pCls1 = output.channel(1);
|
||||||
|
|
||||||
|
for (int c = 0; c < 3; c++)
|
||||||
|
{
|
||||||
|
float* pImage = matting.channel(c);
|
||||||
|
for (int i = 0; i < target_size*target_size; i++){
|
||||||
|
pImage[i] = pCls0[i] < pCls1[i] ? 255 : pImage[i] * 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ncnn::Mat outimg;
|
||||||
|
ncnn::resize_bicubic(matting, outimg, img_width, img_height);
|
||||||
|
out->width = outimg.w;
|
||||||
|
out->height = outimg.h;
|
||||||
|
out->channels = outimg.c;
|
||||||
|
out->data = (unsigned char*)malloc(outimg.total());
|
||||||
|
outimg.to_pixels(out->data, ncnn::Mat::PIXEL_RGB);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Deeplabv3plusSegmentor::Merge(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char*bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out) {
|
||||||
|
|
||||||
|
ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, img_width, img_height, target_size, target_size);
|
||||||
|
ncnn::Mat bg = ncnn::Mat::from_pixels_resize(bgdata, ncnn::Mat::PIXEL_RGB, bg_width, bg_height, target_size, target_size);
|
||||||
|
ncnn::Mat matting = in.clone();
|
||||||
|
|
||||||
|
in.substract_mean_normalize(mean_vals, norm_vals);
|
||||||
|
ncnn::Extractor ex = net_->create_extractor();
|
||||||
|
ex.set_light_mode(light_mode_);
|
||||||
|
ex.set_num_threads(num_threads);
|
||||||
|
|
||||||
|
ex.input("input", in);
|
||||||
|
ncnn::Mat output;
|
||||||
|
ex.extract("output", output);
|
||||||
|
|
||||||
|
const float* pCls0 = output.channel(0);
|
||||||
|
const float* pCls1 = output.channel(1);
|
||||||
|
|
||||||
|
for (int c = 0; c < 3; c++)
|
||||||
|
{
|
||||||
|
float* pImage = matting.channel(c);
|
||||||
|
for (int i = 0; i < target_size*target_size; i++){
|
||||||
|
if (pCls0[i] >= pCls1[i]) {
|
||||||
|
pImage[i] = bg.channel(c)[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ncnn::Mat outimg;
|
||||||
|
ncnn::resize_bicubic(matting, outimg, img_width, img_height);
|
||||||
|
out->width = outimg.w;
|
||||||
|
out->height = outimg.h;
|
||||||
|
out->channels = outimg.c;
|
||||||
|
out->data = (unsigned char*)malloc(outimg.total());
|
||||||
|
outimg.to_pixels(out->data, ncnn::Mat::PIXEL_RGB);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
26
src/pose/segmentor/deeplabv3plus/deeplabv3plus.hpp
Normal file
26
src/pose/segmentor/deeplabv3plus/deeplabv3plus.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _POSE_SEGMENTOR_DEEPLABV3PLUS_H_
|
||||||
|
#define _POSE_SEGMENTOR_DEEPLABV3PLUS_H_
|
||||||
|
|
||||||
|
#include "../segmentor.hpp"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
namespace ovpose {
|
||||||
|
|
||||||
|
class Deeplabv3plusSegmentor : public Segmentor {
|
||||||
|
public:
|
||||||
|
virtual int Matting(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out);
|
||||||
|
virtual int Merge(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char* bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out);
|
||||||
|
private:
|
||||||
|
const int target_size = 640;
|
||||||
|
const float mean_vals[3] = {0.45734706f * 255.f, 0.43338275f * 255.f, 0.40058118f*255.f};
|
||||||
|
const float norm_vals[3] = {1/0.23965294/255.f, 1/0.23532275/255.f, 1/0.2398498/255.f};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // !_POSE_SEGMENTOR_DEEPLABV3PLUS_H_
|
87
src/pose/segmentor/erdnet/erdnet.cpp
Normal file
87
src/pose/segmentor/erdnet/erdnet.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "erdnet.hpp"
|
||||||
|
|
||||||
|
#ifdef OV_VULKAN
|
||||||
|
#include "gpu.h"
|
||||||
|
#endif // OV_VULKAN
|
||||||
|
|
||||||
|
namespace ovpose {
|
||||||
|
|
||||||
|
int ERDNetSegmentor::Matting(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out) {
|
||||||
|
|
||||||
|
ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, img_width, img_height, target_size, target_size);
|
||||||
|
ncnn::Mat matting = ncnn::Mat(target_size, target_size, 3);
|
||||||
|
|
||||||
|
in.substract_mean_normalize(mean_vals, norm_vals);
|
||||||
|
ncnn::Extractor ex = net_->create_extractor();
|
||||||
|
ex.set_light_mode(light_mode_);
|
||||||
|
ex.set_num_threads(num_threads);
|
||||||
|
|
||||||
|
ex.input("input_blob1", in);
|
||||||
|
ncnn::Mat output;
|
||||||
|
ex.extract("sigmoid_blob1", output);
|
||||||
|
|
||||||
|
for (int c = 0; c < 3; ++c) {
|
||||||
|
float* pImage = matting.channel(c);
|
||||||
|
for (int i = 0; i < target_size*target_size; i++) {
|
||||||
|
const float alpha = output[i];
|
||||||
|
float value = 255 * alpha;
|
||||||
|
value = std::max(std::min(value, 255.f), 0.f);
|
||||||
|
pImage[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ncnn::Mat outimg;
|
||||||
|
ncnn::resize_bicubic(matting, outimg, img_width, img_height);
|
||||||
|
|
||||||
|
out->width = outimg.w;
|
||||||
|
out->height = outimg.h;
|
||||||
|
out->channels = outimg.c;
|
||||||
|
out->data = (unsigned char*)malloc(outimg.total());
|
||||||
|
outimg.to_pixels(out->data, ncnn::Mat::PIXEL_RGB);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ERDNetSegmentor::Merge(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char* bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out) {
|
||||||
|
|
||||||
|
ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, img_width, img_height, target_size, target_size);
|
||||||
|
ncnn::Mat bg = ncnn::Mat::from_pixels_resize(bgdata, ncnn::Mat::PIXEL_RGB, bg_width, bg_height, target_size, target_size);
|
||||||
|
ncnn::Mat matting = in.clone();
|
||||||
|
|
||||||
|
in.substract_mean_normalize(mean_vals, norm_vals);
|
||||||
|
ncnn::Extractor ex = net_->create_extractor();
|
||||||
|
ex.set_light_mode(light_mode_);
|
||||||
|
ex.set_num_threads(num_threads);
|
||||||
|
|
||||||
|
ex.input("input_blob1", in);
|
||||||
|
ncnn::Mat output;
|
||||||
|
ex.extract("sigmoid_blob1", output);
|
||||||
|
|
||||||
|
for (int c = 0; c < 3; ++c) {
|
||||||
|
float* pImage = matting.channel(c);
|
||||||
|
for (int i = 0; i < target_size*target_size; i++) {
|
||||||
|
const float alpha = output[i];
|
||||||
|
float value = pImage[i] * alpha + bg.channel(c)[i] * (1 - alpha);
|
||||||
|
value = std::max(std::min(value, 255.f), 0.f);
|
||||||
|
pImage[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ncnn::Mat outimg;
|
||||||
|
ncnn::resize_bicubic(matting, outimg, img_width, img_height);
|
||||||
|
|
||||||
|
out->width = outimg.w;
|
||||||
|
out->height = outimg.h;
|
||||||
|
out->channels = outimg.c;
|
||||||
|
out->data = (unsigned char*)malloc(outimg.total());
|
||||||
|
outimg.to_pixels(out->data, ncnn::Mat::PIXEL_RGB);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
src/pose/segmentor/erdnet/erdnet.hpp
Normal file
26
src/pose/segmentor/erdnet/erdnet.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _POSE_SEGMENTOR_ERDNET_H_
|
||||||
|
#define _POSE_SEGMENTOR_ERDNET_H_
|
||||||
|
|
||||||
|
#include "../segmentor.hpp"
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
namespace ovpose {
|
||||||
|
|
||||||
|
class ERDNetSegmentor : public Segmentor {
|
||||||
|
public:
|
||||||
|
virtual int Matting(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out);
|
||||||
|
virtual int Merge(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char* bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out);
|
||||||
|
private:
|
||||||
|
const int target_size = 256;
|
||||||
|
const float mean_vals[3] = {104.f, 112.f, 121.f};
|
||||||
|
const float norm_vals[3] = {1.f/255.f, 1.f/255.f, 1.f/255.f};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // !_POSE_SEGMENTOR_ERDNET_H_
|
45
src/pose/segmentor/segmentor.cpp
Normal file
45
src/pose/segmentor/segmentor.cpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#include "../segmentor.h"
|
||||||
|
#include "deeplabv3plus/deeplabv3plus.hpp"
|
||||||
|
#include "erdnet/erdnet.hpp"
|
||||||
|
|
||||||
|
IPoseSegmentor new_deeplabv3plus_pose_segmentor() {
|
||||||
|
return new ovpose::Deeplabv3plusSegmentor();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPoseSegmentor new_erdnet_pose_segmentor() {
|
||||||
|
return new ovpose::ERDNetSegmentor();
|
||||||
|
}
|
||||||
|
|
||||||
|
int pose_segment_matting(IPoseSegmentor s, const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out) {
|
||||||
|
int ret = static_cast<ovpose::Segmentor*>(s)->Matting(rgbdata, img_width, img_height, out);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pose_segment_merge(IPoseSegmentor s, const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char* bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out) {
|
||||||
|
int ret = static_cast<ovpose::Segmentor*>(s)->Merge(rgbdata, img_width, img_height, bgdata, bg_width, bg_height, out);
|
||||||
|
if (ret != 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ovpose {
|
||||||
|
|
||||||
|
Segmentor* Deeplabv3plusFactory::CreateSegmentor() {
|
||||||
|
return new Deeplabv3plusSegmentor();
|
||||||
|
}
|
||||||
|
|
||||||
|
Segmentor* ERDNetFactory::CreateSegmentor() {
|
||||||
|
return new ERDNetSegmentor();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
src/pose/segmentor/segmentor.hpp
Normal file
42
src/pose/segmentor/segmentor.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef _POSE_SEGMENTOR_H_
|
||||||
|
#define _POSE_SEGMENTOR_H_
|
||||||
|
|
||||||
|
#include "../../common/common.h"
|
||||||
|
|
||||||
|
namespace ovpose {
|
||||||
|
|
||||||
|
class Segmentor: public ov::Estimator {
|
||||||
|
public:
|
||||||
|
virtual int Matting(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
Image* out) = 0;
|
||||||
|
virtual int Merge(const unsigned char* rgbdata,
|
||||||
|
int img_width, int img_height,
|
||||||
|
const unsigned char* bgdata,
|
||||||
|
int bg_width, int bg_height,
|
||||||
|
Image* out) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SegmentorFactory {
|
||||||
|
public:
|
||||||
|
virtual Segmentor* CreateSegmentor() = 0;
|
||||||
|
virtual ~SegmentorFactory() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Deeplabv3plusFactory: public SegmentorFactory{
|
||||||
|
public:
|
||||||
|
Deeplabv3plusFactory() {}
|
||||||
|
~Deeplabv3plusFactory() {}
|
||||||
|
Segmentor* CreateSegmentor();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ERDNetFactory: public SegmentorFactory{
|
||||||
|
public:
|
||||||
|
ERDNetFactory() {}
|
||||||
|
~ERDNetFactory() {}
|
||||||
|
Segmentor* CreateSegmentor();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //!_POSE_SEGMENTOR_H_
|
Reference in New Issue
Block a user