Commit d0cf0291 by xmh

加入人体特征

1 parent 877b932f
package com.viontech.match.config;
/**
* .
*
* @author 谢明辉
* @date 2020/12/2
*/
public class Constant {
/** 人脸特征维数 */
public final static int FACE_FEATURE_DIMS = 512;
/** 人体特征维数 */
public final static int BODY_FEATURE_DIMS = 2048;
/** poolId不存在时es返回的message所包含的字段 */
public final static String STR_POOL_ID_ALREADY_EXISTS = "already_exists";
/** 人脸匹配结果的数量 */
public final static int MATCH_RESULT_SIZE = 5;
}
package com.viontech.match.service; package com.viontech.match.service;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.viontech.keliu.model.BodyFeature;
import com.viontech.keliu.model.FaceFeature; import com.viontech.keliu.model.FaceFeature;
import com.viontech.keliu.model.Person; import com.viontech.keliu.model.Person;
import com.viontech.keliu.model.Pool; import com.viontech.keliu.model.Pool;
import com.viontech.match.config.Constant;
import com.viontech.match.entity.vo.RequestVo; import com.viontech.match.entity.vo.RequestVo;
import com.viontech.match.entity.vo.ResponseVo; import com.viontech.match.entity.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -116,10 +118,30 @@ public class PersonService { ...@@ -116,10 +118,30 @@ public class PersonService {
if (faceFeatures != null && faceFeatures.size() > 0) { if (faceFeatures != null && faceFeatures.size() > 0) {
for (FaceFeature faceFeature : faceFeatures) { for (FaceFeature faceFeature : faceFeatures) {
Double[] feature = faceFeature.getFeature(); Double[] feature = faceFeature.getFeature();
String fid = faceFeature.getFid(); if (feature != null && feature.length == Constant.FACE_FEATURE_DIMS) {
String fid = faceFeature.getFid();
IndexRequest indexRequest = new IndexRequest(poolId)
.source(XContentType.JSON, "personId", personId, "data", feature, "fid", fid, "age", age, "gender", gender);
bulkRequest.add(indexRequest);
}
}
}
List<BodyFeature> bodyFeatures = person.getBodyFeatures();
if (bodyFeatures != null && bodyFeatures.size() > 0) {
for (BodyFeature bodyFeature : bodyFeatures) {
Double[] feature = bodyFeature.getFeature();
if (feature == null || feature.length < Constant.BODY_FEATURE_DIMS) {
continue;
}
if (feature.length > Constant.BODY_FEATURE_DIMS) {
feature = Arrays.copyOf(feature, Constant.BODY_FEATURE_DIMS);
}
String fid = bodyFeature.getBid();
IndexRequest indexRequest = new IndexRequest(poolId) IndexRequest indexRequest = new IndexRequest(poolId)
.source(XContentType.JSON, "personId", personId, "data", feature, "fid", fid, "age", age, "gender", gender); .source(XContentType.JSON, "personId", personId, "body", feature, "fid", fid, "age", age, "gender", gender);
bulkRequest.add(indexRequest); bulkRequest.add(indexRequest);
} }
} }
...@@ -142,48 +164,85 @@ public class PersonService { ...@@ -142,48 +164,85 @@ public class PersonService {
public List<Person> matchPerson(String poolId, Person person) throws Exception { public List<Person> matchPerson(String poolId, Person person) throws Exception {
List<Person> matchResult = new ArrayList<>();
List<FaceFeature> faceFeatures = person.getFaceFeatures(); List<FaceFeature> faceFeatures = person.getFaceFeatures();
List<Person> persons = new ArrayList<>(); matchFace(faceFeatures, poolId, matchResult);
List<BodyFeature> bodyFeatures = person.getBodyFeatures();
matchBody(bodyFeatures, poolId, matchResult);
if (matchResult.size() > Constant.MATCH_RESULT_SIZE) {
matchResult = matchResult.stream().sorted(Comparator.comparingInt(Person::getScore)).limit(5).collect(Collectors.toList());
}
return matchResult;
}
private void matchFace(List<FaceFeature> faceFeatures, String poolId, List<Person> matchResult) throws IOException {
if (faceFeatures != null && faceFeatures.size() > 0) { if (faceFeatures != null && faceFeatures.size() > 0) {
for (FaceFeature faceFeature : faceFeatures) { for (FaceFeature faceFeature : faceFeatures) {
Double[] feature = faceFeature.getFeature(); Double[] feature = faceFeature.getFeature();
if (feature.length < 512) { if (feature == null || feature.length != Constant.FACE_FEATURE_DIMS) {
continue; continue;
} }
Script script = new Script( Script script = new Script(
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG,
"(cosineSimilarity(params.data, 'data') + 1) / 2 * 100", Collections.singletonMap("data", feature)); "(cosineSimilarity(params.face, 'data') + 1) / 2 * 100", Collections.singletonMap("face", feature));
ScriptScoreQueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), script);
matchResult.addAll(match0(poolId, script));
SearchSourceBuilder builder = new SearchSourceBuilder()
.size(5)
.query(queryBuilder)
.fetchSource(new String[]{"personId", "age", "gender", "fid"}, null);
SearchRequest searchRequest = new SearchRequest(poolId)
.source(builder);
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
SearchHit[] hits1 = hits.getHits();
for (SearchHit item : hits1) {
Map<String, Object> source = item.getSourceAsMap();
Person p = new Person();
p.setPersonId((String) source.get("personId"));
p.setAge((Integer) source.get("age"));
p.setGender((String) source.get("gender"));
p.setScore((int) item.getScore());
p.setPersonPoolId(item.getIndex());
persons.add(p);
}
} }
} else { } else {
log.info("no face feature"); log.info("no face feature");
} }
if (persons.size() > 5) { }
persons = persons.stream().sorted(Comparator.comparingInt(Person::getScore)).limit(5).collect(Collectors.toList());
private void matchBody(List<BodyFeature> bodyFeatures, String poolId, List<Person> matchResult) throws IOException {
if (bodyFeatures != null && bodyFeatures.size() > 0) {
for (BodyFeature faceFeature : bodyFeatures) {
Double[] feature = faceFeature.getFeature();
if (feature == null || feature.length < Constant.BODY_FEATURE_DIMS) {
continue;
}
if (feature.length > Constant.BODY_FEATURE_DIMS) {
feature = Arrays.copyOf(feature, Constant.BODY_FEATURE_DIMS);
}
Script script = new Script(
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG,
"(cosineSimilarity(params.body, 'body') + 1) / 2 * 100", Collections.singletonMap("body", feature));
matchResult.addAll(match0(poolId, script));
}
} else {
log.info("no body feature");
}
}
private List<Person> match0(String poolId, Script script) throws IOException {
List<Person> persons = new ArrayList<>();
ScriptScoreQueryBuilder queryBuilder = QueryBuilders.scriptScoreQuery(QueryBuilders.matchAllQuery(), script);
SearchSourceBuilder builder = new SearchSourceBuilder()
.size(Constant.MATCH_RESULT_SIZE)
.query(queryBuilder)
.fetchSource(new String[]{"personId", "age", "gender", "fid"}, null);
SearchRequest searchRequest = new SearchRequest(poolId)
.source(builder);
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
SearchHit[] hits1 = hits.getHits();
for (SearchHit item : hits1) {
Map<String, Object> source = item.getSourceAsMap();
Person p = new Person();
p.setPersonId((String) source.get("personId"));
p.setAge((Integer) source.get("age"));
p.setGender((String) source.get("gender"));
p.setScore((int) item.getScore());
p.setPersonPoolId(item.getIndex());
persons.add(p);
} }
return persons; return persons;
} }
......
package com.viontech.match.service; package com.viontech.match.service;
import com.viontech.keliu.model.Person; import com.viontech.keliu.model.Person;
import com.viontech.match.config.Constant;
import com.viontech.match.entity.PoolInfo; import com.viontech.match.entity.PoolInfo;
import com.viontech.match.entity.vo.RequestVo; import com.viontech.match.entity.vo.RequestVo;
import com.viontech.match.entity.vo.ResponseVo; import com.viontech.match.entity.vo.ResponseVo;
...@@ -66,11 +67,10 @@ public class PoolService { ...@@ -66,11 +67,10 @@ public class PoolService {
log.info("特征池创建操作完成:[{}]", poolId); log.info("特征池创建操作完成:[{}]", poolId);
return ResponseVo.success(rid); return ResponseVo.success(rid);
} catch (ElasticsearchStatusException e) { } catch (ElasticsearchStatusException e) {
if (e.status() == RestStatus.BAD_REQUEST) { if (e.status() == RestStatus.BAD_REQUEST && e.getMessage().contains(Constant.STR_POOL_ID_ALREADY_EXISTS)) {
return ResponseVo.error(rid, 20, "already exit poolId"); return ResponseVo.error(rid, 20, "already exit poolId");
} else { } else {
log.error("createPool", e); throw e;
return ResponseVo.error(rid, e.getDetailedMessage());
} }
} }
} }
...@@ -174,7 +174,14 @@ public class PoolService { ...@@ -174,7 +174,14 @@ public class PoolService {
builder.startObject("data"); builder.startObject("data");
{ {
builder.field("type", "dense_vector"); builder.field("type", "dense_vector");
builder.field("dims", 512); builder.field("dims", Constant.FACE_FEATURE_DIMS);
}
builder.endObject();
builder.startObject("body");
{
builder.field("type", "dense_vector");
builder.field("dims", Constant.BODY_FEATURE_DIMS);
} }
builder.endObject(); builder.endObject();
......
...@@ -3,4 +3,5 @@ server.port=12000 ...@@ -3,4 +3,5 @@ server.port=12000
spring.jackson.time-zone=GMT+8 spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# es # es
spring.elasticsearch.rest.uris=http://192.168.9.116:9200
\ No newline at end of file \ No newline at end of file
#spring.elasticsearch.rest.uris=http://192.168.9.116:9200
spring.elasticsearch.rest.uris=http://127.0.0.1:9200
\ No newline at end of file \ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!