HumanVehicleAssociationServiceImpl.java 15.7 KB
package com.objecteye.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.objecteye.entity.PageResult;
import com.objecteye.pojo.*;
import com.objecteye.service.HumanVehicleAssociationService;
import com.objecteye.utils.CompareDistance;
import com.objecteye.utils.HttpClientUtils;
import com.objecteye.utils.UserTools;
import com.objecteye.utils.VehicleEngine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yumiu
 */
@Service
@Slf4j
public class HumanVehicleAssociationServiceImpl implements HumanVehicleAssociationService {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private HttpClientUtils httpClientUtils;
    @Autowired
    private VehicleEngine vehicleEngine;
    @Autowired
    private CompareDistance compareDistance;
    @Value("${topN}")
    private int topN;
    @Value("${threadNum}")
    private int threadNum;
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 以人搜车
     *
     * @param currentpage
     * @param pagevolume
     * @param picfile
     * @return
     */
    @Override
    public PageResult searchVehicleFromHuman(Long starttime, Long endtime, Float thresholds, int currentpage, int pagevolume, MultipartFile picfile) {
        if (null == picfile || picfile.equals("undefined")) {
            return null;
        }
        //创建返回的数据对象
        Vector<SearchVehicleFromPeopleInfo> searchVehicleFromPeopleInfos = new Vector<>();

        String peopleFace = httpClientUtils.multiToPeople(picfile);
        JSONObject peopleFaceJson = JSONObject.parseObject(peopleFace);
        Integer code = peopleFaceJson.getInteger("code");
        if (code == 0) {
            JSONObject result = peopleFaceJson.getJSONObject("result");
            if (result == null) {
                return null;
            }
            Integer count = result.getInteger("count");
            if (count > 0) {
                JSONArray info = result.getJSONArray("info");
                //创建treeMap,设置为降序排列
                TreeMap<Integer, JSONArray> treeMap = new TreeMap<>((a, b) -> b - a);
                for (int i = 0; i < info.size(); i++) {
                    int size = 0;
                    JSONObject peopleInfoSingle = info.getJSONObject(i);
                    JSONObject faceDetectInfoParam = peopleInfoSingle.getJSONObject("faceDetectInfoParam");
                    JSONObject face_position = faceDetectInfoParam.containsKey("face_position") ? faceDetectInfoParam.getJSONObject("face_position") : null;
                    Integer width = 0;
                    Integer height = 0;
                    if (null != face_position) {
                        width = face_position.getInteger("width");
                        height = face_position.getInteger("height");
                    }
                    //获取到面积
                    size = width * height;
                    JSONArray featureArray = peopleInfoSingle.containsKey("feature") ? peopleInfoSingle.getJSONArray("feature") : null;
                    treeMap.put(size, featureArray);
                }
                //获取到最大的人像
                JSONArray maxFeaArr = treeMap.get(treeMap.firstKey());

                //将JSONArr转换为float[]
                float[] feaFloats = new float[512];
                for (int i = 0; i < feaFloats.length; i++) {
                    feaFloats[i] = maxFeaArr.getFloat(i);
                }

                //调用人脸检索接口获取相似的人像的RetrieveKey
                int localTopN = 20000;
                SearchDataFromRetrieveDb searchDataFromRetrieveDb = vehicleEngine.searchDataFromRetrieveDb(localTopN, thresholds, threadNum, feaFloats);
                List<SearchDataFromRetrieveDbResult> list = searchDataFromRetrieveDb.getResult();
                Map<String, SearchDataFromRetrieveDbResult> retrieveKeyDbResultMap = list.stream()
                        .collect(Collectors.toMap(SearchDataFromRetrieveDbResult::getRetrieveKey, a -> a, (k1, k2) -> k1));

                Criteria criteria = new Criteria();
                if (starttime == null) {
                    if (endtime != null) {
                        criteria.and("pictime").lte(endtime);
                    }
                } else {
                    if (endtime == null) {
                        criteria.and("pictime").gte(starttime);
                    } else {
                        criteria.and("pictime").gte(starttime).lte(endtime);
                    }
                }
                Query primaryStepQuery = Query.query(criteria).with(Sort.by(Sort.Order.desc("pictime")));
                primaryStepQuery.fields().include("id");
                primaryStepQuery.fields().include("personid");
                primaryStepQuery.fields().include("pictime");
                primaryStepQuery.fields().include("vehicle_plate_hphm");
                primaryStepQuery.fields().include("picurl");
                primaryStepQuery.fields().include("personUrl");
                // 数据库过滤结果
                List<RabbitMQVehicle> rabbitMqVehicles = mongoTemplate.find(primaryStepQuery, RabbitMQVehicle.class);

                for (RabbitMQVehicle rabbitMqVehicle : rabbitMqVehicles) {
                    if (rabbitMqVehicle == null) {
                        continue;
                    }
                    if (retrieveKeyDbResultMap.containsKey(rabbitMqVehicle.getPersonid())) {
                        SearchDataFromRetrieveDbResult searchDataFromRetrieveDbResult = retrieveKeyDbResultMap.get(rabbitMqVehicle.getPersonid());
                        SearchVehicleFromPeopleInfo searchVehicleFromPeopleSingle = new SearchVehicleFromPeopleInfo(rabbitMqVehicle.getId(),
                                simpleDateFormat.format(new Date(rabbitMqVehicle.getPictime())),
                                rabbitMqVehicle.getVehicle_plate_hphm(), searchDataFromRetrieveDbResult.getScore(), rabbitMqVehicle.getPicurl(), rabbitMqVehicle.getPersonUrl());
                        searchVehicleFromPeopleInfos.add(searchVehicleFromPeopleSingle);
                    }
                }
                return UserTools.makePageResultByBaseList(searchVehicleFromPeopleInfos, currentpage, pagevolume);
            }
        }
        return null;
    }

    /**
     * 根据精准车辆号牌查询人像
     *
     * @param currentpage
     * @param pagevolume
     * @param hphm
     * @return
     */
    @Override
    public SearchPeopleOfhphmResult searchPeopleFromHphm(Long starttime, Long endtime, Integer currentpage, Integer pagevolume, String hphm) {
        SearchPeopleOfhphmResult searchPeopleOfhphmResult = new SearchPeopleOfhphmResult();
        List<SearchPeopleOfHphmInfo> list = null;
        if (!"".equals(hphm)) {
            list = new ArrayList<SearchPeopleOfHphmInfo>();
            //首先根据车辆号牌查询到相关的车辆
            List<RabbitMQVehicle> byHphm = findByHphm(starttime, endtime, hphm, currentpage, pagevolume);
            for (RabbitMQVehicle rmqv : byHphm) {
                Long pictime = rmqv.getPictime();

                //获取时间范围
                starttime = (starttime == null) ? 0 : starttime;
                endtime = (endtime == null) ? 9999999999999L : endtime;

                if (pictime <= endtime && pictime >= starttime) {
                    SearchPeopleOfHphmInfo searchPeopleOfHphmInfo = new SearchPeopleOfHphmInfo(rmqv.getId(),
                            simpleDateFormat.format(new Date(rmqv.getPictime())),
                            rmqv.getVehicle_plate_hphm(), rmqv.getPersonUrl());
                    list.add(searchPeopleOfHphmInfo);
                }
            }
            searchPeopleOfhphmResult.setTotal((int) Math.ceil((double) list.size() / pagevolume));
            searchPeopleOfhphmResult.setRow(list);

        }
        return searchPeopleOfhphmResult;
    }


    /**
     * 通过personid获取到车辆信息
     *
     * @return
     */
    @Override
    public RabbitMQVehicle findVehicleByRetrieveKey(String personid) {

        Query query = new Query();
        Criteria criteria = Criteria.where("personid").is(personid);
        query.addCriteria(criteria);
        return mongoTemplate.findOne(query, RabbitMQVehicle.class);
    }

    /**
     * 通过车辆号牌获取到车辆信息
     *
     * @return
     */
    @Override
    public List<RabbitMQVehicle> findByHphm(Long starttime, Long endtime, String hphm, int currentPage, int pageSize) {
        Query query = new Query();
        query.with(Sort.by(Sort.Order.desc("pictime")));
        int skip = (currentPage - 1) * pageSize;
        query.addCriteria(new Criteria().andOperator(Criteria.where("vehicle_plate_hphm").is(hphm), Criteria.where("personUrl").ne(null)));
        query.skip(skip);
        query.limit(pageSize);
        return mongoTemplate.find(query, RabbitMQVehicle.class);
    }

    /**
     * 通过retrieveKey获取到人信息
     *
     * @return
     */
    @Override
    public FaceInfoParam findPeopleByRetrieveKey(String retrieveKey, int currentPage, int pageSize) {
        Query query = new Query();
        int skip = (currentPage - 1) * pageSize;

        Criteria criteria = Criteria.where("retrieveKey").is(retrieveKey);
        query.addCriteria(criteria);

        query.skip(skip);// 从那条记录开始
        query.limit(pageSize);// 取多少条记录
        return mongoTemplate.findOne(query, FaceInfoParam.class);
    }

    /**
     * 根据车辆图片查询关联的人
     *
     * @param number
     * @param threshold
     * @param currentpage
     * @param pagevolume
     * @param picfile
     * @return
     */
    @Override
    public List<FaceInfoParam> searchPeopleOfVehiclePic(int number, double threshold, int currentpage, int pagevolume, MultipartFile picfile) {
        List<FaceInfoParam> list = null;

        //根据MultipartFile,调用接口获取到该车辆的信息
        JSONObject byPic = findByPic(number, threshold, currentpage, pagevolume, picfile);
        //根据查询到的车辆获取到每辆车的retrieveKey
        if (byPic != null && byPic.getInteger("total") > 0) {
            list = new ArrayList<FaceInfoParam>();
            JSONArray rowArr = byPic.getJSONArray("row");
            for (int i = 0; i < rowArr.size(); i++) {
                String retrieveKey = rowArr.getJSONObject(i).getString("retrieveKey");
                //根据retrieveKey查询到相关人
                Query query = new Query();
                query.addCriteria(Criteria.where("retrieveKey").is(retrieveKey));

                FaceInfoParam faceInfoParamSingle = mongoTemplate.findOne(query, FaceInfoParam.class);
                list.add(faceInfoParamSingle);
            }
        }
        return list;
    }

    /**
     * 通过过车序号和图片查询车辆集合
     *
     * @param number
     * @param threshold
     * @param currentpage
     * @param pagevolume
     * @param picfile
     * @return
     */
    public JSONObject findByPic(int number, double threshold, int currentpage, int pagevolume, MultipartFile picfile) {
        JSONObject data = null;
        //封装结果的对象
        if (picfile == null) {
            return data;
        }

        //查询到所有数据信息
        List<RabbitMQVehicle> allRabbitMQVehicleList = mongoTemplate.findAll(RabbitMQVehicle.class);

        String vehicleInfoByBase64 = httpClientUtils.multiToVehicle(picfile);
        JSONArray infoArr = JSONObject.parseObject(vehicleInfoByBase64).getJSONObject("result").getJSONArray("info");

        //获取到用户选中的车辆
        int size = infoArr.size();
        if (number < size) {
            JSONObject vehicleSingleInfo = infoArr.getJSONObject(number);

            //获取该车辆的特征信息
            double[] currentFeature = new double[256];
            JSONArray featureArr = vehicleSingleInfo.getJSONObject("vehicle_fea_res").getJSONArray("feature");
            //将featureArr转换为double[]类型
            for (int i = 0; i < featureArr.size(); i++) {
                currentFeature[i] = featureArr.getDouble(i);
            }

            double currentFea = compareDistance.getDistance(currentFeature);
            //遍历mongodb所有的车辆信息
            List<PicVehicleCompare> pvc = new ArrayList<PicVehicleCompare>();
            for (RabbitMQVehicle rabbitMQVehicle : allRabbitMQVehicleList) {
                int vehicle_special_type = rabbitMQVehicle.getVehicle_special_type();
                double[] dbFeature = rabbitMQVehicle.getVehicle_fea_feature();
                //进行比对
                double dbFea = compareDistance.getDistance(dbFeature);
                double similar = compareDistance.simDistance(currentFeature, currentFea, dbFeature, dbFea);
                if (threshold <= similar) {
                    similar = (double) Math.round(similar * 100) / 100;
                    similar = similar >= 1 ? 1 : similar;
                    PicVehicleCompare picVehicleCompare = new PicVehicleCompare();
                    picVehicleCompare.setSimilar(similar);
                    picVehicleCompare.setRabbitMQVehicle(rabbitMQVehicle);
                    pvc.add(picVehicleCompare);
                }
            }

            //对row进行排序
            pvc.sort((o1, o2) -> {
                if (o2.getSimilar() == o1.getSimilar()) {
                    return 0;
                } else {
                    return (o2.getSimilar() > o1.getSimilar()) ? 1 : -1;
                }
            });

            //对row进行分页查询
            List<PicVehicleCompare> picVehicleComparesNew = UserTools.getPagedResultByBaseList(pvc, currentpage, pagevolume);
            //根据总条数获取总页数
            int totalPage = UserTools.getPageTotalByBaseList(pvc, pagevolume);

            //获取row数据
            JSONArray row = new JSONArray();
            for (PicVehicleCompare next : picVehicleComparesNew) {
                JSONObject rowData = new JSONObject();
                //获取id
                RabbitMQVehicle rabbitMQVehicle1 = next.getRabbitMQVehicle();
                String id = rabbitMQVehicle1.getId();
                rowData.put("id", id);
                rowData.put("hphm", rabbitMQVehicle1.getVehicle_plate_hphm());
                Long pictime = rabbitMQVehicle1.getPictime();
                rowData.put("phototime", simpleDateFormat.format(new Date(pictime)));
                rowData.put("recordid", rabbitMQVehicle1.getRecordid());
                // 新方法,如果不需要四舍五入,可以使用RoundingMode.DOWN
                double similar = next.getSimilar();
                BigDecimal bg = new BigDecimal(similar).setScale(2, RoundingMode.UP);
                rowData.put("similar", bg.doubleValue());
                rowData.put("retrieveKey", rabbitMQVehicle1.getPersonid());
                //添加图片路径
                rowData.put("picurl", rabbitMQVehicle1.getPicurl());
                row.add(rowData);
            }
            data = new JSONObject();
            if (pvc.size() > 0 && row.size() > 0) {
                data.put("total", totalPage);
                data.put("row", row);
            }
        }
        return data;
    }
}