mirror of
				https://github.com/bububa/openvision.git
				synced 2025-10-31 08:46:21 +08:00 
			
		
		
		
	feat(face): add scrfd face detecter/landmarker
This commit is contained in:
		
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							| @@ -22,12 +22,14 @@ cmake .. # optional -DNCNN_VULKAN=OFF -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COM | ||||
|     - centerface [Google Drive](https://drive.google.com/drive/folders/1xMhO6aCnkkjt90Fh8BxVD_JHB3QJ2q-q?usp=sharing) | ||||
|     - retainface [Google Drive](https://drive.google.com/drive/folders/1nxR3WFqqEWLwGVsp5c4tI0_iVVEaVOe8?usp=sharing) | ||||
|     - yoloface [Google Drive](https://drive.google.com/drive/folders/1EM9H6-aYXKsWTRxx_wbKDyYHVIYpU6f7?usp=sharing) | ||||
|     - scrfd [Google Drive](https://drive.google.com/drive/folders/1XPjfsuXGj9rXqAmo1K70BsqWmHvoYQv_?usp=sharing) | ||||
|     - anticonv (for mask detection) [Google Drive](https://drive.google.com/drive/folders/1Fje0fmVPy5g0_oaxUbH_cAedkgjBf7QW?usp=sharing) | ||||
|   - recognizer (face feature extration for classification) | ||||
|     - mobilenet [Google Drive](https://drive.google.com/drive/folders/1fRLs10atm_vwDWQXZ-GJbKQpypNcXLAx?usp=sharing) | ||||
|   - landmarker (for face landmarkers extraction) | ||||
|     - insightface [Google Drive](https://drive.google.com/drive/folders/1e_nRwneMEDf_sXEMZCmOk0S4VT0_XpOS?usp=sharing) | ||||
|     - zq [Google Drive](https://drive.google.com/drive/folders/1ax0J1TVhf2S-B3V6lnqwJaaHUK433sPm?usp=sharing) | ||||
|     - scrfd [Google Drive](https://drive.google.com/drive/folders/1XPjfsuXGj9rXqAmo1K70BsqWmHvoYQv_?usp=sharing) | ||||
|   - 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 | ||||
| @@ -40,3 +42,14 @@ cmake .. # optional -DNCNN_VULKAN=OFF -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COM | ||||
|   - pose (for hand pose estimation) | ||||
|     - handnet [Google Drive](https://drive.google.com/drive/folders/1DsCGmiVaZobbMWRp5Oec8GbIpeg7CsNR?usp=sharing) | ||||
| - golang binding (github.com/bububa/openvision/go) | ||||
|  | ||||
| ## Reference | ||||
|  | ||||
| - [MirrorYuChen/ncnn_example](https://github.com/MirrorYuChen/ncnn_example) | ||||
| - [nihui/ncnn-android-nanodet](https://github.com/nihui/ncnn-android-nanodet) | ||||
| - [FeiGeChuanShu/ncnn_Android_face](https://github.com/FeiGeChuanShu/ncnn_Android_face) | ||||
| - [FeiGeChuanShu/ncnn_nanodet_hand](https://github.com/FeiGeChuanShu/ncnn_nanodet_hand) | ||||
| - [docongminh/deep-head-pose-ncnn](https://github.com/docongminh/deep-head-pose-ncnn) | ||||
| - [nilseuropa/hopenet_ncnn](https://github.com/nilseuropa/hopenet_ncnn) | ||||
| - [dog-qiuqiu/Ultralight-SimplePose](https://github.com/dog-qiuqiu/Ultralight-SimplePose) | ||||
| - [GHLab/deep-head-pose-lite-ncnn](https://github.com/GHLab/deep-head-pose-lite-ncnn) | ||||
|   | ||||
							
								
								
									
										41
									
								
								go/common/estimator.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								go/common/estimator.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| package common | ||||
|  | ||||
| /* | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include "openvision/common/common.h" | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	openvision "github.com/bububa/openvision/go" | ||||
| ) | ||||
|  | ||||
| // Estimator represents Estimator interface | ||||
| type Estimator interface { | ||||
| 	LoadModel(modelPath string) error | ||||
| 	Destroy() | ||||
| 	Pointer() unsafe.Pointer | ||||
| } | ||||
|  | ||||
| // SetEstimatorThreads set ncnn net opt.num_threads | ||||
| func SetEstimatorThreads(e Estimator, n int) { | ||||
| 	C.set_num_threads((C.IEstimator)(e.Pointer()), C.int(n)) | ||||
| } | ||||
|  | ||||
| // DestroyEstimator destory an Estimator | ||||
| func DestroyEstimator(e Estimator) { | ||||
| 	C.destroy_estimator((C.IEstimator)(e.Pointer())) | ||||
| } | ||||
|  | ||||
| // EstimatorLoadModel load detecter model | ||||
| func EstimatorLoadModel(e Estimator, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(e.Pointer()), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -7,16 +7,29 @@ package common | ||||
| */ | ||||
| import "C" | ||||
|  | ||||
| // GetGPUCount get gpu number | ||||
| func GetGPUCount() int { | ||||
| 	count := C.get_gpu_count() | ||||
| 	return int(count) | ||||
| } | ||||
|  | ||||
| // CreateGPUInstance create gpu instance | ||||
| func CreateGPUInstance() int { | ||||
| 	i := C.create_gpu_instance() | ||||
| 	return int(i) | ||||
| } | ||||
|  | ||||
| // DestroyGPUInstance destory gpu instance | ||||
| func DestroyGPUInstance() { | ||||
| 	C.destroy_gpu_instance() | ||||
| } | ||||
|  | ||||
| // GetBigCPUCount get cpu number | ||||
| func GetBigCPUCount() int { | ||||
| 	return int(C.get_big_cpu_count()) | ||||
| } | ||||
|  | ||||
| // SetOMPThreads set omp thread number | ||||
| func SetOMPThreads(n int) { | ||||
| 	C.set_omp_num_threads(C.int(n)) | ||||
| } | ||||
|   | ||||
| @@ -22,14 +22,14 @@ type Keypoint struct { | ||||
| func GoKeypoint(c *C.Keypoint, w float64, h float64) Keypoint { | ||||
| 	return Keypoint{ | ||||
| 		Point: Pt(float64(c.p.x)/w, float64(c.p.y)/h), | ||||
| 		Score: float32(c.prob), | ||||
| 		Score: float32(c.score), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Convert Keypoint to C.Keypoint pointer | ||||
| func (k Keypoint) CKeypoint(w float64, h float64) *C.Keypoint { | ||||
| 	ret := (*C.Keypoint)(C.malloc(C.sizeof_Keypoint)) | ||||
| 	ret.prob = C.float(k.Score) | ||||
| 	ret.score = C.float(k.Score) | ||||
| 	ret.p = C.Point2f{ | ||||
| 		C.float(k.Point.X * w), | ||||
| 		C.float(k.Point.Y * h), | ||||
|   | ||||
| @@ -26,7 +26,7 @@ type ObjectInfo struct { | ||||
| func GoObjectInfo(c *C.ObjectInfo, w float64, h float64) ObjectInfo { | ||||
| 	ret := ObjectInfo{ | ||||
| 		Label: int(c.label), | ||||
| 		Score: float32(c.prob), | ||||
| 		Score: float32(c.score), | ||||
| 		Rect: Rect( | ||||
| 			float64(c.rect.x)/w, | ||||
| 			float64(c.rect.y)/h, | ||||
| @@ -44,7 +44,7 @@ func GoObjectInfo(c *C.ObjectInfo, w float64, h float64) ObjectInfo { | ||||
| func (o ObjectInfo) ToCObjectInfo(w float64, h float64) *C.ObjectInfo { | ||||
| 	ret := (*C.ObjectInfo)(C.malloc(C.sizeof_ObjectInfo)) | ||||
| 	ret.label = C.int(o.Label) | ||||
| 	ret.prob = C.float(o.Score) | ||||
| 	ret.score = C.float(o.Score) | ||||
| 	ret.rect.x = C.int(o.Rect.X * w) | ||||
| 	ret.rect.y = C.int(o.Rect.Y * h) | ||||
| 	ret.rect.width = C.int(o.Rect.Width * w) | ||||
|   | ||||
| @@ -23,24 +23,30 @@ func main() { | ||||
| 	modelPath := filepath.Join(dataPath, "./models") | ||||
| 	common.CreateGPUInstance() | ||||
| 	defer common.DestroyGPUInstance() | ||||
| 	test_detect(imgPath, modelPath) | ||||
| 	test_mask(imgPath, modelPath) | ||||
| 	cpuCores := common.GetBigCPUCount() | ||||
| 	common.SetOMPThreads(cpuCores) | ||||
| 	log.Printf("CPU big cores:%d\n", cpuCores) | ||||
| 	test_detect(imgPath, modelPath, cpuCores) | ||||
| 	test_mask(imgPath, modelPath, cpuCores) | ||||
| } | ||||
|  | ||||
| func test_detect(imgPath string, modelPath string) { | ||||
| func test_detect(imgPath string, modelPath string, threads int) { | ||||
| 	for idx, d := range []detecter.Detecter{ | ||||
| 		retinaface(modelPath), | ||||
| 		centerface(modelPath), | ||||
| 		mtcnn(modelPath), | ||||
| 		yoloface(modelPath), | ||||
| 		scrfd(modelPath), | ||||
| 	} { | ||||
| 		common.SetEstimatorThreads(d, threads) | ||||
| 		detect(d, imgPath, idx, "4.jpg", false) | ||||
| 		d.Destroy() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func test_mask(imgPath string, modelPath string) { | ||||
| func test_mask(imgPath string, modelPath string, threads int) { | ||||
| 	d := anticonv(modelPath) | ||||
| 	common.SetEstimatorThreads(d, threads) | ||||
| 	defer d.Destroy() | ||||
| 	detect(d, imgPath, 0, "mask3.jpg", true) | ||||
| } | ||||
| @@ -72,6 +78,15 @@ func yoloface(modelPath string) detecter.Detecter { | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func scrfd(modelPath string) detecter.Detecter { | ||||
| 	modelPath = filepath.Join(modelPath, "scrfd/scrfd1g") | ||||
| 	d := detecter.NewScrfd() | ||||
| 	if err := d.LoadModel(modelPath); err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func centerface(modelPath string) detecter.Detecter { | ||||
| 	modelPath = filepath.Join(modelPath, "centerface") | ||||
| 	d := detecter.NewCenterface() | ||||
| @@ -96,7 +111,7 @@ func detect(d detecter.Detecter, imgPath string, idx int, filename string, mask | ||||
| 	if err != nil { | ||||
| 		log.Fatalln("load image failed,", err) | ||||
| 	} | ||||
| 	faces, err := d.DetectFace(common.NewImage(img)) | ||||
| 	faces, err := d.Detect(common.NewImage(img)) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|   | ||||
| @@ -24,13 +24,19 @@ func main() { | ||||
| 	modelPath := filepath.Join(dataPath, "./models") | ||||
| 	common.CreateGPUInstance() | ||||
| 	defer common.DestroyGPUInstance() | ||||
| 	cpuCores := common.GetBigCPUCount() | ||||
| 	common.SetOMPThreads(cpuCores) | ||||
| 	log.Printf("CPU big cores:%d\n", cpuCores) | ||||
| 	estimator := handpose(modelPath) | ||||
| 	defer estimator.Destroy() | ||||
| 	common.SetEstimatorThreads(estimator, cpuCores) | ||||
| 	for idx, d := range []detecter.Detecter{ | ||||
| 		yolox(modelPath), nanodet(modelPath), | ||||
| 		yolox(modelPath), | ||||
| 		nanodet(modelPath), | ||||
| 	} { | ||||
| 		defer d.Destroy() | ||||
| 		detect(d, estimator, imgPath, "hand2.jpg", idx) | ||||
| 		common.SetEstimatorThreads(d, cpuCores) | ||||
| 		detect(d, estimator, imgPath, "hand1.jpg", idx) | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -24,10 +24,15 @@ func main() { | ||||
| 	modelPath := filepath.Join(dataPath, "./models") | ||||
| 	common.CreateGPUInstance() | ||||
| 	defer common.DestroyGPUInstance() | ||||
| 	cpuCores := common.GetBigCPUCount() | ||||
| 	common.SetOMPThreads(cpuCores) | ||||
| 	log.Printf("CPU big cores:%d\n", cpuCores) | ||||
| 	d := retinaface(modelPath) | ||||
| 	defer d.Destroy() | ||||
| 	common.SetEstimatorThreads(d, cpuCores) | ||||
| 	h := processer(modelPath) | ||||
| 	defer h.Destroy() | ||||
| 	common.SetEstimatorThreads(h, cpuCores) | ||||
| 	for _, fn := range []string{"robocop.jpg", "terminator.jpg"} { | ||||
| 		process(d, h, imgPath, fn) | ||||
| 	} | ||||
| @@ -60,7 +65,7 @@ func process(d detecter.Detecter, h *hopenet.Hopenet, imgPath string, filename s | ||||
| 		log.Fatalln("load image failed,", err) | ||||
| 	} | ||||
| 	img := common.NewImage(imgLoaded) | ||||
| 	faces, err := d.DetectFace(img) | ||||
| 	faces, err := d.Detect(img) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"image" | ||||
| 	"image/jpeg" | ||||
| 	"log" | ||||
| @@ -23,11 +24,21 @@ func main() { | ||||
| 	modelPath := filepath.Join(dataPath, "./models") | ||||
| 	common.CreateGPUInstance() | ||||
| 	defer common.DestroyGPUInstance() | ||||
| 	cpuCores := common.GetBigCPUCount() | ||||
| 	common.SetOMPThreads(cpuCores) | ||||
| 	log.Printf("CPU big cores:%d\n", cpuCores) | ||||
| 	d := retinaface(modelPath) | ||||
| 	defer d.Destroy() | ||||
| 	m := insightface(modelPath) | ||||
| 	defer m.Destroy() | ||||
| 	extract_keypoints(d, m, imgPath, "4.jpg") | ||||
| 	common.SetEstimatorThreads(d, cpuCores) | ||||
| 	for idx, m := range []landmarker.Landmarker{ | ||||
| 		insightface(modelPath), | ||||
| 		zq(modelPath), | ||||
| 		scrfd(modelPath), | ||||
| 	} { | ||||
| 		defer m.Destroy() | ||||
| 		common.SetEstimatorThreads(m, cpuCores) | ||||
| 		extract_keypoints(d, m, imgPath, "4.jpg", idx) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func retinaface(modelPath string) detecter.Detecter { | ||||
| @@ -57,14 +68,23 @@ func zq(modelPath string) landmarker.Landmarker { | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func extract_keypoints(d detecter.Detecter, m landmarker.Landmarker, imgPath string, filename string) { | ||||
| func scrfd(modelPath string) landmarker.Landmarker { | ||||
| 	modelPath = filepath.Join(modelPath, "scrfd/landmarker") | ||||
| 	d := landmarker.NewScrfd() | ||||
| 	if err := d.LoadModel(modelPath); err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func extract_keypoints(d detecter.Detecter, m landmarker.Landmarker, 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) | ||||
| 	faces, err := d.DetectFace(img) | ||||
| 	faces, err := d.Detect(img) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
| @@ -83,8 +103,7 @@ func extract_keypoints(d detecter.Detecter, m landmarker.Landmarker, imgPath str | ||||
| 		keypoints = append(keypoints, points...) | ||||
| 	} | ||||
| 	out := drawer.DrawLandmark(imgLoaded, keypoints) | ||||
| 	outPath := filepath.Join(imgPath, "./results", filename) | ||||
|  | ||||
| 	outPath := filepath.Join(imgPath, "./results", fmt.Sprintf("landmarker-%d-%s", idx, filename)) | ||||
| 	if err := saveImage(out, outPath); err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|   | ||||
| @@ -23,8 +23,12 @@ func main() { | ||||
| 	modelPath := filepath.Join(dataPath, "./models") | ||||
| 	common.CreateGPUInstance() | ||||
| 	defer common.DestroyGPUInstance() | ||||
| 	cpuCores := common.GetBigCPUCount() | ||||
| 	common.SetOMPThreads(cpuCores) | ||||
| 	log.Printf("CPU big cores:%d\n", cpuCores) | ||||
| 	d := ultralightDetector(modelPath) | ||||
| 	defer d.Destroy() | ||||
| 	common.SetEstimatorThreads(d, cpuCores) | ||||
| 	detect(d, imgPath, "ultralight-pose3.jpg") | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -22,10 +22,15 @@ func main() { | ||||
| 	modelPath := filepath.Join(dataPath, "./models") | ||||
| 	common.CreateGPUInstance() | ||||
| 	defer common.DestroyGPUInstance() | ||||
| 	cpuCores := common.GetBigCPUCount() | ||||
| 	common.SetOMPThreads(cpuCores) | ||||
| 	log.Printf("CPU big cores:%d\n", cpuCores) | ||||
| 	d := retinaface(modelPath) | ||||
| 	defer d.Destroy() | ||||
| 	common.SetEstimatorThreads(d, cpuCores) | ||||
| 	m := mobilefacenet(modelPath) | ||||
| 	defer m.Destroy() | ||||
| 	common.SetEstimatorThreads(m, cpuCores) | ||||
| 	extract_features(d, m, imgPath, "4.jpg") | ||||
| } | ||||
|  | ||||
| @@ -54,7 +59,7 @@ func extract_features(d detecter.Detecter, r recognizer.Recognizer, imgPath stri | ||||
| 		log.Fatalln("load image failed,", err) | ||||
| 	} | ||||
| 	img := common.NewImage(imgLoaded) | ||||
| 	faces, err := d.DetectFace(img) | ||||
| 	faces, err := d.Detect(img) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|   | ||||
| @@ -48,7 +48,7 @@ func track(d detecter.Detecter, t *tracker.Tracker, imgPath string, filename str | ||||
| 		log.Fatalln("load image failed,", err) | ||||
| 	} | ||||
| 	img := common.NewImage(imgLoaded) | ||||
| 	faces, err := d.DetectFace(img) | ||||
| 	faces, err := d.Detect(img) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
| 	} | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| 	"github.com/bububa/openvision/go/face" | ||||
| ) | ||||
| @@ -25,20 +27,20 @@ func NewAnticonv() *Anticonv { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Anticonv) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IDetecter | ||||
| func (d *Anticonv) Handler() C.IFaceDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Anticonv) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load model for detecter | ||||
| func (d *Anticonv) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // DetectFace implement Detecter interface | ||||
| func (d *Anticonv) DetectFace(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return DetectFace(d, img) | ||||
| // Detect implement Detecter interface | ||||
| func (d *Anticonv) Detect(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return Detect(d, img) | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| 	"github.com/bububa/openvision/go/face" | ||||
| ) | ||||
| @@ -25,20 +27,20 @@ func NewCenterface() *Centerface { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Centerface) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IDetecter | ||||
| func (d *Centerface) Handler() C.IFaceDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Centerface) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load model for detecter | ||||
| func (d *Centerface) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // DetectFace implement Detecter interface | ||||
| func (d *Centerface) DetectFace(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return DetectFace(d, img) | ||||
| // Detect implement Detecter interface | ||||
| func (d *Centerface) Detect(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return Detect(d, img) | ||||
| } | ||||
|   | ||||
| @@ -17,36 +17,18 @@ import ( | ||||
|  | ||||
| // Detecter represents deteter interface | ||||
| type Detecter interface { | ||||
| 	Handler() C.IFaceDetecter | ||||
| 	LoadModel(modelPath string) error | ||||
| 	DetectFace(img *common.Image) ([]face.FaceInfo, error) | ||||
| 	Destroy() | ||||
| 	common.Estimator | ||||
| 	Detect(img *common.Image) ([]face.FaceInfo, error) | ||||
| } | ||||
|  | ||||
| // LoadModel load detecter model | ||||
| func LoadModel(d Detecter, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(d.Handler())), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy a detecter | ||||
| func Destroy(d Detecter) { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(d.Handler()))) | ||||
| } | ||||
|  | ||||
| // DetectFace detect face useing detecter | ||||
| func DetectFace(d Detecter, img *common.Image) ([]face.FaceInfo, error) { | ||||
| // Detect detect face useing detecter | ||||
| func Detect(d Detecter, img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	imgWidth := img.WidthF64() | ||||
| 	imgHeight := img.HeightF64() | ||||
| 	data := img.Bytes() | ||||
| 	CFaces := face.NewCFaceInfoVector() | ||||
| 	defer face.FreeCFaceInfoVector(CFaces) | ||||
| 	errCode := C.detect_face(d.Handler(), (*C.uchar)(unsafe.Pointer(&data[0])), C.int(imgWidth), C.int(imgHeight), (*C.FaceInfoVector)(unsafe.Pointer(CFaces))) | ||||
| 	errCode := C.detect_face((C.IFaceDetecter)(d.Pointer()), (*C.uchar)(unsafe.Pointer(&data[0])), C.int(imgWidth), C.int(imgHeight), (*C.FaceInfoVector)(unsafe.Pointer(CFaces))) | ||||
| 	if errCode != 0 { | ||||
| 		return nil, openvision.DetectFaceError(int(errCode)) | ||||
| 	} | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| 	"github.com/bububa/openvision/go/face" | ||||
| ) | ||||
| @@ -25,20 +27,20 @@ func NewMtcnn() *Mtcnn { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Mtcnn) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IFaceDetecter | ||||
| func (d *Mtcnn) Handler() C.IFaceDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Mtcnn) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Detecter interface | ||||
| func (d *Mtcnn) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // DetectFace implement Detecter interface | ||||
| func (d *Mtcnn) DetectFace(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return DetectFace(d, img) | ||||
| // Detect implement Detecter interface | ||||
| func (d *Mtcnn) Detect(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return Detect(d, img) | ||||
| } | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| 	"github.com/bububa/openvision/go/face" | ||||
| ) | ||||
| @@ -25,19 +27,20 @@ func NewRetinaFace() *RetinaFace { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *RetinaFace) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IFaceDetecter | ||||
| func (d *RetinaFace) Handler() C.IFaceDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *RetinaFace) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Detecter interface | ||||
| func (d *RetinaFace) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| func (d *RetinaFace) DetectFace(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return DetectFace(d, img) | ||||
| // Detect implement Detecter interface | ||||
| func (d *RetinaFace) Detect(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return Detect(d, img) | ||||
| } | ||||
|   | ||||
							
								
								
									
										46
									
								
								go/face/detecter/scrfd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								go/face/detecter/scrfd.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| package detecter | ||||
|  | ||||
| /* | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include "openvision/face/detecter.h" | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| 	"github.com/bububa/openvision/go/face" | ||||
| ) | ||||
|  | ||||
| // Scrfd represents scrfd detecter | ||||
| type Scrfd struct { | ||||
| 	d C.IFaceDetecter | ||||
| } | ||||
|  | ||||
| // NewScrfd returns a new Scrfd | ||||
| func NewScrfd() *Scrfd { | ||||
| 	return &Scrfd{ | ||||
| 		d: C.new_scrfd(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Scrfd) Destroy() { | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Detecter interface | ||||
| func (d *Scrfd) LoadModel(modelPath string) error { | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Scrfd) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // Detect implement Detecter interface | ||||
| func (d *Scrfd) Detect(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return Detect(d, img) | ||||
| } | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| 	"github.com/bububa/openvision/go/face" | ||||
| ) | ||||
| @@ -25,20 +27,20 @@ func NewYoloFace() *YoloFace { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *YoloFace) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IFaceDetecter | ||||
| func (d *YoloFace) Handler() C.IFaceDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *YoloFace) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Detecter interface | ||||
| func (d *YoloFace) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // DetectFace implement Detecter interface | ||||
| func (d *YoloFace) DetectFace(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return DetectFace(d, img) | ||||
| // Detect implement Detecter interface | ||||
| func (d *YoloFace) Detect(img *common.Image) ([]face.FaceInfo, error) { | ||||
| 	return Detect(d, img) | ||||
| } | ||||
|   | ||||
| @@ -27,13 +27,13 @@ type FaceInfo struct { | ||||
| // GoFaceInfo convert c FaceInfo to go type | ||||
| func GoFaceInfo(cInfo *C.FaceInfo, w float64, h float64) FaceInfo { | ||||
| 	info := FaceInfo{ | ||||
| 		Score: float32(cInfo.score_), | ||||
| 		Score: float32(cInfo.score), | ||||
| 		Mask:  bool(cInfo.mask_), | ||||
| 		Rect: common.Rect( | ||||
| 			float64(cInfo.location_.x)/w, | ||||
| 			float64(cInfo.location_.y)/h, | ||||
| 			float64(cInfo.location_.width)/w, | ||||
| 			float64(cInfo.location_.height)/h, | ||||
| 			float64(cInfo.rect.x)/w, | ||||
| 			float64(cInfo.rect.y)/h, | ||||
| 			float64(cInfo.rect.width)/w, | ||||
| 			float64(cInfo.rect.height)/h, | ||||
| 		), | ||||
| 	} | ||||
| 	for i := 0; i < 5; i++ { | ||||
| @@ -48,9 +48,9 @@ func GoFaceInfo(cInfo *C.FaceInfo, w float64, h float64) FaceInfo { | ||||
| // CFaceInfo convert FaceInfo to C.FaceInfo | ||||
| func (f FaceInfo) CFaceInfo(w float64, h float64) *C.FaceInfo { | ||||
| 	ret := (*C.FaceInfo)(C.malloc(C.sizeof_FaceInfo)) | ||||
| 	ret.score_ = C.float(f.Score) | ||||
| 	ret.score = C.float(f.Score) | ||||
| 	ret.mask_ = C.bool(f.Mask) | ||||
| 	ret.location_ = C.Rect{ | ||||
| 	ret.rect = C.Rect{ | ||||
| 		C.int(f.Rect.X * w), | ||||
| 		C.int(f.Rect.Y * h), | ||||
| 		C.int(f.Rect.Width * w), | ||||
|   | ||||
| @@ -26,20 +26,20 @@ func NewHopenet() *Hopenet { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Pointer implement Estimator interface | ||||
| func (h *Hopenet) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(h.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load detecter model | ||||
| func (h *Hopenet) LoadModel(modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(h.d)), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return common.EstimatorLoadModel(h, modelPath) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy destroy C.IHopeNet | ||||
| func (h *Hopenet) Destroy() { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(h.d))) | ||||
| 	common.DestroyEstimator(h) | ||||
| } | ||||
|  | ||||
| // Detect head pose | ||||
| @@ -51,7 +51,7 @@ func (h *Hopenet) Detect(img *common.Image, faceRect common.Rectangle) (face.Hea | ||||
| 	CHeadPose := face.NewCHeadPose() | ||||
| 	defer C.free(unsafe.Pointer(CHeadPose)) | ||||
| 	errCode := C.hopenet_detect( | ||||
| 		h.d, | ||||
| 		(C.IHopenet)(h.Pointer()), | ||||
| 		(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 		C.int(imgWidth), C.int(imgHeight), | ||||
| 		(*C.Rect)(unsafe.Pointer(CRect)), | ||||
|   | ||||
| @@ -6,7 +6,11 @@ package landmarker | ||||
| #include "openvision/face/landmarker.h" | ||||
| */ | ||||
| import "C" | ||||
| import "github.com/bububa/openvision/go/common" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| // Insightface represents Insightface landmarker | ||||
| type Insightface struct { | ||||
| @@ -20,19 +24,19 @@ func NewInsightface() *Insightface { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Handler returns C.ILandmarker | ||||
| func (d *Insightface) Handler() C.IFaceLandmarker { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Insightface) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Landmarker interface | ||||
| func (d *Insightface) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Destroy implement Landmarker interface | ||||
| func (d *Insightface) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // ExtractKeypoints implement Landmarker interface | ||||
|   | ||||
| @@ -16,26 +16,8 @@ import ( | ||||
|  | ||||
| // Landmarker represents landmarker interface | ||||
| type Landmarker interface { | ||||
| 	Handler() C.IFaceLandmarker | ||||
| 	LoadModel(modelPath string) error | ||||
| 	common.Estimator | ||||
| 	ExtractKeypoints(img *common.Image, face common.Rectangle) ([]common.Point, error) | ||||
| 	Destroy() | ||||
| } | ||||
|  | ||||
| // LoadModel load landmarker model | ||||
| func LoadModel(d Landmarker, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(d.Handler())), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy a landmarker | ||||
| func Destroy(d Landmarker) { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(d.Handler()))) | ||||
| } | ||||
|  | ||||
| // ExtractKeypoints extract keypoints using landmarker | ||||
| @@ -47,7 +29,7 @@ func ExtractKeypoints(d Landmarker, img *common.Image, faceRect common.Rectangle | ||||
| 	defer common.FreeCPoint2fVector(CPoints) | ||||
| 	CRect := faceRect.CRect(imgWidth, imgHeight) | ||||
| 	errCode := C.extract_face_keypoints( | ||||
| 		d.Handler(), | ||||
| 		(C.IFaceLandmarker)(d.Pointer()), | ||||
| 		(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 		C.int(imgWidth), C.int(imgHeight), | ||||
| 		(*C.Rect)(unsafe.Pointer(CRect)), | ||||
|   | ||||
							
								
								
									
										45
									
								
								go/face/landmarker/scrfd.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								go/face/landmarker/scrfd.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| package landmarker | ||||
|  | ||||
| /* | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include "openvision/face/landmarker.h" | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| // Scrfd represents Scrfd landmarker | ||||
| type Scrfd struct { | ||||
| 	d C.IFaceLandmarker | ||||
| } | ||||
|  | ||||
| // NewScrfd returns a new Scrfd landmarker | ||||
| func NewScrfd() *Scrfd { | ||||
| 	return &Scrfd{ | ||||
| 		d: C.new_scrfd_landmarker(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Scrfd) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Landmarker interface | ||||
| func (d *Scrfd) LoadModel(modelPath string) error { | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Destroy implement Landmarker interface | ||||
| func (d *Scrfd) Destroy() { | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // ExtractKeypoints implement Landmarker interface | ||||
| func (d *Scrfd) ExtractKeypoints(img *common.Image, faceRect common.Rectangle) ([]common.Point, error) { | ||||
| 	return ExtractKeypoints(d, img, faceRect) | ||||
| } | ||||
| @@ -6,7 +6,11 @@ package landmarker | ||||
| #include "openvision/face/landmarker.h" | ||||
| */ | ||||
| import "C" | ||||
| import "github.com/bububa/openvision/go/common" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| // Zq represents Zq landmarker | ||||
| type Zq struct { | ||||
| @@ -20,19 +24,19 @@ func NewZq() *Zq { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Handler returns C.ILandmarker | ||||
| func (d *Zq) Handler() C.IFaceLandmarker { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Zq) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Landmarker interface | ||||
| func (d *Zq) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Destroy implement Landmarker interface | ||||
| func (d *Zq) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // ExtractKeypoints implement Landmarker interface | ||||
|   | ||||
| @@ -6,7 +6,11 @@ package recognizer | ||||
| #include "openvision/face/recognizer.h" | ||||
| */ | ||||
| import "C" | ||||
| import "github.com/bububa/openvision/go/common" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| // Mobilefacenet represents Mobilefacenet recognizer | ||||
| type Mobilefacenet struct { | ||||
| @@ -20,19 +24,19 @@ func NewMobilefacenet() *Mobilefacenet { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Handler returns C.IFaceRecognizer | ||||
| func (d *Mobilefacenet) Handler() C.IFaceRecognizer { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Mobilefacenet) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel implement Recognizer interface | ||||
| func (d *Mobilefacenet) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Destroy implement Recognizer interface | ||||
| func (d *Mobilefacenet) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // ExtractFeatures implement Recognizer interface | ||||
|   | ||||
| @@ -16,26 +16,8 @@ import ( | ||||
|  | ||||
| // Recognizer represents Recognizer interface | ||||
| type Recognizer interface { | ||||
| 	Handler() C.IFaceRecognizer | ||||
| 	LoadModel(modelPath string) error | ||||
| 	common.Estimator | ||||
| 	ExtractFeatures(img *common.Image, face common.Rectangle) ([]float64, error) | ||||
| 	Destroy() | ||||
| } | ||||
|  | ||||
| // LoadModel load recognizer model | ||||
| func LoadModel(r Recognizer, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(r.Handler())), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy a recognizer | ||||
| func Destroy(r Recognizer) { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(r.Handler()))) | ||||
| } | ||||
|  | ||||
| // ExtractFeatures extract features using recognizer | ||||
| @@ -47,7 +29,7 @@ func ExtractFeatures(r Recognizer, img *common.Image, faceRect common.Rectangle) | ||||
| 	defer common.FreeCFloatVector(CFeatures) | ||||
| 	CRect := faceRect.CRect(imgWidth, imgHeight) | ||||
| 	errCode := C.extract_feature( | ||||
| 		r.Handler(), | ||||
| 		(C.IFaceRecognizer)(r.Pointer()), | ||||
| 		(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 		C.int(imgWidth), C.int(imgHeight), | ||||
| 		(*C.Rect)(unsafe.Pointer(CRect)), | ||||
|   | ||||
| @@ -16,26 +16,8 @@ import ( | ||||
|  | ||||
| // Detecter represents deteter interface | ||||
| type Detecter interface { | ||||
| 	Handler() C.IHandDetecter | ||||
| 	LoadModel(modelPath string) error | ||||
| 	common.Estimator | ||||
| 	Detect(img *common.Image) ([]common.ObjectInfo, error) | ||||
| 	Destroy() | ||||
| } | ||||
|  | ||||
| // LoadModel load detecter model | ||||
| func LoadModel(d Detecter, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(d.Handler())), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy a detecter | ||||
| func Destroy(d Detecter) { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(d.Handler()))) | ||||
| } | ||||
|  | ||||
| // Detect detect hand ROI | ||||
| @@ -46,7 +28,7 @@ func Detect(d Detecter, img *common.Image) ([]common.ObjectInfo, error) { | ||||
| 	cObjs := common.NewCObjectInfoVector() | ||||
| 	defer common.FreeCObjectInfoVector(cObjs) | ||||
| 	errCode := C.extract_hand_rois( | ||||
| 		d.Handler(), | ||||
| 		(C.IHandDetecter)(d.Pointer()), | ||||
| 		(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 		C.int(imgWidth), | ||||
| 		C.int(imgHeight), | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| @@ -24,17 +26,17 @@ func NewNanodet() *Nanodet { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Nanodet) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IHandDetecter | ||||
| func (d *Nanodet) Handler() C.IHandDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Nanodet) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load model for detecter | ||||
| func (d *Nanodet) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Detect implement Detecter interface | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| @@ -24,17 +26,17 @@ func NewYolox() *Yolox { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Yolox) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IHandDetecter | ||||
| func (d *Yolox) Handler() C.IHandDetecter { | ||||
| 	return d.d | ||||
| // Pointer implenment Estimator interface | ||||
| func (d *Yolox) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load model for detecter | ||||
| func (d *Yolox) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Detect implement Detecter interface | ||||
|   | ||||
| @@ -16,26 +16,8 @@ import ( | ||||
|  | ||||
| // Estimator represents estimator interface | ||||
| type Estimator interface { | ||||
| 	Handler() C.IHandPoseEstimator | ||||
| 	LoadModel(modelPath string) error | ||||
| 	common.Estimator | ||||
| 	Detect(img *common.Image, rect common.Rectangle) ([]common.Point, error) | ||||
| 	Destroy() | ||||
| } | ||||
|  | ||||
| // LoadModel load detecter model | ||||
| func LoadModel(d Estimator, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(d.Handler())), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy a estimator | ||||
| func Destroy(d Estimator) { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(d.Handler()))) | ||||
| } | ||||
|  | ||||
| // Detect detect hand pose | ||||
| @@ -47,7 +29,7 @@ func Detect(d Estimator, img *common.Image, rect common.Rectangle) ([]common.Poi | ||||
| 	defer common.FreeCPoint2fVector(CPoints) | ||||
| 	CRect := rect.CRect(imgWidth, imgHeight) | ||||
| 	errCode := C.hand_pose( | ||||
| 		d.Handler(), | ||||
| 		(C.IHandPoseEstimator)(d.Pointer()), | ||||
| 		(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 		C.int(imgWidth), C.int(imgHeight), | ||||
| 		(*C.Rect)(unsafe.Pointer(CRect)), | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package pose | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| @@ -24,17 +26,17 @@ func NewHandPoseEstimator() *HandPoseEstimator { | ||||
|  | ||||
| // Destroy free Estimator | ||||
| func (d *HandPoseEstimator) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IHandPoseEstimator | ||||
| func (d *HandPoseEstimator) Handler() C.IHandPoseEstimator { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *HandPoseEstimator) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load model for  estimator | ||||
| func (d *HandPoseEstimator) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // Detect implement Estimator interface | ||||
|   | ||||
| @@ -16,26 +16,8 @@ import ( | ||||
|  | ||||
| // Detecter represents deteter interface | ||||
| type Detecter interface { | ||||
| 	Handler() C.IPoseDetecter | ||||
| 	LoadModel(modelPath string) error | ||||
| 	common.Estimator | ||||
| 	ExtractKeypoints(img *common.Image) ([]common.ObjectInfo, error) | ||||
| 	Destroy() | ||||
| } | ||||
|  | ||||
| // LoadModel load detecter model | ||||
| func LoadModel(d Detecter, modelPath string) error { | ||||
| 	cpath := C.CString(modelPath) | ||||
| 	defer C.free(unsafe.Pointer(cpath)) | ||||
| 	retCode := C.load_model((C.IEstimator)(unsafe.Pointer(d.Handler())), cpath) | ||||
| 	if retCode != 0 { | ||||
| 		return openvision.LoadModelError(int(retCode)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Destroy a detecter | ||||
| func Destroy(d Detecter) { | ||||
| 	C.destroy_estimator((C.IEstimator)(unsafe.Pointer(d.Handler()))) | ||||
| } | ||||
|  | ||||
| // ExtractKeypoints detect pose keypoints using detecter | ||||
| @@ -46,7 +28,7 @@ func ExtractKeypoints(d Detecter, img *common.Image) ([]common.ObjectInfo, error | ||||
| 	cObjs := common.NewCObjectInfoVector() | ||||
| 	defer common.FreeCObjectInfoVector(cObjs) | ||||
| 	errCode := C.extract_pose_rois( | ||||
| 		d.Handler(), | ||||
| 		(C.IPoseDetecter)(d.Pointer()), | ||||
| 		(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 		C.int(imgWidth), | ||||
| 		C.int(imgHeight), | ||||
| @@ -62,7 +44,7 @@ func ExtractKeypoints(d Detecter, img *common.Image) ([]common.ObjectInfo, error | ||||
| 		defer common.FreeCKeypointVector(cKeypoints) | ||||
| 		cROI := (*C.ObjectInfo)(unsafe.Pointer(uintptr(ptr) + uintptr(C.sizeof_ObjectInfo*C.int(i)))) | ||||
| 		errCode := C.extract_pose_keypoints( | ||||
| 			d.Handler(), | ||||
| 			(C.IPoseDetecter)(d.Pointer()), | ||||
| 			(*C.uchar)(unsafe.Pointer(&data[0])), | ||||
| 			C.int(imgWidth), | ||||
| 			C.int(imgHeight), | ||||
| @@ -80,7 +62,7 @@ func ExtractKeypoints(d Detecter, img *common.Image) ([]common.ObjectInfo, error | ||||
| 				float64(cROI.rect.width)/imgWidth, | ||||
| 				float64(cROI.rect.height)/imgHeight, | ||||
| 			), | ||||
| 			Score: float32(cROI.prob), | ||||
| 			Score: float32(cROI.score), | ||||
| 		}) | ||||
|  | ||||
| 	} | ||||
|   | ||||
| @@ -7,6 +7,8 @@ package detecter | ||||
| */ | ||||
| import "C" | ||||
| import ( | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/bububa/openvision/go/common" | ||||
| ) | ||||
|  | ||||
| @@ -24,17 +26,17 @@ func NewUltralight() *Ultralight { | ||||
|  | ||||
| // Destroy free detecter | ||||
| func (d *Ultralight) Destroy() { | ||||
| 	Destroy(d) | ||||
| 	common.DestroyEstimator(d) | ||||
| } | ||||
|  | ||||
| // Handler returns C.IPoseDetecter | ||||
| func (d *Ultralight) Handler() C.IPoseDetecter { | ||||
| 	return d.d | ||||
| // Pointer implement Estimator interface | ||||
| func (d *Ultralight) Pointer() unsafe.Pointer { | ||||
| 	return unsafe.Pointer(d.d) | ||||
| } | ||||
|  | ||||
| // LoadModel load model for detecter | ||||
| func (d *Ultralight) LoadModel(modelPath string) error { | ||||
| 	return LoadModel(d, modelPath) | ||||
| 	return common.EstimatorLoadModel(d, modelPath) | ||||
| } | ||||
|  | ||||
| // ExtractKeypoints implement Detecter interface | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #include "common.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <math.h> | ||||
| #include <float.h> | ||||
| #include "cpu.h" | ||||
|  | ||||
| #ifdef OV_VULKAN | ||||
| #include "gpu.h" | ||||
| @@ -28,6 +28,16 @@ void destroy_gpu_instance() { | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| int get_big_cpu_count() { | ||||
|     return ncnn::get_big_cpu_count(); | ||||
| } | ||||
|  | ||||
| void set_omp_num_threads(int n) { | ||||
| #ifdef OV_OPENMP | ||||
|     ncnn::set_omp_num_threads(n); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| int load_model(IEstimator d, const char *root_path) { | ||||
|     return static_cast<ov::Estimator*>(d)->LoadModel(root_path); | ||||
| } | ||||
| @@ -36,6 +46,10 @@ void destroy_estimator(IEstimator d) { | ||||
|     delete static_cast<ov::Estimator*>(d); | ||||
| } | ||||
|  | ||||
| void set_num_threads(IEstimator d, int n) { | ||||
|     static_cast<ov::Estimator*>(d)->set_num_threads(n); | ||||
| } | ||||
|  | ||||
| void FreePoint2fVector(Point2fVector* p) { | ||||
|     if (p->points != NULL) { | ||||
|         free(p->points); | ||||
| @@ -97,9 +111,44 @@ void FreeObjectInfoVector(ObjectInfoVector *p) { | ||||
| } | ||||
| namespace ov { | ||||
|  | ||||
| Estimator::Estimator() { | ||||
|     net_ = new ncnn::Net(); | ||||
| 	initialized_ = false; | ||||
| #ifdef OV_VULKAN | ||||
|     net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| Estimator::~Estimator() { | ||||
|     if (net_) { | ||||
|         net_->clear(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int Estimator::LoadModel(const char * root_path) { | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (net_->load_param(param_file.c_str()) == -1 || | ||||
| 		net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
| 	initialized_ = true; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void Estimator::set_num_threads(int n) { | ||||
|     num_threads = n; | ||||
|     if (net_) { | ||||
|         net_->opt.num_threads = n; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| int RatioAnchors(const Rect & anchor, | ||||
| 	const std::vector<float>& ratios,  | ||||
| 	std::vector<Rect>* anchors) { | ||||
| 	std::vector<Rect>* anchors, int threads_num) { | ||||
| 	anchors->clear(); | ||||
| 	Point center = Point(anchor.x + (anchor.width - 1) * 0.5f, | ||||
| 		anchor.y + (anchor.height - 1) * 0.5f); | ||||
| @@ -123,7 +172,7 @@ int RatioAnchors(const Rect & anchor, | ||||
| } | ||||
|  | ||||
| int ScaleAnchors(const std::vector<Rect>& ratio_anchors, | ||||
| 	const std::vector<float>& scales, std::vector<Rect>* anchors) { | ||||
| 	const std::vector<float>& scales, std::vector<Rect>* anchors, int threads_num) { | ||||
| 	anchors->clear(); | ||||
| #if defined(_OPENMP) | ||||
| #pragma omp parallel for num_threads(threads_num) | ||||
| @@ -150,12 +199,13 @@ int ScaleAnchors(const std::vector<Rect>& ratio_anchors, | ||||
| int GenerateAnchors(const int & base_size, | ||||
| 	const std::vector<float>& ratios,  | ||||
| 	const std::vector<float> scales, | ||||
| 	std::vector<Rect>* anchors) { | ||||
| 	std::vector<Rect>* anchors, | ||||
|     int threads_num) { | ||||
| 	anchors->clear(); | ||||
| 	Rect anchor = Rect(0, 0, base_size, base_size); | ||||
| 	std::vector<Rect> ratio_anchors; | ||||
| 	RatioAnchors(anchor, ratios, &ratio_anchors); | ||||
| 	ScaleAnchors(ratio_anchors, scales, anchors); | ||||
| 	RatioAnchors(anchor, ratios, &ratio_anchors, threads_num); | ||||
| 	ScaleAnchors(ratio_anchors, scales, anchors, threads_num); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
| @@ -207,14 +257,14 @@ void qsort_descent_inplace(std::vector<ObjectInfo>& objects, int left, int right | ||||
| { | ||||
|     int i = left; | ||||
|     int j = right; | ||||
|     float p = objects[(left + right) / 2].prob; | ||||
|     float p = objects[(left + right) / 2].score; | ||||
|  | ||||
|     while (i <= j) | ||||
|     { | ||||
|         while (objects[i].prob > p) | ||||
|         while (objects[i].score > p) | ||||
|             i++; | ||||
|  | ||||
|         while (objects[j].prob < p) | ||||
|         while (objects[j].score < p) | ||||
|             j--; | ||||
|  | ||||
|         if (i <= j) | ||||
| @@ -281,6 +331,44 @@ void nms_sorted_bboxes(const std::vector<ObjectInfo>& objects, std::vector<int>& | ||||
|             picked.push_back(i); | ||||
|     } | ||||
| } | ||||
| // | ||||
| // insightface/detection/scrfd/mmdet/core/anchor/anchor_generator.py gen_single_level_base_anchors() | ||||
| ncnn::Mat generate_anchors(int base_size, const ncnn::Mat& ratios, const ncnn::Mat& scales) | ||||
| { | ||||
|     int num_ratio = ratios.w; | ||||
|     int num_scale = scales.w; | ||||
|  | ||||
|     ncnn::Mat anchors; | ||||
|     anchors.create(4, num_ratio * num_scale); | ||||
|  | ||||
|     const float cx = 0; | ||||
|     const float cy = 0; | ||||
|  | ||||
|     for (int i = 0; i < num_ratio; i++) | ||||
|     { | ||||
|         float ar = ratios[i]; | ||||
|  | ||||
|         int r_w = round(base_size / sqrt(ar)); | ||||
|         int r_h = round(r_w * ar); //round(base_size * sqrt(ar)); | ||||
|  | ||||
|         for (int j = 0; j < num_scale; j++) | ||||
|         { | ||||
|             float scale = scales[j]; | ||||
|  | ||||
|             float rs_w = r_w * scale; | ||||
|             float rs_h = r_h * scale; | ||||
|  | ||||
|             float* anchor = anchors.row(i * num_scale + j); | ||||
|  | ||||
|             anchor[0] = cx - rs_w * 0.5f; | ||||
|             anchor[1] = cy - rs_h * 0.5f; | ||||
|             anchor[2] = cx + rs_w * 0.5f; | ||||
|             anchor[3] = cy + rs_h * 0.5f; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return anchors; | ||||
| } | ||||
|  | ||||
| int generate_grids_and_stride(const int target_size, std::vector<int>& strides, std::vector<GridAndStride>& grid_strides) | ||||
| { | ||||
|   | ||||
| @@ -43,7 +43,7 @@ typedef struct Rect { | ||||
|  | ||||
| typedef struct Keypoint { | ||||
|     Point2f p; | ||||
|     float prob; | ||||
|     float score; | ||||
| } Keypoint; | ||||
|  | ||||
|  | ||||
| @@ -54,8 +54,11 @@ typedef void* IEstimator; | ||||
| int get_gpu_count(); | ||||
| int create_gpu_instance(); | ||||
| void destroy_gpu_instance(); | ||||
| int get_big_cpu_count();  | ||||
| void set_omp_num_threads(int n); | ||||
| int load_model(IEstimator e, const char* root_path); | ||||
| void destroy_estimator(IEstimator e); | ||||
| void set_num_threads(IEstimator e, int n); | ||||
|  | ||||
| typedef struct Point2fVector { | ||||
|     Point2f* points; | ||||
| @@ -96,7 +99,7 @@ void KeypointVectorSetValue(KeypointVector *p, int i, const Keypoint* val); | ||||
|  | ||||
| typedef struct ObjectInfoC { | ||||
|     Rect rect; | ||||
|     float prob; | ||||
|     float score; | ||||
|     int label; | ||||
|     KeypointVector* pts; | ||||
| } ObjectInfo; | ||||
|   | ||||
| @@ -10,12 +10,17 @@ | ||||
| #endif | ||||
|  | ||||
| namespace ov { | ||||
| const int threads_num = 2; | ||||
|  | ||||
| class Estimator { | ||||
| public: | ||||
|     virtual ~Estimator(){}; | ||||
|     virtual int LoadModel(const char* root_path) = 0; | ||||
|     Estimator(); | ||||
|     virtual ~Estimator(); | ||||
|     virtual int LoadModel(const char* root_path); | ||||
|     virtual void set_num_threads(int n); | ||||
| protected: | ||||
|     int num_threads = 2; | ||||
|     ncnn::Net* net_; | ||||
|     bool initialized_ = false; | ||||
| }; | ||||
|  | ||||
| // Wrapper for an individual cv::cvSize | ||||
| @@ -78,17 +83,17 @@ typedef struct Rect { | ||||
|  | ||||
| struct ImageInfo { | ||||
|     std::string label_; | ||||
|     float score_; | ||||
|     float score; | ||||
| }; | ||||
|  | ||||
| struct Keypoint { | ||||
|     ov::Point2f p; | ||||
|     float prob; | ||||
|     Point2f p; | ||||
|     float score; | ||||
| }; | ||||
|  | ||||
| struct ObjectInfo { | ||||
| 	Rect rect; | ||||
| 	float prob; | ||||
| 	float score; | ||||
|     int label; | ||||
|     std::vector<Point2f> pts; | ||||
| }; | ||||
| @@ -101,14 +106,15 @@ struct GridAndStride | ||||
| }; | ||||
|  | ||||
| int RatioAnchors(const Rect & anchor, | ||||
| 	const std::vector<float>& ratios, std::vector<Rect>* anchors); | ||||
| 	const std::vector<float>& ratios, std::vector<Rect>* anchors, int threads_num); | ||||
|  | ||||
| int ScaleAnchors(const std::vector<Rect>& ratio_anchors, | ||||
| 	const std::vector<float>& scales, std::vector<Rect>* anchors); | ||||
| 	const std::vector<float>& scales, std::vector<Rect>* anchors, int threads_num); | ||||
|  | ||||
| int GenerateAnchors(const int & base_size, | ||||
| 	const std::vector<float>& ratios, const std::vector<float> scales, | ||||
| 	std::vector<Rect>* anchors); | ||||
| 	std::vector<Rect>* anchors, | ||||
|     int threads_num); | ||||
|  | ||||
| float InterRectArea(const Rect & a, | ||||
| 	const Rect & b); | ||||
| @@ -128,7 +134,7 @@ int const NMS(const std::vector<T>& inputs, std::vector<T>* result, | ||||
|     inputs_tmp.assign(inputs.begin(), inputs.end()); | ||||
|     std::sort(inputs_tmp.begin(), inputs_tmp.end(), | ||||
|     [](const T& a, const T& b) { | ||||
|         return a.score_ > b.score_; | ||||
|         return a.score > b.score; | ||||
|     }); | ||||
|  | ||||
|     std::vector<int> indexes(inputs_tmp.size()); | ||||
| @@ -145,7 +151,7 @@ int const NMS(const std::vector<T>& inputs, std::vector<T>* result, | ||||
|         for (int i = 1; i < tmp_indexes.size(); i++) { | ||||
|             int tmp_i = tmp_indexes[i]; | ||||
|             float iou = 0.0f; | ||||
|             ComputeIOU(inputs_tmp[good_idx].location_, inputs_tmp[tmp_i].location_, &iou, type); | ||||
|             ComputeIOU(inputs_tmp[good_idx].rect, inputs_tmp[tmp_i].rect, &iou, type); | ||||
|             if (iou <= threshold) { | ||||
|                 indexes.push_back(tmp_i); | ||||
|             } | ||||
| @@ -160,6 +166,9 @@ void qsort_descent_inplace(std::vector<ObjectInfo>& objects); | ||||
|  | ||||
| void nms_sorted_bboxes(const std::vector<ObjectInfo>& objects, std::vector<int>& picked, float nms_threshold); | ||||
|  | ||||
| // insightface/detection/scrfd/mmdet/core/anchor/anchor_generator.py gen_single_level_base_anchors() | ||||
| ncnn::Mat generate_anchors(int base_size, const ncnn::Mat& ratios, const ncnn::Mat& scales); | ||||
|  | ||||
| int generate_grids_and_stride(const int target_size, std::vector<int>& strides, std::vector<GridAndStride>& grid_strides); | ||||
|  | ||||
| float sigmoid(float x); | ||||
|   | ||||
| @@ -13,8 +13,8 @@ typedef ovface::TrackedFaceInfo TrackedFaceInfo; | ||||
| typedef ovface::HeadPose HeadPose; | ||||
| #else | ||||
| typedef struct FaceInfo { | ||||
|     Rect location_; | ||||
|     float score_; | ||||
|     Rect rect; | ||||
|     float score; | ||||
|     float keypoints_[10]; | ||||
|     bool mask_; | ||||
| } FaceInfo; | ||||
|   | ||||
| @@ -33,7 +33,86 @@ void FreeTrackedFaceInfoVector(TrackedFaceInfoVector *p) { | ||||
|  | ||||
| namespace ovface { | ||||
|  | ||||
| float CalculateSimilarity(const std::vector<float>&feature1, const std::vector<float>& feature2) { | ||||
| void qsort_descent_inplace(std::vector<FaceInfo>& objects, int left, int right) | ||||
| { | ||||
|     int i = left; | ||||
|     int j = right; | ||||
|     float p = objects[(left + right) / 2].score; | ||||
|  | ||||
|     while (i <= j) | ||||
|     { | ||||
|         while (objects[i].score > p) | ||||
|             i++; | ||||
|  | ||||
|         while (objects[j].score < p) | ||||
|             j--; | ||||
|  | ||||
|         if (i <= j) | ||||
|         { | ||||
|             // swap | ||||
|             std::swap(objects[i], objects[j]); | ||||
|  | ||||
|             i++; | ||||
|             j--; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #pragma omp parallel sections | ||||
|     { | ||||
|         #pragma omp section | ||||
|         { | ||||
|             if (left < j) qsort_descent_inplace(objects, left, j); | ||||
|         } | ||||
|         #pragma omp section | ||||
|         { | ||||
|             if (i < right) qsort_descent_inplace(objects, i, right); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| void qsort_descent_inplace(std::vector<FaceInfo>& objects)  | ||||
| { | ||||
|     if (objects.empty()) | ||||
|         return; | ||||
|  | ||||
|     qsort_descent_inplace(objects, 0, objects.size() - 1); | ||||
| } | ||||
|  | ||||
| void nms_sorted_bboxes(const std::vector<FaceInfo>& objects, std::vector<int>& picked, float nms_threshold) | ||||
| { | ||||
|     picked.clear(); | ||||
|  | ||||
|     const int n = objects.size(); | ||||
|  | ||||
|     std::vector<float> areas(n); | ||||
|     for (int i = 0; i < n; i++) | ||||
|     { | ||||
|         areas[i] = objects[i].rect.area(); | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < n; i++) | ||||
|     { | ||||
|         const FaceInfo& a = objects[i]; | ||||
|  | ||||
|         int keep = 1; | ||||
|         for (int j = 0; j < (int)picked.size(); j++) | ||||
|         { | ||||
|             const FaceInfo& b = objects[picked[j]]; | ||||
|  | ||||
|             // intersection over union | ||||
|             float inter_area = InterRectArea(a.rect, b.rect); | ||||
|             float union_area = areas[i] + areas[picked[j]] - inter_area; | ||||
|             // float IoU = inter_area / union_area | ||||
|             if (inter_area / union_area > nms_threshold) | ||||
|                 keep = 0; | ||||
|         } | ||||
|  | ||||
|         if (keep) | ||||
|             picked.push_back(i); | ||||
|     } | ||||
| } | ||||
|  | ||||
| float CalculateSimilarity(const std::vector<float>&feature1, const std::vector<float>& feature2, int threads_num) { | ||||
| 	if (feature1.size() != feature2.size()) { | ||||
| 		return 10003; | ||||
| 	} | ||||
| @@ -41,7 +120,7 @@ float CalculateSimilarity(const std::vector<float>&feature1, const std::vector<f | ||||
| 	float feature_norm1 = 0.0f; | ||||
| 	float feature_norm2 = 0.0f; | ||||
| #ifdef OV_OPENMP | ||||
| #pragma omp parallel for num_threads(ov::threads_num) | ||||
| #pragma omp parallel for num_threads(threads_num) | ||||
| #endif | ||||
| 	for(int i = 0; i < kFaceFeatureDim; ++i) { | ||||
| 		inner_product += feature1[i] * feature2[i]; | ||||
|   | ||||
| @@ -8,8 +8,8 @@ namespace ovface { | ||||
| #define kFaceFeatureDim 128 | ||||
| #define kFaceNameDim 256 | ||||
| struct FaceInfo { | ||||
|     ov::Rect location_; | ||||
| 	float score_; | ||||
|     ov::Rect rect; | ||||
| 	float score; | ||||
| 	float keypoints_[10]; | ||||
|     bool mask_; | ||||
| }; | ||||
| @@ -25,7 +25,15 @@ struct HeadPose | ||||
|     float pitch; | ||||
|     float yaw; | ||||
| }; | ||||
| } | ||||
|  | ||||
| void qsort_descent_inplace(std::vector<FaceInfo>& objects, int left, int right); | ||||
|  | ||||
| void qsort_descent_inplace(std::vector<FaceInfo>& objects);  | ||||
|  | ||||
| void nms_sorted_bboxes(const std::vector<FaceInfo>& objects, std::vector<int>& picked, float nms_threshold); | ||||
|  | ||||
| float CalculateSimilarity(const std::vector<float>&feature1, const std::vector<float>& feature2); | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif // !_FACE_COMMON_H_ | ||||
|   | ||||
| @@ -12,6 +12,7 @@ extern "C" { | ||||
|     IFaceDetecter new_centerface(); | ||||
|     IFaceDetecter new_mtcnn(); | ||||
|     IFaceDetecter new_yoloface(); | ||||
|     IFaceDetecter new_scrfd(); | ||||
|     IFaceDetecter new_anticonv(); | ||||
|     int detect_face(IFaceDetecter d, const unsigned char* rgbdata, int img_width, int img_height, FaceInfoVector* faces);  | ||||
| #ifdef __cplusplus | ||||
|   | ||||
| @@ -5,44 +5,26 @@ | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| AntiConv::AntiConv() : | ||||
| 	anticonv_net_(new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     anticonv_net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| } | ||||
|  | ||||
| AntiConv::~AntiConv() { | ||||
| 	if (anticonv_net_) { | ||||
| 		anticonv_net_->clear(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int AntiConv::LoadModel(const char * root_path) { | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (anticonv_net_->load_param(param_file.c_str()) == -1 || | ||||
| 		anticonv_net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
|     int ret = Estimator::LoadModel(root_path); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
| 	// generate anchors | ||||
| 	for (int i = 0; i < 3; ++i) { | ||||
| 		ANCHORS anchors; | ||||
| 		if (0 == i) { | ||||
| 			GenerateAnchors(16, { 1.0f }, { 32, 16 }, &anchors); | ||||
| 			GenerateAnchors(16, { 1.0f }, { 32, 16 }, &anchors, num_threads); | ||||
| 		} | ||||
| 		else if (1 == i) { | ||||
| 			GenerateAnchors(16, { 1.0f }, { 8, 4 }, &anchors); | ||||
| 			GenerateAnchors(16, { 1.0f }, { 8, 4 }, &anchors, num_threads); | ||||
| 		} | ||||
| 		else { | ||||
| 			GenerateAnchors(16, { 1.0f }, { 2, 1 }, &anchors); | ||||
| 			GenerateAnchors(16, { 1.0f }, { 2, 1 }, &anchors, num_threads); | ||||
| 		} | ||||
| 		anchors_generated_.push_back(anchors); | ||||
| 	} | ||||
| 	initialized_ = true; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -60,7 +42,7 @@ int AntiConv::DetectFace(const unsigned char* rgbdata, | ||||
|  | ||||
| 	float factor_x = static_cast<float>(img_width) / inputSize_.width; | ||||
| 	float factor_y = static_cast<float>(img_height) / inputSize_.height; | ||||
| 	ncnn::Extractor ex = anticonv_net_->create_extractor(); | ||||
| 	ncnn::Extractor ex = net_->create_extractor(); | ||||
| 	ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, | ||||
| 		ncnn::Mat::PIXEL_RGB, img_width, img_height, inputSize_.width, inputSize_.height); | ||||
| 	ex.input("data", in); | ||||
| @@ -115,9 +97,9 @@ int AntiConv::DetectFace(const unsigned char* rgbdata, | ||||
|  | ||||
| 					FaceInfo face_info; | ||||
| 					memset(&face_info, 0, sizeof(face_info)); | ||||
| 					face_info.score_ = score; | ||||
| 					face_info.score = score; | ||||
| 					face_info.mask_ = (prob > maskThreshold_); | ||||
| 					face_info.location_ = curr_box; | ||||
| 					face_info.rect = curr_box; | ||||
| 					faces_tmp.push_back(face_info); | ||||
| 				} | ||||
| 			} | ||||
|   | ||||
| @@ -8,17 +8,13 @@ namespace ovface { | ||||
| using ANCHORS = std::vector<ov::Rect>; | ||||
| class AntiConv : public Detecter { | ||||
| public: | ||||
| 	AntiConv(); | ||||
| 	~AntiConv(); | ||||
| 	int LoadModel(const char* root_path); | ||||
| 	int DetectFace(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* anticonv_net_; | ||||
| 	std::vector<ANCHORS> anchors_generated_; | ||||
| 	bool initialized_; | ||||
| 	const int RPNs_[3] = { 32, 16, 8 }; | ||||
| 	const Size inputSize_ = { 640, 640 }; | ||||
| 	const float iouThreshold_ = 0.4f; | ||||
|   | ||||
| @@ -5,31 +5,6 @@ | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| CenterFace::CenterFace() { | ||||
|     centernet_ = new ncnn::Net(); | ||||
|     initialized_ = false; | ||||
| #ifdef OV_VULKAN | ||||
|     centernet_->opt.use_vulkan_compute = true; | ||||
| #endif // MIRROR_VULKAN | ||||
| } | ||||
|  | ||||
| CenterFace::~CenterFace(){ | ||||
|     if (centernet_) { | ||||
|         centernet_->clear(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int CenterFace::LoadModel(const char* root_path) { | ||||
|     std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string model_file = std::string(root_path) + "/bin"; | ||||
|     if (centernet_->load_param(param_file.c_str()) == -1 || | ||||
|         centernet_->load_model(model_file.c_str()) == -1) { | ||||
|         return 10000; | ||||
| 	} | ||||
|  | ||||
|     initialized_ = true; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int CenterFace::DetectFace(const unsigned char* rgbdata,  | ||||
|     int img_width, int img_height, | ||||
| @@ -49,7 +24,7 @@ int CenterFace::DetectFace(const unsigned char* rgbdata, | ||||
|  | ||||
|     ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, | ||||
| 		img_width, img_height, img_width_new, img_height_new); | ||||
| 	ncnn::Extractor ex = centernet_->create_extractor(); | ||||
| 	ncnn::Extractor ex = net_->create_extractor(); | ||||
| 	ex.input("input.1", in); | ||||
| 	ncnn::Mat mat_heatmap, mat_scale, mat_offset, mat_landmark; | ||||
| 	ex.extract("537", mat_heatmap); | ||||
| @@ -78,11 +53,11 @@ int CenterFace::DetectFace(const unsigned char* rgbdata, | ||||
| 			float xmax = fminf(xmin + s1, img_width_new); | ||||
|  | ||||
|             FaceInfo face_info; | ||||
|             face_info.score_ = score; | ||||
|             face_info.location_.x = scale_x * xmin; | ||||
|             face_info.location_.y = scale_y * ymin; | ||||
|             face_info.location_.width = scale_x * (xmax - xmin); | ||||
|             face_info.location_.height = scale_y * (ymax - ymin); | ||||
|             face_info.score = score; | ||||
|             face_info.rect.x = scale_x * xmin; | ||||
|             face_info.rect.y = scale_y * ymin; | ||||
|             face_info.rect.width = scale_x * (xmax - xmin); | ||||
|             face_info.rect.height = scale_y * (ymax - ymin); | ||||
|  | ||||
|             for (int num = 0; num < 5; ++num) { | ||||
|                 face_info.keypoints_[num    ] = scale_x * (s1 * mat_landmark.channel(2 * num + 1)[index] + xmin); | ||||
|   | ||||
| @@ -8,18 +8,13 @@ | ||||
| namespace ovface { | ||||
| class CenterFace : public Detecter { | ||||
| public: | ||||
|     CenterFace(); | ||||
|     ~CenterFace(); | ||||
| 	int LoadModel(const char* root_path); | ||||
| 	int DetectFace(const unsigned char* rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces); | ||||
|  | ||||
| private: | ||||
|     ncnn::Net* centernet_ = nullptr; | ||||
|     const float scoreThreshold_ = 0.5f; | ||||
|     const float nmsThreshold_ = 0.5f; | ||||
|     bool initialized_; | ||||
| }; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include "retinaface/retinaface.hpp" | ||||
| #include "anticonv/anticonv.hpp" | ||||
| #include "yoloface/yoloface.hpp" | ||||
| #include "scrfd/scrfd.hpp" | ||||
|  | ||||
| IFaceDetecter new_retinaface() { | ||||
|     return new ovface::RetinaFace(); | ||||
| @@ -21,6 +22,10 @@ IFaceDetecter new_yoloface() { | ||||
|     return new ovface::YoloFace(); | ||||
| } | ||||
|  | ||||
| IFaceDetecter new_scrfd() { | ||||
|     return new ovface::Scrfd(); | ||||
| } | ||||
|  | ||||
| IFaceDetecter new_anticonv() { | ||||
|     return new ovface::AntiConv(); | ||||
| } | ||||
| @@ -58,6 +63,10 @@ Detecter* YoloFaceFactory::CreateDetecter() { | ||||
| 	return new YoloFace(); | ||||
| } | ||||
|  | ||||
| Detecter* ScrfdFactory::CreateDetecter() { | ||||
| 	return new Scrfd(); | ||||
| } | ||||
|  | ||||
| Detecter* AnticonvFactory::CreateDetecter() { | ||||
| 	return new AntiConv(); | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ namespace ovface { | ||||
| // 抽象类 | ||||
| class Detecter: public ov::Estimator { | ||||
| public: | ||||
| 	virtual ~Detecter() {}; | ||||
| 	virtual int DetectFace(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces) = 0; | ||||
| @@ -51,6 +50,13 @@ public: | ||||
| 	Detecter* CreateDetecter(); | ||||
| }; | ||||
|  | ||||
| class ScrfdFactory : public DetecterFactory { | ||||
| public: | ||||
| 	ScrfdFactory() {} | ||||
| 	~ScrfdFactory() {} | ||||
| 	Detecter* CreateDetecter(); | ||||
| }; | ||||
|  | ||||
| class AnticonvFactory : public DetecterFactory { | ||||
| public: | ||||
| 	AnticonvFactory() {} | ||||
|   | ||||
| @@ -32,6 +32,19 @@ Mtcnn::~Mtcnn() { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Mtcnn::set_num_threads(int n) { | ||||
|     num_threads = n; | ||||
|     if (pnet_) { | ||||
|         pnet_->opt.num_threads = n; | ||||
|     } | ||||
|     if (rnet_) { | ||||
|         rnet_->opt.num_threads = n; | ||||
|     } | ||||
|     if (onet_) { | ||||
|         onet_->opt.num_threads = n; | ||||
|     } | ||||
| } | ||||
|  | ||||
| int Mtcnn::LoadModel(const char * root_path) { | ||||
| 	std::string pnet_param = std::string(root_path) + "/pnet.param"; | ||||
| 	std::string pnet_bin = std::string(root_path) + "/pnet.bin"; | ||||
| @@ -141,12 +154,12 @@ int Mtcnn::PDetect(const ncnn::Mat & img_in, | ||||
| 				int bbox_height = y2 - y1 + 1; | ||||
|  | ||||
| 				FaceInfo face_info; | ||||
| 				face_info.score_ = score; | ||||
| 				face_info.location_.x = x1 + x1_reg * bbox_width; | ||||
| 				face_info.location_.y = y1 + y1_reg * bbox_height; | ||||
| 				face_info.location_.width = x2 + x2_reg * bbox_width - face_info.location_.x; | ||||
| 				face_info.location_.height = y2 + y2_reg * bbox_height - face_info.location_.y; | ||||
| 				face_info.location_ = face_info.location_ & Rect(0, 0, width, height); | ||||
| 				face_info.score = score; | ||||
| 				face_info.rect.x = x1 + x1_reg * bbox_width; | ||||
| 				face_info.rect.y = y1 + y1_reg * bbox_height; | ||||
| 				face_info.rect.width = x2 + x2_reg * bbox_width - face_info.rect.x; | ||||
| 				face_info.rect.height = y2 + y2_reg * bbox_height - face_info.rect.y; | ||||
| 				face_info.rect = face_info.rect & Rect(0, 0, width, height); | ||||
| 				first_bboxes->push_back(face_info); | ||||
| 			} | ||||
| 		} | ||||
| @@ -159,13 +172,13 @@ int Mtcnn::RDetect(const ncnn::Mat & img_in, | ||||
| 	std::vector<FaceInfo>* second_bboxes) { | ||||
| 	second_bboxes->clear(); | ||||
| 	for (int i = 0; i < static_cast<int>(first_bboxes.size()); ++i) { | ||||
| 		Rect face = first_bboxes.at(i).location_ & Rect(0, 0, img_in.w, img_in.h); | ||||
| 		Rect face = first_bboxes.at(i).rect & Rect(0, 0, img_in.w, img_in.h); | ||||
| 		ncnn::Mat img_face, img_resized; | ||||
| 		ncnn::copy_cut_border(img_in, img_face, face.y, img_in.h - face.br().y, face.x, img_in.w - face.br().x); | ||||
| 		ncnn::resize_bilinear(img_face, img_resized, 24, 24); | ||||
| 		ncnn::Extractor ex = rnet_->create_extractor(); | ||||
| 		ex.set_light_mode(true); | ||||
| 		ex.set_num_threads(2); | ||||
| 		// ex.set_num_threads(2); | ||||
| 		ex.input("data", img_resized); | ||||
| 		ncnn::Mat score_mat, location_mat; | ||||
| 		ex.extract("prob1", score_mat); | ||||
| @@ -178,13 +191,13 @@ int Mtcnn::RDetect(const ncnn::Mat & img_in, | ||||
| 		float h_reg = location_mat[3]; | ||||
|  | ||||
| 		FaceInfo face_info; | ||||
| 		face_info.score_ = score; | ||||
| 		face_info.location_.x = face.x + x_reg * face.width; | ||||
| 		face_info.location_.y = face.y + y_reg * face.height; | ||||
| 		face_info.location_.width = face.x + face.width + | ||||
| 			w_reg * face.width - face_info.location_.x; | ||||
| 		face_info.location_.height = face.y + face.height + | ||||
| 			h_reg * face.height - face_info.location_.y; | ||||
| 		face_info.score = score; | ||||
| 		face_info.rect.x = face.x + x_reg * face.width; | ||||
| 		face_info.rect.y = face.y + y_reg * face.height; | ||||
| 		face_info.rect.width = face.x + face.width + | ||||
| 			w_reg * face.width - face_info.rect.x; | ||||
| 		face_info.rect.height = face.y + face.height + | ||||
| 			h_reg * face.height - face_info.rect.y; | ||||
| 		second_bboxes->push_back(face_info); | ||||
| 	} | ||||
| 	return 0; | ||||
| @@ -195,14 +208,14 @@ int Mtcnn::ODetect(const ncnn::Mat & img_in, | ||||
| 	std::vector<FaceInfo>* third_bboxes) { | ||||
| 	third_bboxes->clear(); | ||||
| 	for (int i = 0; i < static_cast<int>(second_bboxes.size()); ++i) { | ||||
| 		Rect face = second_bboxes.at(i).location_ & Rect(0, 0, img_in.w, img_in.h); | ||||
| 		Rect face = second_bboxes.at(i).rect & Rect(0, 0, img_in.w, img_in.h); | ||||
| 		ncnn::Mat img_face, img_resized; | ||||
| 		ncnn::copy_cut_border(img_in, img_face, face.y, img_in.h - face.br().y, face.x, img_in.w - face.br().x); | ||||
| 		ncnn::resize_bilinear(img_face, img_resized, 48, 48); | ||||
|  | ||||
| 		ncnn::Extractor ex = onet_->create_extractor(); | ||||
| 		ex.set_light_mode(true); | ||||
| 		ex.set_num_threads(2); | ||||
| 		// ex.set_num_threads(2); | ||||
| 		ex.input("data", img_resized); | ||||
| 		ncnn::Mat score_mat, location_mat, keypoints_mat; | ||||
| 		ex.extract("prob1", score_mat); | ||||
| @@ -216,13 +229,13 @@ int Mtcnn::ODetect(const ncnn::Mat & img_in, | ||||
| 		float h_reg = location_mat[3]; | ||||
|  | ||||
| 		FaceInfo face_info; | ||||
| 		face_info.score_ = score; | ||||
| 		face_info.location_.x = face.x + x_reg * face.width; | ||||
| 		face_info.location_.y = face.y + y_reg * face.height; | ||||
| 		face_info.location_.width = face.x + face.width + | ||||
| 			w_reg * face.width - face_info.location_.x; | ||||
| 		face_info.location_.height = face.y + face.height + | ||||
| 			h_reg * face.height - face_info.location_.y; | ||||
| 		face_info.score = score; | ||||
| 		face_info.rect.x = face.x + x_reg * face.width; | ||||
| 		face_info.rect.y = face.y + y_reg * face.height; | ||||
| 		face_info.rect.width = face.x + face.width + | ||||
| 			w_reg * face.width - face_info.rect.x; | ||||
| 		face_info.rect.height = face.y + face.height + | ||||
| 			h_reg * face.height - face_info.rect.y; | ||||
|  | ||||
| 		for (int num = 0; num < 5; num++) { | ||||
| 			face_info.keypoints_[num] = face.x + face.width * keypoints_mat[num]; | ||||
| @@ -238,15 +251,15 @@ int Mtcnn::Refine(std::vector<FaceInfo>* bboxes, const Size max_size) { | ||||
| 	int num_boxes = static_cast<int>(bboxes->size()); | ||||
| 	for (int i = 0; i < num_boxes; ++i) { | ||||
| 		FaceInfo face_info = bboxes->at(i); | ||||
| 		int width = face_info.location_.width; | ||||
| 		int height = face_info.location_.height; | ||||
| 		int width = face_info.rect.width; | ||||
| 		int height = face_info.rect.height; | ||||
| 		float max_side = fmaxf(width, height); | ||||
|  | ||||
| 		face_info.location_.x = face_info.location_.x + 0.5 * width - 0.5 * max_side; | ||||
| 		face_info.location_.y = face_info.location_.y + 0.5 * height - 0.5 * max_side; | ||||
| 		face_info.location_.width = max_side; | ||||
| 		face_info.location_.height = max_side; | ||||
| 		face_info.location_ = face_info.location_ & Rect(0, 0, max_size.width, max_size.height); | ||||
| 		face_info.rect.x = face_info.rect.x + 0.5 * width - 0.5 * max_side; | ||||
| 		face_info.rect.y = face_info.rect.y + 0.5 * height - 0.5 * max_side; | ||||
| 		face_info.rect.width = max_side; | ||||
| 		face_info.rect.height = max_side; | ||||
| 		face_info.rect = face_info.rect & Rect(0, 0, max_size.width, max_size.height); | ||||
| 		bboxes->at(i) = face_info; | ||||
| 	} | ||||
| 	 | ||||
|   | ||||
| @@ -11,6 +11,7 @@ public: | ||||
| 	Mtcnn(); | ||||
| 	~Mtcnn(); | ||||
| 	int LoadModel(const char* root_path); | ||||
|     void set_num_threads(int n); | ||||
| 	int DetectFace(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces); | ||||
|   | ||||
| @@ -5,44 +5,26 @@ | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| RetinaFace::RetinaFace() : | ||||
| 	retina_net_(new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     retina_net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| } | ||||
|  | ||||
| RetinaFace::~RetinaFace() { | ||||
| 	if (retina_net_) { | ||||
| 		retina_net_->clear(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int RetinaFace::LoadModel(const char * root_path) { | ||||
| 	std::string fd_param = std::string(root_path) + "/param"; | ||||
| 	std::string fd_bin = std::string(root_path) + "/bin"; | ||||
| 	if (retina_net_->load_param(fd_param.c_str()) == -1 || | ||||
| 		retina_net_->load_model(fd_bin.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
|     int ret = Estimator::LoadModel(root_path); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
| 	// generate anchors | ||||
| 	for (int i = 0; i < 3; ++i) { | ||||
| 		ANCHORS anchors; | ||||
| 		if (0 == i) { | ||||
| 			GenerateAnchors(16, { 1.0f }, { 32, 16 }, &anchors); | ||||
| 			GenerateAnchors(16, { 1.0f }, { 32, 16 }, &anchors, num_threads); | ||||
| 		} | ||||
| 		else if (1 == i) { | ||||
| 			GenerateAnchors(16, { 1.0f }, { 8, 4 }, &anchors); | ||||
| 			GenerateAnchors(16, { 1.0f }, { 8, 4 }, &anchors, num_threads); | ||||
| 		} | ||||
| 		else { | ||||
| 			GenerateAnchors(16, { 1.0f }, { 2, 1 }, &anchors); | ||||
| 			GenerateAnchors(16, { 1.0f }, { 2, 1 }, &anchors, num_threads); | ||||
| 		} | ||||
| 		anchors_generated_.push_back(anchors); | ||||
| 	} | ||||
| 	initialized_ = true; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -60,7 +42,7 @@ int RetinaFace::DetectFace(const unsigned char* rgbdata, | ||||
|  | ||||
| 	float factor_x = static_cast<float>(img_width) / inputSize_.width; | ||||
| 	float factor_y = static_cast<float>(img_height) / inputSize_.height; | ||||
| 	ncnn::Extractor ex = retina_net_->create_extractor(); | ||||
| 	ncnn::Extractor ex = net_->create_extractor(); | ||||
| 	ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, | ||||
| 		ncnn::Mat::PIXEL_RGB, img_width, img_height, inputSize_.width, inputSize_.height); | ||||
| 	ex.input("data", in); | ||||
| @@ -131,8 +113,8 @@ int RetinaFace::DetectFace(const unsigned char* rgbdata, | ||||
| 						face_info.keypoints_[k + 5] = fminf(fmaxf(y * factor_y, 0.0f), img_height - 1); | ||||
| 					} | ||||
|  | ||||
| 					face_info.score_ = score; | ||||
| 					face_info.location_ = curr_box; | ||||
| 					face_info.score = score; | ||||
| 					face_info.rect = curr_box; | ||||
| 					faces_tmp.push_back(face_info); | ||||
| 				} | ||||
| 			} | ||||
|   | ||||
| @@ -5,20 +5,16 @@ | ||||
| #include "net.h" | ||||
|  | ||||
| namespace ovface { | ||||
| using ANCHORS = std::vector<Rect>; | ||||
| using ANCHORS = std::vector<ov::Rect>; | ||||
| class RetinaFace : public Detecter { | ||||
| public: | ||||
| 	RetinaFace(); | ||||
| 	~RetinaFace(); | ||||
| 	int LoadModel(const char* root_path); | ||||
| 	int DetectFace(const unsigned char* rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* retina_net_; | ||||
| 	std::vector<ANCHORS> anchors_generated_; | ||||
| 	bool initialized_; | ||||
| 	const int RPNs_[3] = { 32, 16, 8 }; | ||||
| 	const Size inputSize_ = { 300, 300 }; | ||||
| 	const float iouThreshold_ = 0.4f; | ||||
|   | ||||
							
								
								
									
										262
									
								
								src/face/detecter/scrfd/scrfd.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								src/face/detecter/scrfd/scrfd.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| #include "scrfd.hpp" | ||||
|  | ||||
| #ifdef OV_VULKAN | ||||
| #include "gpu.h" | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| static void generate_scrfd_proposals(const ncnn::Mat& anchors, int feat_stride, const ncnn::Mat& score_blob, const ncnn::Mat& bbox_blob, const ncnn::Mat& kps_blob, float prob_threshold, std::vector<FaceInfo>& faceobjects) | ||||
| { | ||||
|     int w = score_blob.w; | ||||
|     int h = score_blob.h; | ||||
|  | ||||
|     // generate face proposal from bbox deltas and shifted anchors | ||||
|     const int num_anchors = anchors.h; | ||||
|  | ||||
|     for (int q = 0; q < num_anchors; q++) | ||||
|     { | ||||
|         const float* anchor = anchors.row(q); | ||||
|  | ||||
|         const ncnn::Mat score = score_blob.channel(q); | ||||
|         const ncnn::Mat bbox = bbox_blob.channel_range(q * 4, 4); | ||||
|  | ||||
|         // shifted anchor | ||||
|         float anchor_y = anchor[1]; | ||||
|  | ||||
|         float anchor_w = anchor[2] - anchor[0]; | ||||
|         float anchor_h = anchor[3] - anchor[1]; | ||||
|  | ||||
|         for (int i = 0; i < h; i++) | ||||
|         { | ||||
|             float anchor_x = anchor[0]; | ||||
|  | ||||
|             for (int j = 0; j < w; j++) | ||||
|             { | ||||
|                 int index = i * w + j; | ||||
|  | ||||
|                 float prob = score[index]; | ||||
|  | ||||
|                 if (prob >= prob_threshold) | ||||
|                 { | ||||
|                     // insightface/detection/scrfd/mmdet/models/dense_heads/scrfd_head.py _get_bboxes_single() | ||||
|                     float dx = bbox.channel(0)[index] * feat_stride; | ||||
|                     float dy = bbox.channel(1)[index] * feat_stride; | ||||
|                     float dw = bbox.channel(2)[index] * feat_stride; | ||||
|                     float dh = bbox.channel(3)[index] * feat_stride; | ||||
|  | ||||
|                     // insightface/detection/scrfd/mmdet/core/bbox/transforms.py distance2bbox() | ||||
|                     float cx = anchor_x + anchor_w * 0.5f; | ||||
|                     float cy = anchor_y + anchor_h * 0.5f; | ||||
|  | ||||
|                     float x0 = cx - dx; | ||||
|                     float y0 = cy - dy; | ||||
|                     float x1 = cx + dw; | ||||
|                     float y1 = cy + dh; | ||||
|  | ||||
|                     FaceInfo obj; | ||||
|                     obj.rect.x = x0; | ||||
|                     obj.rect.y = y0; | ||||
|                     obj.rect.width = x1 - x0 + 1; | ||||
|                     obj.rect.height = y1 - y0 + 1; | ||||
|                     obj.score = prob; | ||||
|  | ||||
|                     if (!kps_blob.empty()) | ||||
|                     { | ||||
|                         const ncnn::Mat kps = kps_blob.channel_range(q * 10, 10); | ||||
|  | ||||
|                         obj.keypoints_[0] = cx + kps.channel(0)[index] * feat_stride; | ||||
|                         obj.keypoints_[5] = cy + kps.channel(1)[index] * feat_stride; | ||||
|                         obj.keypoints_[1] = cx + kps.channel(2)[index] * feat_stride; | ||||
|                         obj.keypoints_[6] = cy + kps.channel(3)[index] * feat_stride; | ||||
|                         obj.keypoints_[2] = cx + kps.channel(4)[index] * feat_stride; | ||||
|                         obj.keypoints_[7] = cy + kps.channel(5)[index] * feat_stride; | ||||
|                         obj.keypoints_[3] = cx + kps.channel(6)[index] * feat_stride; | ||||
|                         obj.keypoints_[8] = cy + kps.channel(7)[index] * feat_stride; | ||||
|                         obj.keypoints_[4] = cx + kps.channel(8)[index] * feat_stride; | ||||
|                         obj.keypoints_[9] = cy + kps.channel(9)[index] * feat_stride; | ||||
|                     } | ||||
|  | ||||
|                     faceobjects.push_back(obj); | ||||
|                 } | ||||
|  | ||||
|                 anchor_x += feat_stride; | ||||
|             } | ||||
|  | ||||
|             anchor_y += feat_stride; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| int Scrfd::DetectFace(const unsigned char* rgbdata, | ||||
|     int img_width, int img_height,  | ||||
|     std::vector<FaceInfo>* faces) { | ||||
|     faces->clear(); | ||||
| 	if (!initialized_) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	if (rgbdata == 0){ | ||||
| 		return 10001; | ||||
|     } | ||||
|  | ||||
|     // pad to multiple of 32 | ||||
|     int w = img_width; | ||||
|     int h = img_height; | ||||
|     float scale = 1.f; | ||||
|     if (w > h) | ||||
|     { | ||||
|         scale = (float)target_size / w; | ||||
|         w = target_size; | ||||
|         h = h * scale; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         scale = (float)target_size / h; | ||||
|         h = target_size; | ||||
|         w = w * scale; | ||||
|     } | ||||
|  | ||||
|     ncnn::Mat in = ncnn::Mat::from_pixels_resize(rgbdata, ncnn::Mat::PIXEL_RGB, img_width, img_height, w, h); | ||||
|  | ||||
|     // pad to target_size rectangle | ||||
|     float wpad = (float)(w + 31) / 32 * 32 - w; | ||||
|     float hpad = (float)(h + 31) / 32 * 32 - h; | ||||
|     ncnn::Mat in_pad; | ||||
|     ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2, wpad / 2, wpad - wpad / 2, ncnn::BORDER_CONSTANT, 0.f); | ||||
|  | ||||
|     const float mean_vals[3] = {127.5f, 127.5f, 127.5f}; | ||||
|     const float norm_vals[3] = {1/128.f, 1/128.f, 1/128.f}; | ||||
|     in_pad.substract_mean_normalize(mean_vals, norm_vals); | ||||
|  | ||||
|     ncnn::Extractor ex = net_->create_extractor(); | ||||
|  | ||||
|     ex.input("input.1", in_pad); | ||||
|  | ||||
|     std::vector<FaceInfo> faceproposals; | ||||
|  | ||||
|     // stride 8 | ||||
|     { | ||||
|         ncnn::Mat score_blob, bbox_blob, kps_blob; | ||||
|         ex.extract("score_8", score_blob); | ||||
|         ex.extract("bbox_8", bbox_blob); | ||||
|         if (has_kps) | ||||
|             ex.extract("kps_8", kps_blob); | ||||
|  | ||||
|         const int base_size = 16; | ||||
|         const int feat_stride = 8; | ||||
|         ncnn::Mat ratios(1); | ||||
|         ratios[0] = 1.f; | ||||
|         ncnn::Mat scales(2); | ||||
|         scales[0] = 1.f; | ||||
|         scales[1] = 2.f; | ||||
|         ncnn::Mat anchors = ov::generate_anchors(base_size, ratios, scales); | ||||
|  | ||||
|         std::vector<FaceInfo> faceobjects32; | ||||
|         generate_scrfd_proposals(anchors, feat_stride, score_blob, bbox_blob, kps_blob, prob_threshold, faceobjects32); | ||||
|  | ||||
|         faceproposals.insert(faceproposals.end(), faceobjects32.begin(), faceobjects32.end()); | ||||
|     } | ||||
|  | ||||
|     // stride 16 | ||||
|     { | ||||
|         ncnn::Mat score_blob, bbox_blob, kps_blob; | ||||
|         ex.extract("score_16", score_blob); | ||||
|         ex.extract("bbox_16", bbox_blob); | ||||
|         if (has_kps) | ||||
|             ex.extract("kps_16", kps_blob); | ||||
|  | ||||
|         const int base_size = 64; | ||||
|         const int feat_stride = 16; | ||||
|         ncnn::Mat ratios(1); | ||||
|         ratios[0] = 1.f; | ||||
|         ncnn::Mat scales(2); | ||||
|         scales[0] = 1.f; | ||||
|         scales[1] = 2.f; | ||||
|         ncnn::Mat anchors = ov::generate_anchors(base_size, ratios, scales); | ||||
|  | ||||
|         std::vector<FaceInfo> faceobjects16; | ||||
|         generate_scrfd_proposals(anchors, feat_stride, score_blob, bbox_blob, kps_blob, prob_threshold, faceobjects16); | ||||
|  | ||||
|         faceproposals.insert(faceproposals.end(), faceobjects16.begin(), faceobjects16.end()); | ||||
|     } | ||||
|  | ||||
|     // stride 32 | ||||
|     { | ||||
|         ncnn::Mat score_blob, bbox_blob, kps_blob; | ||||
|         ex.extract("score_32", score_blob); | ||||
|         ex.extract("bbox_32", bbox_blob); | ||||
|         if (has_kps) | ||||
|             ex.extract("kps_32", kps_blob); | ||||
|  | ||||
|         const int base_size = 256; | ||||
|         const int feat_stride = 32; | ||||
|         ncnn::Mat ratios(1); | ||||
|         ratios[0] = 1.f; | ||||
|         ncnn::Mat scales(2); | ||||
|         scales[0] = 1.f; | ||||
|         scales[1] = 2.f; | ||||
|         ncnn::Mat anchors = ov::generate_anchors(base_size, ratios, scales); | ||||
|  | ||||
|         std::vector<FaceInfo> faceobjects8; | ||||
|         generate_scrfd_proposals(anchors, feat_stride, score_blob, bbox_blob, kps_blob, prob_threshold, faceobjects8); | ||||
|  | ||||
|         faceproposals.insert(faceproposals.end(), faceobjects8.begin(), faceobjects8.end()); | ||||
|     } | ||||
|  | ||||
|     // sort all proposals by score from highest to lowest | ||||
|     qsort_descent_inplace(faceproposals); | ||||
|  | ||||
|     // apply nms with nms_threshold | ||||
|     std::vector<int> picked; | ||||
|     nms_sorted_bboxes(faceproposals, picked, nms_threshold); | ||||
|  | ||||
|     int face_count = picked.size(); | ||||
|  | ||||
|     for (int i = 0; i < face_count; i++) | ||||
|     { | ||||
|         FaceInfo obj = faceproposals[picked[i]]; | ||||
|  | ||||
|         // adjust offset to original unpadded | ||||
|         float x0 = (obj.rect.x - (wpad / 2)) / scale; | ||||
|         float y0 = (obj.rect.y - (hpad / 2)) / scale; | ||||
|         float x1 = (obj.rect.x + obj.rect.width - (wpad / 2)) / scale; | ||||
|         float y1 = (obj.rect.y + obj.rect.height - (hpad / 2)) / scale; | ||||
|  | ||||
|         x0 = std::max(std::min(x0, (float)img_width - 1), 0.f); | ||||
|         y0 = std::max(std::min(y0, (float)img_height - 1), 0.f); | ||||
|         x1 = std::max(std::min(x1, (float)img_width - 1), 0.f); | ||||
|         y1 = std::max(std::min(y1, (float)img_height - 1), 0.f); | ||||
|  | ||||
|         obj.rect.x = x0; | ||||
|         obj.rect.y = y0; | ||||
|         obj.rect.width = x1 - x0; | ||||
|         obj.rect.height = y1 - y0; | ||||
|  | ||||
|         if (has_kps) | ||||
|         { | ||||
|             float x0 = (obj.keypoints_[0] - (wpad / 2)) / scale; | ||||
|             float y0 = (obj.keypoints_[5] - (hpad / 2)) / scale; | ||||
|             float x1 = (obj.keypoints_[1] - (wpad / 2)) / scale; | ||||
|             float y1 = (obj.keypoints_[6] - (hpad / 2)) / scale; | ||||
|             float x2 = (obj.keypoints_[2] - (wpad / 2)) / scale; | ||||
|             float y2 = (obj.keypoints_[7] - (hpad / 2)) / scale; | ||||
|             float x3 = (obj.keypoints_[3] - (wpad / 2)) / scale; | ||||
|             float y3 = (obj.keypoints_[8] - (hpad / 2)) / scale; | ||||
|             float x4 = (obj.keypoints_[4] - (wpad / 2)) / scale; | ||||
|             float y4 = (obj.keypoints_[9] - (hpad / 2)) / scale; | ||||
|  | ||||
|             obj.keypoints_[0] = std::max(std::min(x0, (float)img_width - 1), 0.f); | ||||
|             obj.keypoints_[5] = std::max(std::min(y0, (float)img_height - 1), 0.f); | ||||
|             obj.keypoints_[1] = std::max(std::min(x1, (float)img_width - 1), 0.f); | ||||
|             obj.keypoints_[6] = std::max(std::min(y1, (float)img_height - 1), 0.f); | ||||
|             obj.keypoints_[2] = std::max(std::min(x2, (float)img_width - 1), 0.f); | ||||
|             obj.keypoints_[7] = std::max(std::min(y2, (float)img_height - 1), 0.f); | ||||
|             obj.keypoints_[3] = std::max(std::min(x3, (float)img_width - 1), 0.f); | ||||
|             obj.keypoints_[8] = std::max(std::min(y3, (float)img_height - 1), 0.f); | ||||
|             obj.keypoints_[4] = std::max(std::min(x4, (float)img_width - 1), 0.f); | ||||
|             obj.keypoints_[9] = std::max(std::min(y4, (float)img_height - 1), 0.f); | ||||
|         } | ||||
|         faces->push_back(obj); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| } | ||||
							
								
								
									
										26
									
								
								src/face/detecter/scrfd/scrfd.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/face/detecter/scrfd/scrfd.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| #ifndef _SCRFD_DETECT_H_ | ||||
| #define _SCRFD_DETECT_H_ | ||||
|  | ||||
| #include "../detecter.hpp" | ||||
| #include "net.h" | ||||
|  | ||||
| namespace ovface { | ||||
| class Scrfd : public Detecter { | ||||
| public: | ||||
| 	int DetectFace(const unsigned char* rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces); | ||||
|  | ||||
| private: | ||||
|     const int target_size = 640; | ||||
|     const float meanVals[3] = { 123.675f, 116.28f,  103.53f }; | ||||
|     const float normVals[3] = { 0.01712475f, 0.0175f, 0.01742919f }; | ||||
|     const float prob_threshold = 0.5f; | ||||
|     const float nms_threshold = 0.45f; | ||||
|     const bool has_kps = false; | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif // !_RETINAFACE_H_ | ||||
|  | ||||
| @@ -92,7 +92,7 @@ static void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn: | ||||
|                     obj.rect.width = x1 - x0; | ||||
|                     obj.rect.height = y1 - y0; | ||||
|                     obj.label = class_index; | ||||
|                     obj.prob = confidence; | ||||
|                     obj.score = confidence; | ||||
|  | ||||
| 					for (int l = 0; l < 5; l++) | ||||
| 					{ | ||||
| @@ -107,28 +107,10 @@ static void generate_proposals(const ncnn::Mat& anchors, int stride, const ncnn: | ||||
|     } | ||||
| } | ||||
|  | ||||
| YoloFace::YoloFace() :  | ||||
|     net_ (new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| YoloFace::~YoloFace() { | ||||
|     net_->clear(); | ||||
| } | ||||
|  | ||||
| int YoloFace::LoadModel(const char * root_path) { | ||||
|     register_yolov5focus(net_); | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (net_->load_param(param_file.c_str()) == -1 || | ||||
| 		net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	initialized_ = true; | ||||
| 	return 0; | ||||
|     return Estimator::LoadModel(root_path); | ||||
| } | ||||
|  | ||||
| int YoloFace::DetectFace(const unsigned char* rgbdata, | ||||
| @@ -274,7 +256,7 @@ int YoloFace::DetectFace(const unsigned char* rgbdata, | ||||
|         obj.rect.height = y1 - y0; | ||||
|  | ||||
|         FaceInfo info; | ||||
|         info.location_ = obj.rect; | ||||
|         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; | ||||
|   | ||||
| @@ -7,16 +7,12 @@ | ||||
| namespace ovface { | ||||
| class YoloFace : public Detecter { | ||||
| public: | ||||
| 	YoloFace(); | ||||
| 	~YoloFace(); | ||||
| 	int LoadModel(const char* root_path); | ||||
|     int LoadModel(const char * root_path); | ||||
| 	int DetectFace(const unsigned char* rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<FaceInfo>* faces); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* net_; | ||||
| 	bool initialized_; | ||||
|     const int target_size = 640; | ||||
|     const float mean_vals[3] = {127.f, 127.f, 127.f}; | ||||
|     const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f}; | ||||
|   | ||||
| @@ -21,34 +21,15 @@ namespace ovface { | ||||
| #define NEAR_0 1e-10 | ||||
| #define ODIM   66 | ||||
|  | ||||
| Hopenet::Hopenet(): | ||||
|     net_(new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| Hopenet::~Hopenet() { | ||||
| 	if (net_) { | ||||
| 		net_->clear(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int Hopenet::LoadModel(const char * root_path) { | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (net_->load_param(param_file.c_str()) == -1 || | ||||
| 		net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| int Hopenet::LoadModel(const char* root_path) { | ||||
|     int ret = Estimator::LoadModel(root_path); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
|     for (uint i=1; i<67; i++) idx_tensor[i-1] = i; | ||||
| 	initialized_ = true; | ||||
|  | ||||
| 	return 0; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| int Hopenet::Detect(const unsigned char* rgbdata,  | ||||
|     int img_width, int img_height, | ||||
|     Rect roi, HeadPose* head_angles) { | ||||
| @@ -80,15 +61,15 @@ int Hopenet::Detect(const unsigned char* rgbdata, | ||||
|     float* pred_roll  = output.range(ODIM, ODIM*2); | ||||
|     float* pred_yaw   = output.range(ODIM*2, ODIM*3); | ||||
|  | ||||
|     softmax(pred_pitch, ODIM); | ||||
|     softmax(pred_roll,  ODIM); | ||||
|     softmax(pred_yaw,   ODIM); | ||||
|     this->softmax(pred_pitch, ODIM); | ||||
|     this->softmax(pred_roll,  ODIM); | ||||
|     this->softmax(pred_yaw,   ODIM); | ||||
|  | ||||
|     // printArray(pred_pitch, ODIM); | ||||
|  | ||||
|     head_angles->pitch = getAngle(pred_pitch, ODIM); | ||||
|     head_angles->roll  = getAngle(pred_roll,  ODIM); | ||||
|     head_angles->yaw   = getAngle(pred_yaw,   ODIM); | ||||
|     head_angles->pitch = this->getAngle(pred_pitch, ODIM); | ||||
|     head_angles->roll  = this->getAngle(pred_roll,  ODIM); | ||||
|     head_angles->yaw   = this->getAngle(pred_yaw,   ODIM); | ||||
|  | ||||
|     free(img_face); | ||||
|  | ||||
|   | ||||
| @@ -7,16 +7,12 @@ | ||||
| namespace ovface { | ||||
| class Hopenet : public ov::Estimator { | ||||
| public: | ||||
|     Hopenet(); | ||||
|     ~Hopenet(); | ||||
| 	int LoadModel(const char* root_path); | ||||
|     int LoadModel(const char* root_path); | ||||
|     int Detect(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
|         Rect roi, HeadPose* euler_angles); | ||||
|  | ||||
| private: | ||||
|     ncnn::Net* net_; | ||||
|     bool initialized_; | ||||
|     float idx_tensor[66]; | ||||
|     void softmax(float* z, size_t el); | ||||
|     double getAngle(float* prediction, size_t len); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ extern "C" { | ||||
|     typedef void* IFaceLandmarker; | ||||
|     IFaceLandmarker new_insightface(); | ||||
|     IFaceLandmarker new_zq(); | ||||
|     IFaceLandmarker new_scrfd_landmarker(); | ||||
|     int extract_face_keypoints(IFaceLandmarker m, const unsigned char* rgbdata, int img_width, int img_height, const Rect* face, Point2fVector* keypoints);  | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|   | ||||
| @@ -6,34 +6,12 @@ | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| InsightfaceLandmarker::InsightfaceLandmarker() { | ||||
| 	insightface_landmarker_net_ = new ncnn::Net(); | ||||
| 	initialized = false; | ||||
| #ifdef OV_VULKAN | ||||
|     insightface_landmarker_net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| InsightfaceLandmarker::~InsightfaceLandmarker() { | ||||
| 	insightface_landmarker_net_->clear(); | ||||
| } | ||||
|  | ||||
| int InsightfaceLandmarker::LoadModel(const char * root_path) { | ||||
| 	std::string fl_param = std::string(root_path) + "/param"; | ||||
| 	std::string fl_bin = std::string(root_path) + "/bin"; | ||||
| 	if (insightface_landmarker_net_->load_param(fl_param.c_str()) == -1 || | ||||
| 		insightface_landmarker_net_->load_model(fl_bin.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	initialized = true; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int InsightfaceLandmarker::ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|     int img_width, int img_height, | ||||
| 	const ov::Rect & face, std::vector<ov::Point2f>* keypoints) { | ||||
| 	keypoints->clear(); | ||||
| 	if (!initialized) { | ||||
| 	if (!initialized_) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
| @@ -42,7 +20,7 @@ int InsightfaceLandmarker::ExtractKeypoints(const unsigned char* rgbdata, | ||||
| 	} | ||||
|  | ||||
| 	// 1 enlarge the face rect | ||||
| 	Rect face_enlarged = face;  | ||||
|     ov::Rect face_enlarged = face;  | ||||
| 	const float enlarge_scale = 1.5f; | ||||
| 	EnlargeRect(enlarge_scale, &face_enlarged); | ||||
|  | ||||
| @@ -61,7 +39,7 @@ int InsightfaceLandmarker::ExtractKeypoints(const unsigned char* rgbdata, | ||||
|     } | ||||
|  | ||||
| 	// 4 do inference | ||||
| 	ncnn::Extractor ex = insightface_landmarker_net_->create_extractor(); | ||||
| 	ncnn::Extractor ex = net_->create_extractor(); | ||||
| 	ncnn::Mat in = ncnn::Mat::from_pixels_resize(img_face, | ||||
| 		ncnn::Mat::PIXEL_RGB, face_enlarged.width, face_enlarged.height, 192, 192); | ||||
| 	ex.input("data", in); | ||||
|   | ||||
| @@ -7,17 +7,10 @@ | ||||
| namespace ovface { | ||||
| class InsightfaceLandmarker : public Landmarker { | ||||
| public: | ||||
| 	InsightfaceLandmarker(); | ||||
| 	~InsightfaceLandmarker(); | ||||
|  | ||||
| 	int LoadModel(const char* root_path); | ||||
| 	int ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
| 		const ov::Rect& face, std::vector<ov::Point2f>* keypoints); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* insightface_landmarker_net_; | ||||
| 	bool initialized; | ||||
| }; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #include "../landmarker.h" | ||||
| #include "zqlandmarker/zqlandmarker.hpp" | ||||
| #include "insightface/insightface.hpp" | ||||
| #include "scrfd/scrfd.hpp" | ||||
|  | ||||
| IFaceLandmarker new_zq() { | ||||
|     return new ovface::ZQLandmarker(); | ||||
| @@ -10,6 +11,10 @@ IFaceLandmarker new_insightface() { | ||||
|     return new ovface::InsightfaceLandmarker(); | ||||
| } | ||||
|  | ||||
| IFaceLandmarker new_scrfd_landmarker() { | ||||
|     return new ovface::ScrfdLandmarker(); | ||||
| } | ||||
|  | ||||
| int extract_face_keypoints( | ||||
|     IFaceLandmarker m,  | ||||
|     const unsigned char* rgbdata,  | ||||
| @@ -39,4 +44,8 @@ Landmarker* InsightfaceLandmarkerFactory::CreateLandmarker() { | ||||
| 	return new InsightfaceLandmarker(); | ||||
| } | ||||
|  | ||||
| Landmarker* ScrfdLandmarkerFactory::CreateLandmarker() { | ||||
| 	return new ScrfdLandmarker(); | ||||
| } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ namespace ovface { | ||||
| // 抽象类 | ||||
| class Landmarker: public ov::Estimator { | ||||
| public: | ||||
| 	virtual ~Landmarker() {}; | ||||
| 	virtual int ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
| 		const Rect& face, std::vector<Point2f>* keypoints) = 0; | ||||
| @@ -35,6 +34,13 @@ public: | ||||
| 	~InsightfaceLandmarkerFactory() {} | ||||
| }; | ||||
|  | ||||
| class ScrfdLandmarkerFactory : public LandmarkerFactory { | ||||
| public: | ||||
| 	ScrfdLandmarkerFactory(){} | ||||
| 	Landmarker* CreateLandmarker(); | ||||
| 	~ScrfdLandmarkerFactory() {} | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif // !_FACE_LANDMARKER_H_ | ||||
|   | ||||
							
								
								
									
										57
									
								
								src/face/landmarker/scrfd/scrfd.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/face/landmarker/scrfd/scrfd.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| #include "scrfd.hpp" | ||||
|  | ||||
| #ifdef OV_VULKAN | ||||
| #include "gpu.h" | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
|  | ||||
| int ScrfdLandmarker::ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|     int img_width, int img_height, | ||||
| 	const ov::Rect & face, std::vector<ov::Point2f>* keypoints) { | ||||
| 	keypoints->clear(); | ||||
| 	if (!initialized_) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
| 	if (rgbdata == 0){ | ||||
| 		return 10001; | ||||
| 	} | ||||
| 	// 1 enlarge the face rect | ||||
|     ov::Rect box = face;  | ||||
| 	const float enlarge_scale = 1.5f; | ||||
| 	EnlargeRect(enlarge_scale, &box); | ||||
|  | ||||
| 	// 2 square the rect | ||||
| 	RectifyRect(&box); | ||||
|  | ||||
|     box = box & Rect(0, 0, img_width, img_height); | ||||
|  | ||||
|     size_t total_size = box.width * box.height * 3 * sizeof(unsigned char); | ||||
|     unsigned char* img_face = (unsigned char*)malloc(total_size); | ||||
|     const unsigned char *start_ptr = rgbdata; | ||||
|     for(size_t i = 0; i < box.height; ++i) { | ||||
|         const unsigned char* srcCursor = start_ptr + ((i + box.y) * img_width + box.x) * 3;  | ||||
|         unsigned char* dstCursor = img_face + i * box.width * 3; | ||||
|         memcpy(dstCursor, srcCursor, sizeof(unsigned char) * 3 * box.width); | ||||
|     } | ||||
|      | ||||
|     ncnn::Extractor ex = net_->create_extractor(); | ||||
|     ncnn::Mat ncnn_in = ncnn::Mat::from_pixels_resize(img_face, ncnn::Mat::PIXEL_RGB, box.width, box.height, 192, 192); | ||||
|     ncnn_in.substract_mean_normalize(means, norms); | ||||
|     ex.input("input.1",ncnn_in); | ||||
|     ncnn::Mat ncnn_out; | ||||
|     ex.extract("482",ncnn_out); | ||||
|     float *scoredata = (float*)ncnn_out.data; | ||||
|     for(int i = 0; i < 468; i++) | ||||
|     { | ||||
|         ov::Point2f pt; | ||||
|         pt.x = scoredata[i*3]*box.width/192 + box.x; | ||||
|         pt.y = scoredata[i*3+1]*box.height/192 + box.y; | ||||
|         keypoints->push_back(pt); | ||||
|     } | ||||
|  | ||||
|     free(img_face); | ||||
|     return 0; | ||||
| } | ||||
| } | ||||
							
								
								
									
										22
									
								
								src/face/landmarker/scrfd/scrfd.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/face/landmarker/scrfd/scrfd.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #ifndef _FACE_SCRFD_LANDMARKER_H_ | ||||
| #define _FACE_SCRFD_LANDMARKER_H_ | ||||
|  | ||||
| #include "../landmarker.hpp" | ||||
| #include "net.h" | ||||
|  | ||||
| namespace ovface { | ||||
| class ScrfdLandmarker : public Landmarker { | ||||
| public: | ||||
| 	int ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
| 		const ov::Rect& face, std::vector<ov::Point2f>* keypoints); | ||||
|  | ||||
| private: | ||||
|     const float means[3] = { 127.5f, 127.5f,  127.5f }; | ||||
|     const float norms[3] = { 1/127.5f, 1 / 127.5f, 1 / 127.5f }; | ||||
| }; | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif // !_FACE_SCRFD_ANDMARKER_H_ | ||||
|  | ||||
| @@ -1,39 +1,16 @@ | ||||
| #include "zqlandmarker.hpp" | ||||
| #include <string> | ||||
|  | ||||
| #ifdef OV_VULKAN | ||||
| #include "gpu.h" | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| ZQLandmarker::ZQLandmarker() { | ||||
| 	zq_landmarker_net_ = new ncnn::Net(); | ||||
| 	initialized = false; | ||||
| #ifdef OV_VULKAN | ||||
|     zq_landmarker_net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| ZQLandmarker::~ZQLandmarker() { | ||||
| 	zq_landmarker_net_->clear(); | ||||
| } | ||||
|  | ||||
| int ZQLandmarker::LoadModel(const char * root_path) { | ||||
| 	std::string fl_param = std::string(root_path) + "/param"; | ||||
| 	std::string fl_bin = std::string(root_path) + "/bin"; | ||||
| 	if (zq_landmarker_net_->load_param(fl_param.c_str()) == -1 || | ||||
| 		zq_landmarker_net_->load_model(fl_bin.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	initialized = true; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int ZQLandmarker::ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|     int img_width, int img_height, | ||||
| 	const ov::Rect & face, std::vector<ov::Point2f>* keypoints) { | ||||
| 	keypoints->clear(); | ||||
| 	if (!initialized) { | ||||
| 	if (!initialized_) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
| @@ -49,7 +26,7 @@ int ZQLandmarker::ExtractKeypoints(const unsigned char* rgbdata, | ||||
|         unsigned char* dstCursor = img_face + i * face.width * 3; | ||||
|         memcpy(dstCursor, srcCursor, sizeof(unsigned char) * 3 * face.width); | ||||
|     } | ||||
| 	ncnn::Extractor ex = zq_landmarker_net_->create_extractor(); | ||||
| 	ncnn::Extractor ex = net_->create_extractor(); | ||||
| 	ncnn::Mat in = ncnn::Mat::from_pixels_resize(img_face, | ||||
| 		ncnn::Mat::PIXEL_RGB, face.width, face.height, 112, 112); | ||||
| 	in.substract_mean_normalize(meanVals, normVals); | ||||
|   | ||||
| @@ -7,19 +7,13 @@ | ||||
| namespace ovface { | ||||
| class ZQLandmarker : public Landmarker { | ||||
| public: | ||||
| 	ZQLandmarker(); | ||||
| 	~ZQLandmarker(); | ||||
|  | ||||
| 	int LoadModel(const char* root_path); | ||||
| 	int ExtractKeypoints(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
| 		const ov::Rect& face, std::vector<ov::Point2f>* keypoints); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* zq_landmarker_net_; | ||||
| 	const float meanVals[3] = { 127.5f, 127.5f, 127.5f }; | ||||
| 	const float normVals[3] = { 0.0078125f, 0.0078125f, 0.0078125f }; | ||||
| 	bool initialized; | ||||
| }; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -5,29 +5,6 @@ | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovface { | ||||
| Mobilefacenet::Mobilefacenet() { | ||||
| 	mobileface_net_ = new ncnn::Net(); | ||||
| 	initialized_ = false; | ||||
| #ifdef OV_VULKAN | ||||
|     mobileface_net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| Mobilefacenet::~Mobilefacenet() { | ||||
| 	mobileface_net_->clear(); | ||||
| } | ||||
|  | ||||
| int Mobilefacenet::LoadModel(const char * root_path) { | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (mobileface_net_->load_param(param_file.c_str()) == -1 || | ||||
| 		mobileface_net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
|  | ||||
| 	initialized_ = true; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int Mobilefacenet::ExtractFeature(const unsigned char* rgbdata,  | ||||
|     int img_width, int img_height, | ||||
| @@ -52,7 +29,7 @@ int Mobilefacenet::ExtractFeature(const unsigned char* rgbdata, | ||||
| 	ncnn::Mat in = ncnn::Mat::from_pixels_resize(img_face, | ||||
| 		ncnn::Mat::PIXEL_RGB, face.width, face.height, 112, 112); | ||||
| 	feature->resize(kFaceFeatureDim); | ||||
| 	ncnn::Extractor ex = mobileface_net_->create_extractor(); | ||||
| 	ncnn::Extractor ex = net_->create_extractor(); | ||||
| 	ex.input("data", in); | ||||
| 	ncnn::Mat out; | ||||
| 	ex.extract("fc1", out); | ||||
|   | ||||
| @@ -9,18 +9,11 @@ namespace ovface { | ||||
|  | ||||
| class Mobilefacenet : public Recognizer { | ||||
| public: | ||||
| 	Mobilefacenet(); | ||||
| 	~Mobilefacenet(); | ||||
|  | ||||
| 	int LoadModel(const char* root_path); | ||||
| 	int ExtractFeature(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
|         const ov::Rect& face, | ||||
|         std::vector<float>* feature); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* mobileface_net_; | ||||
| 	bool initialized_; | ||||
| }; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| namespace ovface { | ||||
| class Recognizer: public ov::Estimator { | ||||
| public: | ||||
| 	virtual ~Recognizer() {}; | ||||
| 	virtual int ExtractFeature(const unsigned char* rgbdata,  | ||||
|         int img_width, int img_height, | ||||
|         const ov::Rect& face, | ||||
|   | ||||
| @@ -45,8 +45,8 @@ int Tracker::Track(const std::vector<FaceInfo>& curr_faces, std::vector<TrackedF | ||||
|     for (int i = 0; i < num_faces; ++i) { | ||||
|         auto& face = curr_faces.at(i); | ||||
|         for (auto scored_tracked_face : scored_tracked_faces) { | ||||
|             ComputeIOU(scored_tracked_face.face_info_.location_, | ||||
|                 face.location_, &scored_tracked_face.iou_score_); | ||||
|             ComputeIOU(scored_tracked_face.face_info_.rect, | ||||
|                 face.rect, &scored_tracked_face.iou_score_); | ||||
|         } | ||||
|         if (scored_tracked_faces.size() > 0) { | ||||
|             std::partial_sort(scored_tracked_faces.begin(), | ||||
| @@ -61,10 +61,10 @@ int Tracker::Track(const std::vector<FaceInfo>& curr_faces, std::vector<TrackedF | ||||
| 			scored_tracked_faces.pop_front(); | ||||
| 			TrackedFaceInfo &tracked_face = matched_face; | ||||
| 			if (matched_face.iou_score_ < maxScore_) { | ||||
| 				tracked_face.face_info_.location_.x = (tracked_face.face_info_.location_.x + face.location_.x) / 2; | ||||
| 				tracked_face.face_info_.location_.y = (tracked_face.face_info_.location_.y + face.location_.y) / 2; | ||||
| 				tracked_face.face_info_.location_.width = (tracked_face.face_info_.location_.width + face.location_.width) / 2; | ||||
| 				tracked_face.face_info_.location_.height = (tracked_face.face_info_.location_.height + face.location_.height) / 2; | ||||
| 				tracked_face.face_info_.rect.x = (tracked_face.face_info_.rect.x + face.rect.x) / 2; | ||||
| 				tracked_face.face_info_.rect.y = (tracked_face.face_info_.rect.y + face.rect.y) / 2; | ||||
| 				tracked_face.face_info_.rect.width = (tracked_face.face_info_.rect.width + face.rect.width) / 2; | ||||
| 				tracked_face.face_info_.rect.height = (tracked_face.face_info_.rect.height + face.rect.height) / 2; | ||||
| 			} else { | ||||
| 				tracked_face.face_info_ = face; | ||||
| 			} | ||||
|   | ||||
| @@ -23,7 +23,7 @@ int extract_hand_rois(IHandDetecter d, const unsigned char* rgbdata, int img_wid | ||||
|         ov::ObjectInfo o = detected[i]; | ||||
|         rois->items[i] = ObjectInfo{ | ||||
|             o.rect, | ||||
|             o.prob, | ||||
|             o.score, | ||||
|             o.label, | ||||
|             NULL | ||||
|         }; | ||||
|   | ||||
| @@ -5,7 +5,6 @@ | ||||
| namespace ovhand { | ||||
| class Detecter: public ov::Estimator { | ||||
| public: | ||||
|     virtual ~Detecter() {}; | ||||
|     virtual int Detect(const unsigned char*rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<ov::ObjectInfo>& rois) = 0; | ||||
|   | ||||
| @@ -62,7 +62,7 @@ static void generate_nanodet_proposals(const ncnn::Mat& cls_pred, const ncnn::Ma | ||||
|                     softmax->load_param(pd); | ||||
|  | ||||
|                     ncnn::Option opt; | ||||
|                     opt.num_threads = 1; | ||||
|                     // opt.num_threads = 1; | ||||
|                     opt.use_packing_layout = false; | ||||
|  | ||||
|                     softmax->create_pipeline(opt); | ||||
| @@ -101,7 +101,7 @@ static void generate_nanodet_proposals(const ncnn::Mat& cls_pred, const ncnn::Ma | ||||
|                 obj.rect.width = x1 - x0; | ||||
|                 obj.rect.height = y1 - y0; | ||||
|                 obj.label = label; | ||||
|                 obj.prob = score; | ||||
|                 obj.score= score; | ||||
|  | ||||
|                 objects.push_back(obj); | ||||
|             } | ||||
| @@ -109,29 +109,6 @@ static void generate_nanodet_proposals(const ncnn::Mat& cls_pred, const ncnn::Ma | ||||
|     } | ||||
| } | ||||
|  | ||||
| Nanodet::Nanodet() :  | ||||
|     net_ (new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| Nanodet::~Nanodet() { | ||||
|     net_->clear(); | ||||
| } | ||||
|  | ||||
| int Nanodet::LoadModel(const char * root_path) { | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (net_->load_param(param_file.c_str()) == -1 || | ||||
| 		net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	initialized_ = true; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int Nanodet::Detect(const unsigned char* rgbdata, | ||||
|     int img_width, int img_height,  | ||||
|     std::vector<ov::ObjectInfo>& rois) { | ||||
|   | ||||
| @@ -9,17 +9,11 @@ namespace ovhand { | ||||
|  | ||||
| class Nanodet : public Detecter { | ||||
| public: | ||||
|     Nanodet(); | ||||
|     ~Nanodet(); | ||||
|  | ||||
|     int LoadModel(const char* root_path); | ||||
|     int Detect(const unsigned char* rgbadata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<ov::ObjectInfo>& rois); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* net_; | ||||
|     bool initialized_; | ||||
|     const int target_size = 320; | ||||
|     const float mean_vals[3] = {103.53f, 116.28f, 123.675f}; | ||||
|     const float norm_vals[3] = {1.f / 57.375f, 1.f / 57.12f, 1.f / 58.395f}; | ||||
|   | ||||
| @@ -46,7 +46,7 @@ static void generate_yolox_proposals(std::vector<ov::GridAndStride> grid_strides | ||||
|                 obj.rect.width = w; | ||||
|                 obj.rect.height = h; | ||||
|                 obj.label = class_idx; | ||||
|                 obj.prob = box_prob; | ||||
|                 obj.score= box_prob; | ||||
|  | ||||
|                 objects.push_back(obj); | ||||
|             } | ||||
| @@ -57,28 +57,9 @@ static void generate_yolox_proposals(std::vector<ov::GridAndStride> grid_strides | ||||
|     } // point anchor loop | ||||
| } | ||||
|  | ||||
| Yolox::Yolox() :  | ||||
|     net_ (new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| Yolox::~Yolox() { | ||||
|     net_->clear(); | ||||
| } | ||||
|  | ||||
| int Yolox::LoadModel(const char * root_path) { | ||||
|     register_yolov5focus(net_); | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (net_->load_param(param_file.c_str()) == -1 || | ||||
| 		net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	initialized_ = true; | ||||
| 	return 0; | ||||
|     return Estimator::LoadModel(root_path); | ||||
| } | ||||
|  | ||||
| int Yolox::Detect(const unsigned char* rgbdata, | ||||
| @@ -116,7 +97,6 @@ int Yolox::Detect(const unsigned char* rgbdata, | ||||
|     in_pad.substract_mean_normalize(mean_vals, norm_vals); | ||||
|  | ||||
|     ncnn::Extractor ex = net_->create_extractor(); | ||||
|     ex.set_num_threads(4); | ||||
|     ex.input("input", in_pad); | ||||
|     ncnn::Mat out; | ||||
|     ex.extract("output", out); | ||||
|   | ||||
| @@ -9,17 +9,12 @@ namespace ovhand { | ||||
|  | ||||
| class Yolox : public Detecter { | ||||
| public: | ||||
|     Yolox(); | ||||
|     ~Yolox(); | ||||
|  | ||||
|     int LoadModel(const char* root_path); | ||||
|     int LoadModel(const char * root_path); | ||||
|     int Detect(const unsigned char* rgbadata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<ov::ObjectInfo>& rois); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* net_; | ||||
|     bool initialized_; | ||||
|     const int target_size = 416; | ||||
|     const float mean_vals[3] = {255.f * 0.485f, 255.f * 0.456, 255.f * 0.406f}; | ||||
|     const float norm_vals[3] = {1 / (255.f * 0.229f), 1 / (255.f * 0.224f), 1 / (255.f * 0.225f)}; | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| namespace ovhand { | ||||
| class PoseEstimator: public ov::Estimator { | ||||
| public: | ||||
|     virtual ~PoseEstimator() {}; | ||||
|     virtual int Detect(const unsigned char*rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         const ov::Rect& rect, | ||||
|   | ||||
| @@ -6,28 +6,6 @@ | ||||
| #endif // OV_VULKAN | ||||
|  | ||||
| namespace ovhand { | ||||
| HandPose::HandPose() :  | ||||
|     net_ (new ncnn::Net()), | ||||
| 	initialized_(false) { | ||||
| #ifdef OV_VULKAN | ||||
|     net_->opt.use_vulkan_compute = true; | ||||
| #endif // OV_VULKAN | ||||
| } | ||||
|  | ||||
| HandPose::~HandPose() { | ||||
|     net_->clear(); | ||||
| } | ||||
|  | ||||
| int HandPose::LoadModel(const char * root_path) { | ||||
| 	std::string param_file = std::string(root_path) + "/param"; | ||||
| 	std::string bin_file = std::string(root_path) + "/bin"; | ||||
| 	if (net_->load_param(param_file.c_str()) == -1 || | ||||
| 		net_->load_model(bin_file.c_str()) == -1) { | ||||
| 		return 10000; | ||||
| 	} | ||||
| 	initialized_ = true; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int HandPose::Detect(const unsigned char* rgbdata, | ||||
|     int img_width, int img_height, | ||||
|   | ||||
| @@ -9,18 +9,12 @@ namespace ovhand { | ||||
|  | ||||
| class HandPose : public PoseEstimator { | ||||
| public: | ||||
|     HandPose(); | ||||
|     ~HandPose(); | ||||
|  | ||||
|     int LoadModel(const char* root_path); | ||||
|     int Detect(const unsigned char* rgbdata, | ||||
|         int img_width, int img_height, | ||||
|         const ov::Rect& rect, | ||||
|         std::vector<ov::Point2f>& keypoints); | ||||
|  | ||||
| private: | ||||
| 	ncnn::Net* net_; | ||||
|     bool initialized_; | ||||
|     const float meanVals[3] = { 128.0f, 128.0f,  128.0f }; | ||||
|     const float normVals[3] = { 0.00390625f, 0.00390625f, 0.00390625f }; | ||||
| }; | ||||
|   | ||||
| @@ -18,7 +18,7 @@ int extract_pose_rois(IPoseDetecter d, const unsigned char* rgbdata, int img_wid | ||||
|         ov::ObjectInfo o = detected[i]; | ||||
|         rois->items[i] = ObjectInfo{ | ||||
|             o.rect, | ||||
|             o.prob, | ||||
|             o.score, | ||||
|             o.label, | ||||
|             NULL | ||||
|         }; | ||||
|   | ||||
| @@ -7,7 +7,6 @@ namespace ovpose { | ||||
|  | ||||
| class Detecter: public ov::Estimator { | ||||
| public: | ||||
|     virtual ~Detecter(){}; | ||||
|     virtual int ExtractROIs(const unsigned char* rgbadata, | ||||
|         int img_width, int img_height, | ||||
|         std::vector<ov::ObjectInfo>* rois) = 0; | ||||
|   | ||||
| @@ -55,7 +55,6 @@ int Ultralight::ExtractROIs(const unsigned char* rgbdata, | ||||
|     in.substract_mean_normalize(mean_vals, norm_vals); | ||||
|  | ||||
|     ncnn::Extractor ex = roi_net_->create_extractor(); | ||||
|     ex.set_num_threads(4); | ||||
|     ex.input("data", in); | ||||
|     ncnn::Mat out; | ||||
|     ex.extract("output", out); | ||||
| @@ -99,7 +98,7 @@ int Ultralight::ExtractROIs(const unsigned char* rgbdata, | ||||
|         ov::Rect rect = ov::Rect(x1, y1, x2-x1, y2-y1); | ||||
|         ov::ObjectInfo roi; | ||||
|         roi.rect = rect; | ||||
|         roi.prob = score; | ||||
|         roi.score = score; | ||||
|         rois->push_back(roi); | ||||
|     } | ||||
|     return 0; | ||||
| @@ -124,7 +123,6 @@ int Ultralight::ExtractKeypoints(const unsigned char* rgbdata, | ||||
|     in.substract_mean_normalize(meanVals, normVals); | ||||
|  | ||||
|     ncnn::Extractor ex = pose_net_->create_extractor(); | ||||
|     ex.set_num_threads(4); | ||||
|     ex.input("data", in); | ||||
|     ncnn::Mat out; | ||||
|     ex.extract("hybridsequential0_conv7_fwd", out); | ||||
| @@ -152,7 +150,7 @@ int Ultralight::ExtractKeypoints(const unsigned char* rgbdata, | ||||
|  | ||||
|         ov::Keypoint keypoint; | ||||
|         keypoint.p = ov::Point2f(max_x * w / (float)out.w+rect.x, max_y * h / (float)out.h+rect.y); | ||||
|         keypoint.prob = max_prob; | ||||
|         keypoint.score = max_prob; | ||||
|         keypoints->push_back(keypoint); | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Syd Xu
					Syd Xu