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;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.viontech.keliu.model.BodyFeature;
import com.viontech.keliu.model.FaceFeature;
import com.viontech.keliu.model.Person;
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.ResponseVo;
import lombok.extern.slf4j.Slf4j;
......@@ -116,6 +118,7 @@ public class PersonService {
if (faceFeatures != null && faceFeatures.size() > 0) {
for (FaceFeature faceFeature : faceFeatures) {
Double[] feature = faceFeature.getFeature();
if (feature != null && feature.length == Constant.FACE_FEATURE_DIMS) {
String fid = faceFeature.getFid();
IndexRequest indexRequest = new IndexRequest(poolId)
......@@ -124,6 +127,25 @@ public class PersonService {
}
}
}
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)
.source(XContentType.JSON, "personId", personId, "body", feature, "fid", fid, "age", age, "gender", gender);
bulkRequest.add(indexRequest);
}
}
}
if (bulkRequest.requests().size() == 0) {
return null;
}
......@@ -142,28 +164,72 @@ public class PersonService {
public List<Person> matchPerson(String poolId, Person person) throws Exception {
List<Person> matchResult = new ArrayList<>();
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) {
for (FaceFeature faceFeature : faceFeatures) {
Double[] feature = faceFeature.getFeature();
if (feature.length < 512) {
if (feature == null || feature.length != Constant.FACE_FEATURE_DIMS) {
continue;
}
Script script = new Script(
ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG,
"(cosineSimilarity(params.face, 'data') + 1) / 2 * 100", Collections.singletonMap("face", feature));
matchResult.addAll(match0(poolId, script));
}
} else {
log.info("no face feature");
}
}
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.data, 'data') + 1) / 2 * 100", Collections.singletonMap("data", feature));
"(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(5)
.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();
......@@ -178,13 +244,6 @@ public class PersonService {
p.setPersonPoolId(item.getIndex());
persons.add(p);
}
}
} else {
log.info("no face feature");
}
if (persons.size() > 5) {
persons = persons.stream().sorted(Comparator.comparingInt(Person::getScore)).limit(5).collect(Collectors.toList());
}
return persons;
}
......
package com.viontech.match.service;
import com.viontech.keliu.model.Person;
import com.viontech.match.config.Constant;
import com.viontech.match.entity.PoolInfo;
import com.viontech.match.entity.vo.RequestVo;
import com.viontech.match.entity.vo.ResponseVo;
......@@ -66,11 +67,10 @@ public class PoolService {
log.info("特征池创建操作完成:[{}]", poolId);
return ResponseVo.success(rid);
} 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");
} else {
log.error("createPool", e);
return ResponseVo.error(rid, e.getDetailedMessage());
throw e;
}
}
}
......@@ -174,7 +174,14 @@ public class PoolService {
builder.startObject("data");
{
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();
......
......@@ -3,4 +3,5 @@ server.port=12000
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# es
spring.elasticsearch.rest.uris=http://192.168.9.116:9200
\ 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
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!