From a3e29fd900f721007c60284ec76092a6154d4e19 Mon Sep 17 00:00:00 2001
From: houxiao <houxiao@454eff88-639b-444f-9e54-f578c98de674>
Date: 星期五, 21 四月 2017 11:03:51 +0800
Subject: [PATCH] add

---
 FaceServer/PB_0_1 (51x51).yuv     |    2 
 FaceServer/STFaceCache.cpp        |   68 ++++++
 FaceServer/make.sh                |   18 +
 FaceServer/test_client.cpp        |    2 
 FaceServer/PB_0_0 (41x41).yuv     |    0 
 /dev/null                         |    0 
 FaceServer/main_face_daemon.cpp   |   53 +++--
 FaceServer/face_daemon_proto.h    |    6 
 FaceServer/sample_face_search.h   |   37 +++
 FaceServer/sample_face_search.cpp |  376 +++++++++++++++++++++++++++++++++++++
 FaceServer/ev_server.h            |    2 
 FaceServer/facelist-1001-0-5.pb   |    0 
 FaceServer/STFaceCache.h          |   33 +++
 FaceServer/pseudo_stfacesdk.cpp   |    0 
 14 files changed, 571 insertions(+), 26 deletions(-)

diff --git "a/FaceServer/PB_0_0 \05041x41\051.yuv" "b/FaceServer/PB_0_0 \05041x41\051.yuv"
new file mode 100644
index 0000000..e6b2e8f
--- /dev/null
+++ "b/FaceServer/PB_0_0 \05041x41\051.yuv"
Binary files differ
diff --git "a/FaceServer/PB_0_1 \05051x51\051.yuv" "b/FaceServer/PB_0_1 \05051x51\051.yuv"
new file mode 100644
index 0000000..f9dce05
--- /dev/null
+++ "b/FaceServer/PB_0_1 \05051x51\051.yuv"
@@ -0,0 +1,2 @@
+Xr}��亗倎剝fUk唵儐噥厞媽噯墋pd[ZZUNIC=74.+)"Wnw~~~亖�亖i[r墖厗剗�剚倇wxzoc\^[VQHB;41.+,'Vksz~}~���n_mz}�剙{|~{~vputdUSUPNOHA92/.++,"Ugqw|~~~~u_TOUdr|{zywxrok[F:>@<=@B;40/.++*$T_nv{~~}}}}}~~uW8/$/Hetzxtri`K0!!)...0740/.-+++& T]irw~|||}}{{~yY<2":\quohYH7%#)*,-.../.-**)% 
S\elszzzz}}y{亜dMJJ<&)EaonbQ@5,%%,320.,,-.-,*''% SYahovyyw}~唥h`ekyy[>;Umk_K>513>II>6.*++,-+*''%RT]dkrzyw~倖rB'Do儛梽aNXklYD71;OkvbK;/(**++*)*)#QRY^elsuw~~\+
+"?Rlsvj`dok]H>AUr唫gSB6()'())('$PQTX`goswxQ!,CH@239Mdx^A11?RVHB:3-,)%$)&"QPQU\bkpvrB7^Q205/!-V`5&2,! ##RONMTYbjurN#*?S\S.)C:-?HE("1*$&USJHNP[dotY<RqniaK2";@&")'3>C7!91#$('&"\ZXWXYabiqm[YmjcppeaaiV1(/&(GO:)%59%&$.4761&cccceeheelh[Xhrlsw}we[P'4F2?aog[OB2)*0?BA>.*' edbcddccbcfYXfsmgk\GAJP:Y~Q4W]]c[K;53+,?GB<8/*(#a__aaaaa``a\V`jgivo\]h`Ns抇$6XZOLFA;9:17CG@:6/*)%_]]_____^^_[S_tpovsilpbSz媋-=Z]RKB===B<=DFA:4-)(%!db`_```___`ZOSajuypotjQV儑c7#?Yb[RHAEOPA=EF>62-('&#mllkjhgggggg_QD?FKYfhP:f巶];'6Nac`]Y\eS=>FB731+('%#poppoooooppooswgUJIKH=O~搝ZF2*0CRXVWPD<:DG<31.)''%#onnooopppqqrowvmghklb^c垞uWMH824<@EDFLRPE<62/,)((%%onnpppppqrrrspxk[XVWQPe姁qOHJGAIQRZ`\WOB;531-*)))%&onnpppqqqrrqpsytnmhd^[i寙_IA=:AMOLJGEB?:6420,*))(&&onnpppqqqrrrrs||~zqdZj垁XA9/-8L\a]WSLE<741.+))((&&ooopppqqqrrssty|亐xk[Vr墊WB>512E_mmi`TH@93.-+*))(&&pooppqqqrrrsssw{|raV]y卹VJKF8.=[lppfXH@93.-+*))(&&pooppqqqrrrrrruz}xo]UbzyaNJQK7+4RjrpeWH@92.-+*))('&ppppqqqqrrrsssuz}{o_SWZSE99?A:+1Nhnk`TG?82.-+*))(&&ppppqqqqrrrssstx|zk[U\S=3.(/(+Hckg^RF>82..,*))(&&ppppqqqqqssssttvxtbUXovQ5*#&&$#+Ibhd[PF>82/.,+)(''(ppopqqqqrssstttwupaW^z刵J3.+&##5NaeaWMD>81//-+*)'&'ssrqqqrrrsssttuwtm^Xg儔~hJ6.++,:Pad`UKB<620/-+))'%%stuuutrrrssstuvwun][n剢僿bJ:69:BR`b^TJA;621/-+))'%$bbgkppqqrssstvvwun_`r亖}uj\MCBBGS]a[TJA;631/-+))'%#PRSTUVVY\^cehkjmqlgkv~z{rheXFCGLV[^XQJA;631/-+))'&$PPONMMKKLLMMNOOUbkkpw{|�zttgQJJLSVXSOJA;732/-+))&$"UTTSSSRRPONMKKJKWgqrsy~{swpdYPHHLORQMKD<521/-+*(&$"]\ZYXYXXUUWVSQQQWdqrnobNEDC@GGGEEHMNMLG=421/-+)(%#"kjhgecb`^\ZYYYXYZcoshZ=,++#'028@GGIKLF:310/-+)($!"llkkkkllkkkjhggdcdlp_C$%$")2<BDFHA7200/-+*'$"!lllllllllmlnnnnmlkkj\F5(;ABBA;41///,+*&# lllllllllllkjjjlmjje[Wd`RL4&$1BC@><720/1.,**&" llkkkkkkllkmmmllnmqe_baaoyiR7/5?BB?<9620//,+*($ lllllllllllllllnqrbWY`]SSX\R>027<AB?;631//.,**&!llllllmllmmnmlmqlbF?Ra`O><?9,)04:?A=840.--,+*($ llllllnkkmmpqsolU=34K`aO7/,+-125:>?:62.,,+*)(%!llllllmllknqvp[F3/14D\jZD/-0797::><630,,,*)'&"lllllmmmnnoohS<01221<Vki]K=799>B@>931-+**)&#!llllmmnnrr^L;--/432/5NjutjXPJHGFE?;50,)(%#"!!
\ No newline at end of file
diff --git a/FaceServer/STFaceCache.cpp b/FaceServer/STFaceCache.cpp
new file mode 100644
index 0000000..f57dc58
--- /dev/null
+++ b/FaceServer/STFaceCache.cpp
@@ -0,0 +1,68 @@
+#include "STFaceCache.h"
+#include <MaterialBuffer.h>
+#include <logger.h>
+#include <map>
+
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "sample_face_search.h"
+
+struct STFaceContext
+{
+	int dbid;
+	std::string dbfn;
+	stface_handles handles;
+};
+
+typedef std::map<int, STFaceContext> stface_ctx_map_t; // <dbid, ctx>
+
+STFaceCache::STFaceCache(const std::string& _stfacedbPath)
+	: stfacedbPath(_stfacedbPath), stfaceModels(STFACESDK_BASE "/models"), _cacheContext(new stface_ctx_map_t)
+{
+	LOG_INFO << "st face db: " << stfacedbPath << LOG_ENDL;
+	LOG_INFO << "st face sdk models: " << stfaceModels << LOG_ENDL;
+}
+
+STFaceCache::~STFaceCache()
+{
+	delete (stface_ctx_map_t*)_cacheContext;
+	_cacheContext = nullptr;
+}
+
+bool STFaceCache::load_dbs()
+{
+	stface_ctx_map_t& cacheContext(*(stface_ctx_map_t*)_cacheContext);
+	
+	DIR* dp = opendir(stfacedbPath.c_str());
+	if (dp != NULL)
+	{
+		struct dirent* ep;
+		while(ep = readdir(dp))
+		{
+			//puts(ep->d_name);
+			
+			STFaceContext ctx;
+			ctx.dbfn = ep->d_name;
+			ctx.dbid = strtol(ctx.dbfn.c_str(), nullptr, 10);
+		}
+		closedir(dp);
+	}
+	else
+	{
+		LOG_ERROR << "Couldn't open the directory." << LOG_ENDL;
+		return false;
+	}
+}
+
+FDP_FaceDetectResult STFaceCache::detect(const STFaceImage& img)
+{
+	stface_ctx_map_t& cacheContext(*(stface_ctx_map_t*)_cacheContext);
+	return FDP_FaceDetectResult(0, 0);
+}
+
+FDP_FaceDetectResult STFaceCache::save(const STFaceImage& img)
+{
+	stface_ctx_map_t& cacheContext(*(stface_ctx_map_t*)_cacheContext);
+	return FDP_FaceDetectResult(0, 0);
+}
diff --git a/FaceServer/STFaceCache.h b/FaceServer/STFaceCache.h
new file mode 100644
index 0000000..2c37ca0
--- /dev/null
+++ b/FaceServer/STFaceCache.h
@@ -0,0 +1,33 @@
+#ifndef _ST_FACE_CACHE_H_
+#define _ST_FACE_CACHE_H_
+
+#include <string>
+#include "face_daemon_proto.h"
+
+struct STFaceImage
+{
+	int32_t db_id;
+	int16_t mb_type; // MB_Frame::MBFType
+	int16_t width;
+	int16_t height;
+	uint32_t size;
+	const uint8_t* buff;
+};
+
+class STFaceCache
+{
+public:
+	STFaceCache(const std::string& _stfacedbPath);
+	~STFaceCache();
+	
+	bool load_dbs();
+	FDP_FaceDetectResult detect(const STFaceImage& img);
+	FDP_FaceDetectResult save(const STFaceImage& img);
+	
+private:
+	const std::string stfacedbPath;
+	const std::string stfaceModels;
+	void* _cacheContext;
+};
+
+#endif
diff --git a/FaceServer/ev_server.h b/FaceServer/ev_server.h
index 6a47cda..bb720b7 100644
--- a/FaceServer/ev_server.h
+++ b/FaceServer/ev_server.h
@@ -5,7 +5,9 @@
 #include <stdint.h>
 #include "ev_proto.h"
 
+#ifndef SERVER_PORT
 #define SERVER_PORT 5432
+#endif
 #define REUSEADDR_ON 1
 #define CLIENT_BUFFER_MAX 100*1024 // 100KB
 #define CLIENT_READ_TIMES_MAX 100
diff --git a/FaceServer/face_daemon_proto.h b/FaceServer/face_daemon_proto.h
index ccda811..63d5741 100644
--- a/FaceServer/face_daemon_proto.h
+++ b/FaceServer/face_daemon_proto.h
@@ -25,7 +25,7 @@
 
 struct FDP_Image
 {
-	int32_t school_id;
+	int32_t db_id;
 	int16_t mb_type; // MB_Frame::MBFType
 	int16_t width;
 	int16_t height;
@@ -38,6 +38,8 @@
 	
 	FDP_FaceDetectPB(int32_t _db_id) : db_id(_db_id)
 	{}
+	
+	void hton();
 };
 
 struct FDP_FaceDetectResult
@@ -47,6 +49,8 @@
 	
 	FDP_FaceDetectResult(int32_t _db_id, int32_t _st_id) : db_id(_db_id), st_id(_st_id)
 	{}
+	
+	void hton();
 };
 
 #pragma pack()
diff --git a/FaceServer/facelist-1001-0-2.pb b/FaceServer/facelist-1001-0-2.pb
deleted file mode 100644
index 83e8e4d..0000000
--- a/FaceServer/facelist-1001-0-2.pb
+++ /dev/null
Binary files differ
diff --git a/FaceServer/facelist-1001-0-4.pb b/FaceServer/facelist-1001-0-4.pb
deleted file mode 100644
index 3200270..0000000
--- a/FaceServer/facelist-1001-0-4.pb
+++ /dev/null
Binary files differ
diff --git a/FaceServer/facelist-1001-0-5.pb b/FaceServer/facelist-1001-0-5.pb
new file mode 100644
index 0000000..cc64865
--- /dev/null
+++ b/FaceServer/facelist-1001-0-5.pb
Binary files differ
diff --git a/FaceServer/facelist-3.pb b/FaceServer/facelist-3.pb
deleted file mode 100644
index 86e15d0..0000000
--- a/FaceServer/facelist-3.pb
+++ /dev/null
Binary files differ
diff --git a/FaceServer/main_face_daemon.cpp b/FaceServer/main_face_daemon.cpp
index 09f30e3..21da9f3 100644
--- a/FaceServer/main_face_daemon.cpp
+++ b/FaceServer/main_face_daemon.cpp
@@ -4,7 +4,7 @@
 #include "ev_server.h" 
 #include "ev_proto.h"
 #include "face_daemon_proto.h"
-
+#include "STFaceCache.h"
 #include <PbFaceList.pb.h>
 
 #include <signal.h>
@@ -12,7 +12,10 @@
 #include <sstream>
 #include <iostream>
 
+#define WRAPPER_TEXT(x) "\"" << x << "\""
+
 Logger g_logger(std::cout);
+STFaceCache g_STFaceCache("/opt/FaceServer/stfacedb");
 
 evclient_proc_t evclient_proc;
 
@@ -25,12 +28,12 @@
 {
 	std::stringstream ss;
 	ss << "{" << std::endl;
-	ss << "\"ret\":" << 0 << "," << std::endl;
-	ss << "\"count\":" << result.size() << "," << std::endl;
+	ss << "\"ret\":" << WRAPPER_TEXT(0) << "," << std::endl;
+	ss << "\"count\":" << WRAPPER_TEXT(result.size()) << "," << std::endl;
 	ss << "\"result\":[";
 	for(fdr_vec_t::const_iterator iter = result.begin(); iter != result.end(); ++iter)
 	{
-		ss << "[" << iter->db_id << "," << iter->st_id << "]";
+		ss << "[" << WRAPPER_TEXT(iter->db_id) << "," << WRAPPER_TEXT(iter->st_id) << "]";
 		if (iter != std::prev(result.end()))
 			ss << ",";
 	}
@@ -63,28 +66,38 @@
 	LOGP(DEBUG, "pbFaceList: magic=%u, image_count=%u, src_width=%u, src_height=%u", 
 		pbFaceList.magic(), pbFaceList.image_count(), pbFaceList.src_width(), pbFaceList.src_height());
 
+	fdr_vec_t result;
+	
 	for(int i = 0; i < pbFaceList.image_count(); i++)
 	{
 		const PbFaceList_FaceListImage& pbFaceListImage = pbFaceList.images(i);
 		LOGP(DEBUG, "\tpbFaceList %d: idx=%u, size=%u, type=%u, width=%u, height=%u, top_left_x=%u, top_left_y=%u", 
 			i, pbFaceListImage.idx(), pbFaceListImage.size(), pbFaceListImage.type(), pbFaceListImage.width(), pbFaceListImage.height(), pbFaceListImage.top_left_x(), pbFaceListImage.top_left_y());
-			
-		char imgfn[100 * 1024];
-		sprintf(imgfn, "PB_%d_%d.yuv", 0, i);
-
-		FILE * pFile = fopen(imgfn, "wb");
-		fwrite(*(pbFaceListImage.img().data()), sizeof(char), pbFaceListImage.size(), pFile);
-		fclose(pFile);
-		pFile = nullptr;
+		
+		//#test
+		//char imgfn[100 * 1024];
+		//sprintf(imgfn, "PB_%d_%d.yuv", 0, i);
+        //
+		//FILE * pFile = fopen(imgfn, "wb");
+		const std::string* img(*pbFaceListImage.img().data());
+		//fwrite(img->data(), sizeof(char), img->size(), pFile);
+		//fclose(pFile);
+		//pFile = nullptr;
+		
+		STFaceImage stimg;
+		stimg.db_id = fdpFaceDetectPB->db_id;
+		stimg.mb_type = pbFaceListImage.type();
+		stimg.width = pbFaceListImage.width();
+		stimg.height = pbFaceListImage.height();
+		stimg.size = img->size();
+		stimg.buff = (const uint8_t*)img->data();
+		result.push_back(g_STFaceCache.detect(stimg));
 	}
-		
-		
-	fdr_vec_t result;
-	
-	//do detect(client)
-	result.push_back(FDP_FaceDetectResult(-1,123));
-	result.push_back(FDP_FaceDetectResult(2,456));
-	result.push_back(FDP_FaceDetectResult(0,0));
+
+	//#test
+	//result.push_back(FDP_FaceDetectResult(-1,123));
+	//result.push_back(FDP_FaceDetectResult(2,456));
+	//result.push_back(FDP_FaceDetectResult(0,0));
 	
 	return send_SensetimeFaceDetectResultJson(client, result);
 }
diff --git a/FaceServer/make.sh b/FaceServer/make.sh
index e15e9e6..dd03a91 100644
--- a/FaceServer/make.sh
+++ b/FaceServer/make.sh
@@ -8,8 +8,14 @@
 PROTOBUF_INC="-I$PROTOBUF_BASE/include"
 PROTOBUF_LIB="-L$PROTOBUF_BASE/lib -lprotobuf"
 
-CPPFLAGS+="-g -c -std=c++11 -pthread -I$PIPELINE_BASE -I$VISITFACE_BASE $PROTOBUF_INC "
-LDFLAGS+="-pthread -levent $PROTOBUF_LIB "
+STFACESDK_BASE=/opt/st_face-6.3.1-verify_p1-linux-524d0c3
+STFACESDK_INC="-I$STFACESDK_BASE/include"
+STFACESDK_LIB="-L$STFACESDK_BASE/libs/linux-x86_64"
+
+OPENCV_LIB=`pkg-config --libs-only-l opencv`
+
+CPPFLAGS+="-g -c -std=c++11 -pthread -DSERVER_PORT=5432 -DSTFACESDK_BASE=\"$STFACESDK_BASE\" -I$PIPELINE_BASE -I$VISITFACE_BASE $PROTOBUF_INC $STFACESDK_INC "
+LDFLAGS+="-pthread -levent $PROTOBUF_LIB $STFACESDK_LIB $OPENCV_LIB " # -lcvface_api 
 
 rm *.o
 rm face_server
@@ -17,8 +23,10 @@
 
 g++ $PIPELINE_BASE/Logger/src/logger.cc $CFLAGS $CPPFLAGS
 g++ ev_server.cpp -DUSER_DEFINE_EVCLIENT_PROC $CFLAGS $CPPFLAGS
-g++ main_face_daemon.cpp $CFLAGS $CPPFLAGS
 g++ $VISITFACE_BASE/PbFaceList.pb.cc $CFLAGS $CPPFLAGS
+g++ main_face_daemon.cpp $CFLAGS $CPPFLAGS
+g++ sample_face_search.cpp $CFLAGS $CPPFLAGS
+g++ STFaceCache.cpp $CFLAGS $CPPFLAGS
 
 g++ test_client.cpp $CFLAGS $CPPFLAGS
 
@@ -27,6 +35,8 @@
   ev_server.o \
   PbFaceList.pb.o \
   main_face_daemon.o \
+  sample_face_search.o \
+  STFaceCache.o \
   $LDFLAGS -o face_server
 #
 
@@ -35,4 +45,4 @@
   $LDFLAGS -o test_client
 #
 
-#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/protobuf/inst/lib
+#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/protobuf/inst/lib:/opt/st_face-6.3.1-verify_p1-linux-524d0c3/libs/linux-x86_64
diff --git a/FaceServer/pseudo_stfacesdk.cpp b/FaceServer/pseudo_stfacesdk.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaceServer/pseudo_stfacesdk.cpp
diff --git a/FaceServer/sample_face_search.cpp b/FaceServer/sample_face_search.cpp
new file mode 100644
index 0000000..bc11aef
--- /dev/null
+++ b/FaceServer/sample_face_search.cpp
@@ -0,0 +1,376 @@
+#include "sample_face_search.h"
+#include <logger.h>
+
+#include <vector>
+#include <stdio.h>
+#include <cv_face.h>
+
+#include <opencv2/opencv.hpp>
+
+using namespace std;
+using namespace cv;
+
+//static cv_handle_t handle_verify = nullptr;
+//static cv_handle_t handle_db = nullptr;
+//static cv_handle_t handle_detect = nullptr;
+
+#define _MAX_PATH 260
+
+cv_feature_t *stface_extract_feature(stface_handles& handles, const char *image_path) {
+	Mat bgr_image = imread(image_path);  // CV_PIX_FMT_BGR888
+	if (!bgr_image.data) {
+		return nullptr;
+	}
+	
+	cv_feature_t *p_feature = nullptr;
+	cv_face_t *p_face = nullptr;
+	int face_count = 0;
+	cv_result_t st_result = CV_OK;
+	st_result = cv_face_detect(handles.handle_detect, bgr_image.data, CV_PIX_FMT_BGR888,
+				bgr_image.cols, bgr_image.rows, bgr_image.step,
+				CV_FACE_UP, &p_face, &face_count);
+	if (face_count >= 1) {
+		st_result = cv_verify_get_feature(handles.handle_verify,
+						(unsigned char *)bgr_image.data, CV_PIX_FMT_BGR888,
+						bgr_image.cols, bgr_image.rows, bgr_image.step,
+						p_face, &p_feature, nullptr);
+		if (st_result != CV_OK) {
+			LOGP(INFO, "cv_verify_get_feature failed, error code %d\n", st_result);
+		}
+	} else {
+		LOGP(INFO, "can't find face in %s", image_path);
+	}
+	// release the memory of face
+	cv_face_release_detector_result(p_face, face_count);
+	return p_feature;
+}
+
+int stface_db_add(stface_handles& handles, const char *image_path) {
+	cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
+	if (!p_feature) {
+		return -1;
+	}
+	int idx;
+	cv_result_t cv_result = cv_verify_add_face(handles.handle_db, p_feature, &idx);
+	if (cv_result != CV_OK) {
+		LOGP(INFO, "cv_verify_add_face failed, error code %d\n", cv_result);
+	}
+	cv_verify_release_feature(p_feature);
+	return idx;
+}
+
+bool stface_db_del(stface_handles& handles, int idx) {
+	if (idx < 0) {
+		LOGP(INFO, "invalid idx!\n");
+		return false;
+	}
+	cv_result_t cv_result = CV_OK;
+	cv_result = cv_verify_delete_face(handles.handle_db, idx);
+	if (cv_result != CV_OK) {
+		LOGP(INFO, "cv_verify_delete_face failed, error code %d\n", cv_result);
+	}
+	else {
+		LOGP(INFO, "delete succeed\n");
+	}
+}
+
+bool stface_db_save(stface_handles& handles, char *db_path) {
+	cv_result_t cv_result = CV_OK;
+	cv_result = cv_verify_save_db(handles.handle_db, db_path);
+	if (cv_result != CV_OK) {
+		LOGP(INFO, "cv_verify_save_db failed, error code %d\n", cv_result);
+		return false;
+	}
+	else {
+		LOGP(INFO, "save done!\n");
+	}
+
+	return true;
+}
+
+bool stface_db_load(stface_handles& handles, char *db_path) {
+	cv_result_t cv_result = CV_OK;
+	cv_result = cv_verify_load_db(handles.handle_db, db_path);
+	if (cv_result != CV_OK) {
+		LOGP(INFO, "cv_verify_load_db failed, error code %d\n", cv_result);
+		return false;
+	}
+	else {
+		LOGP(INFO, "load done!\n");
+	}
+
+	return true;
+}
+
+bool stface_db_gen(stface_handles& handles, char *image_list, char *output_db_path) {
+	bool bresult = true;
+	FILE *fp_path = fopen(image_list, "r");
+	if(!fp_path) {
+		LOGP(INFO, "failed to load %s\n", image_list);
+		return false;
+	}
+	std::vector<cv_feature_t *> list_feature;
+	list_feature.clear();
+	for (;;) {
+		char image_path[1024];
+		int num = fscanf(fp_path, "%s", image_path);
+		if (num != 1) {
+			bresult = false;
+			break;
+		}
+		LOGP(INFO, "extracting %s\n", image_path);
+
+		// get the face feature
+		cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
+		if (!p_feature) {
+			LOGP(INFO, "failed to extract image: %s\n", image_path);
+			continue;
+		}
+		list_feature.push_back(p_feature);
+	}
+	fclose(fp_path);
+	cv_verify_destroy_db(handles.handle_db);
+	cv_result_t cv_result = CV_OK;
+	cv_verify_create_db(&handles.handle_db);
+	cv_result = cv_verify_build_db(handles.handle_db, &list_feature[0], list_feature.size());
+	if (cv_result != CV_OK) {
+		LOGP(INFO, "cv_verify_build_db failed, error code %d\n", cv_result);
+		bresult = false;
+	}
+	cv_verify_save_db(handles.handle_db, output_db_path);
+	for (int i = 0; i < list_feature.size(); i++) {
+		cv_verify_release_feature(list_feature[i]);
+	}
+	cout << "db gen done!" << endl;
+
+	return bresult;
+}
+
+bool stface_search_db(stface_handles& handles, char *image_path) {
+	FILE *fp_path = fopen(image_path, "r");
+	if (fp_path == nullptr) {
+		LOGP(INFO, "invalid path !\n");
+		return false;
+	}
+	fclose(fp_path);
+
+	cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
+	if (p_feature == nullptr) {
+		LOGP(INFO, "extract failed !\n");
+		return false;
+	}
+
+	int top_k = 10;
+	int *top_idxs = new int[top_k];
+	float *top_scores = new float[top_k];
+	unsigned int result_length = 0;
+	cv_result_t cv_result = cv_verify_search_face(handles.handle_verify, handles.handle_db,
+		p_feature, top_k,
+		top_idxs, top_scores, &result_length);
+	if (cv_result == CV_OK) {
+		for (unsigned int t = 0; t < result_length; t++) {
+			// const cv_feature_t item = result[t].item;
+			LOGP(INFO, "%d\t", top_idxs[t]);
+			LOGP(INFO, "%0.2f\n", top_scores[t]);
+		}
+	}
+	else {
+		LOGP(INFO, "cv_verify_search_face failed, error code %d\n", cv_result);
+	}
+	if (top_idxs) {
+		delete[]top_idxs;
+	}
+	if (top_scores) {
+		delete[]top_scores;
+	}
+	cv_verify_release_feature(p_feature);
+
+	return true;
+}
+
+bool stface_search_list(stface_handles& handles, char *image_path, char *list_path) {
+	cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
+	if (p_feature == nullptr) {
+		LOGP(INFO, "failed to extract image: %s\n", image_path);
+		return false;
+	}
+
+	FILE *fp_path = fopen(list_path, "r");
+	if(!fp_path) {
+		LOGP(INFO, "failed to load %s\n", list_path);
+		return false;
+	}
+	std::vector<cv_feature_t *> list_feature;
+	list_feature.clear();
+	for (;;) {
+		char image_path[_MAX_PATH];
+		int num = fscanf(fp_path, "%s", image_path);
+		if (num != 1) {
+			break;
+		}
+		LOGP(INFO, "extracting %s\n", image_path);
+
+		// get the face feature
+		cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
+		if (!p_feature) {
+			LOGP(INFO, "failed to extract image: %s\n", image_path);
+			continue;
+		}
+		list_feature.push_back(p_feature);
+	}
+	fclose(fp_path);
+
+
+	const int top_k = 10;
+	int top_idxs[top_k];
+	float top_scores[top_k];
+	unsigned int result_length = 0;
+	cv_result_t cv_result = cv_verify_search_face_from_list(handles.handle_verify,
+				&list_feature[0], list_feature.size(),
+				p_feature, top_k,
+				top_idxs, top_scores, &result_length);
+
+	if (cv_result == CV_OK) {
+		for (unsigned int t = 0; t < result_length; t++) {
+			LOGP(INFO, "%d\t", top_idxs[t]);
+			LOGP(INFO, "%0.2f\n", top_scores[t]);
+		}
+	} else {
+		LOGP(INFO, "search face failed");
+	}
+	cv_verify_release_feature(p_feature);
+
+	for (int i = 0; i < list_feature.size(); i++) {
+		cv_verify_release_feature(list_feature[i]);
+	}
+	LOGP(INFO, "list search done!\n");
+
+	return true;
+}
+
+void stface_get_help() {
+	LOGP(INFO, "Usage: help | Get cmd list\n");
+	LOGP(INFO, "Usage: search p_image_colorpath | Search image in db\n");
+	LOGP(INFO, "Usage: add p_image_colorpath | Add image in db, return idx in db, if idx < 0 means failed\n");
+	LOGP(INFO, "Usage: del idx | Delete image in db\n");
+	LOGP(INFO, "Usage: save db_file | Save current db in db_file\n");
+	LOGP(INFO, "Usage: load db_file | Load db in db_file\n");
+	LOGP(INFO, "Usage: gen p_image_colorlist db_file | Gen images in p_image_colorlist and save in db_file\n");
+	LOGP(INFO, "Usage: exit | Exit the program\n");
+}
+
+int stface_main(stface_handles& handles, int argc, char *argv[]) {
+	cv_result_t cv_result = cv_face_create_detector(&handles.handle_detect, nullptr, CV_DETECT_ENABLE_ALIGN_21);
+	if (cv_result != CV_OK){
+		LOGP(INFO, "create detect handle failed, error code %d\n", cv_result);
+	}
+	cv_result = cv_verify_create_handle(&handles.handle_verify, "../../../models/verify.model");
+	if (cv_result != CV_OK){
+		LOGP(INFO, "create verify handle failed, error code %d\n", cv_result);
+	}
+	cv_result = cv_verify_create_db(&handles.handle_db);
+	if (cv_result != CV_OK){
+		LOGP(INFO, "create db handle failed, error code %d\n", cv_result);
+	}
+	
+	if (handles.handle_detect != nullptr && handles.handle_verify != nullptr && handles.handle_db != nullptr) {
+		// stface_db_gen("list.txt","out.db");
+		LOGP(INFO, "Database is empty at the beginning\n");
+		LOGP(INFO, "Please input 'help' to get the cmd list\n");
+		char input_code[256];
+		char image_path[_MAX_PATH];
+		char db_path[_MAX_PATH];
+		char command[256];
+		input_code[0] = 0;
+		while (1) {
+			LOGP(INFO, ">>");
+			if (!fgets(input_code, 256, stdin)) {
+				LOGP(INFO, "read nothing\n");
+				continue;
+			}
+			int input_length = strlen(input_code);
+			if (input_length > 0 && input_code[input_length - 1] == '\n') {
+				input_code[--input_length] = 0;
+			}
+			if (input_length == 0) {
+				continue;
+			}
+			std::string str_input_code(input_code);
+			if (strcmp(str_input_code.c_str(), "help") == 0) {
+				stface_get_help();
+			}
+			else if (strcmp(str_input_code.substr(0, 3).c_str(), "add") == 0) {
+				int input_number = sscanf(input_code, "%s%s", command, image_path);
+				if (input_number != 2) {
+					LOGP(INFO, "invalid! Usage: add p_image_colorpath\n");
+					continue;
+				}
+				int idx = stface_db_add(handles, image_path);
+				cout << "idx = " << idx << endl;
+			}
+			else if (strcmp(str_input_code.substr(0, 3).c_str(), "del") == 0) {
+				int idx = -1;
+				int input_number = sscanf(input_code, "%s%d", image_path, &idx);
+				if (input_number != 2) {
+					LOGP(INFO, "invalid! Usage: del idx(unsigned int\n");
+					continue;
+				}
+				stface_db_del(handles, idx);
+			}
+			else if (strcmp(str_input_code.substr(0, 4).c_str(), "save") == 0) {
+				int input_number = sscanf(input_code, "%s%s", command, image_path);
+				if (input_number != 2) {
+					LOGP(INFO, "invalid! Usage: save db_file\n");
+					continue;
+				}
+				stface_db_save(handles, image_path);
+			}
+			else if (strcmp(str_input_code.substr(0, 4).c_str(), "load") == 0) {
+				int input_number = sscanf(input_code, "%s%s", command, image_path);
+				if (input_number != 2) {
+					LOGP(INFO, "invalid! Usage: load db_file\n");
+					continue;
+				}
+				stface_db_load(handles, image_path);
+			}
+			else if (strcmp(str_input_code.c_str(), "exit") == 0) {
+				break;
+			}
+			else if (strcmp(str_input_code.substr(0, 3).c_str(), "gen") == 0) {
+				int input_number = sscanf(input_code, "%s%s%s", command, image_path, db_path);
+				if (input_number != 3) {
+					LOGP(INFO, "invalid! Usage: gen p_image_colorlist_file db_file\n");
+					continue;
+				}
+				stface_db_gen(handles, image_path, db_path);
+			}
+			else if (strcmp(str_input_code.substr(0, 6).c_str(), "search") == 0) {
+				int input_number = sscanf(input_code, "%s%s", command, image_path);
+				if (input_number != 2) {
+					LOGP(INFO, "invalid! Usage: search p_image_colorpath\n");
+					continue;
+				}
+				stface_search_db(handles, image_path);
+			}
+			else if (strcmp(str_input_code.substr(0, 10).c_str(), "listsearch") == 0) {
+				char search_path[_MAX_PATH];
+				int input_number = sscanf(input_code, "%s%s%s", command, search_path,
+					image_path);
+				if (input_number != 3) {
+					LOGP(INFO, "invalid! Usage: listsearch p_image_colorsrcpath p_image_colorlistpath\n");
+					continue;
+				}
+				stface_search_list(handles, search_path, image_path);
+			}
+			else {
+				LOGP(INFO, "invalid cmd, please input 'help' to get the cmd list\n");
+			}
+		}
+	}
+
+	cv_face_destroy_detector(handles.handle_detect);
+	cv_verify_destroy_db(handles.handle_db);
+	cv_verify_destroy_handle(handles.handle_verify);
+	return 0;
+}
+
diff --git a/FaceServer/sample_face_search.h b/FaceServer/sample_face_search.h
new file mode 100644
index 0000000..fb37ee7
--- /dev/null
+++ b/FaceServer/sample_face_search.h
@@ -0,0 +1,37 @@
+#ifndef _SAMPLE_FACE_SEARCH_H_
+#define _SAMPLE_FACE_SEARCH_H_
+
+typedef void* cv_handle_t;
+struct cv_feature_t;
+
+struct stface_handles
+{
+	cv_handle_t handle_verify;
+	cv_handle_t handle_db;
+	cv_handle_t handle_detect;
+	
+	stface_handles() : handle_verify(nullptr), handle_db(nullptr), handle_detect(nullptr)
+	{}
+};
+
+cv_feature_t *stface_extract_feature(stface_handles& handles, const char *image_path);
+
+int stface_db_add(stface_handles& handles, const char *image_path);
+
+bool stface_db_del(stface_handles& handles, int idx);
+
+bool stface_db_save(stface_handles& handles, char *db_path);
+
+bool stface_db_load(stface_handles& handles, char *db_path);
+
+bool stface_db_gen(stface_handles& handles, char *image_list, char *output_db_path);
+
+bool stface_search_db(stface_handles& handles, char *image_path);
+
+bool stface_search_list(stface_handles& handles, char *image_path, char *list_path);
+
+void stface_get_help();
+
+int stface_main(int argc, char *argv[]);
+
+#endif
diff --git a/FaceServer/test_client.cpp b/FaceServer/test_client.cpp
index d8d1ce1..320845e 100644
--- a/FaceServer/test_client.cpp
+++ b/FaceServer/test_client.cpp
@@ -35,7 +35,7 @@
 
 void make_msg(char* mesg, int& length)
 {
-	FILE* pFile = fopen("facelist-1001-0-2.pb", "rb");
+	FILE* pFile = fopen("facelist-1001-0-5.pb", "rb");
 	length = fread(mesg, 1, length, pFile);
 	fclose(pFile);
 }

--
Gitblit v1.8.0