package org.wlld.imageRecognition;


import org.wlld.MatrixTools.Matrix;
import org.wlld.MatrixTools.MatrixOperation;
import org.wlld.config.Classifier;
import org.wlld.config.StudyPattern;
import org.wlld.i.OutBack;
import org.wlld.imageRecognition.border.*;
import org.wlld.imageRecognition.segmentation.*;
import org.wlld.nerveCenter.NerveManager;
import org.wlld.nerveCenter.Normalization;
import org.wlld.nerveEntity.SensoryNerve;
import org.wlld.param.Food;
import org.wlld.tools.ArithUtil;
import org.wlld.tools.IdCreator;

import java.util.*;

public class Operation {//进行计算
    private TempleConfig templeConfig;//配置初始化参数模板
    private Convolution convolution = new Convolution();
    private MatrixBack matrixBack = new MatrixBack();
    private ImageBack imageBack = new ImageBack();
    private OutBack outBack;

    public TempleConfig getTempleConfig() {
        return templeConfig;
    }

    public Operation(TempleConfig templeConfig) {
        this.templeConfig = templeConfig;
    }

    public Operation(TempleConfig templeConfig, OutBack outBack) {
        this.templeConfig = templeConfig;
        this.outBack = outBack;
    }

    public List<Double> convolution(Matrix matrix, Map<Integer, Double> tagging) throws Exception {
        //进行卷积
        int maxNub;
        if (templeConfig.getRow() >= templeConfig.getColumn()) {
            maxNub = templeConfig.getRow();
        } else {
            maxNub = templeConfig.getColumn();
        }
        int id = -1;
        if (tagging != null && templeConfig.isHavePosition()) {
            for (Map.Entry<Integer, Double> entry : tagging.entrySet()) {
                if (entry.getValue() == 1) {
                    id = entry.getKey();
                    break;
                }
            }
        }
        Matrix matrix1 = convolution.getFeatures(matrix, maxNub, templeConfig, id);
        return sub(matrix1);
    }

    public void setTray(ThreeChannelMatrix threeChannelMatrix) throws Exception {//设置托盘
        Matrix matrixR = threeChannelMatrix.getMatrixR();
        Matrix matrixG = threeChannelMatrix.getMatrixG();
        Matrix matrixB = threeChannelMatrix.getMatrixB();
        Random random = new Random();
        int x = matrixR.getX();
        int y = matrixR.getY();
        int size = templeConfig.getFood().getRegressionNub();
        RgbRegression rgbRegression = new RgbRegression(size);
        for (int i = 0; i < size; i++) {
            int xr = random.nextInt(x);
            int yr = random.nextInt(y);
            double[] rgb = new double[]{matrixR.getNumber(xr, yr) / 255, matrixG.getNumber(xr, yr) / 255,
                    matrixB.getNumber(xr, yr) / 255};
            rgbRegression.insertRGB(rgb);
        }
        rgbRegression.regression();
        templeConfig.getFood().getTrayBody().add(rgbRegression);
    }

    public void finishColorStudy() throws Exception {//进行最后学习
        DimensionMappingStudy dimensionAll = new DimensionMappingStudy(templeConfig);
        dimensionAll.start();//生成映射层，并将已经保存的knn特征进行映射
        templeConfig.getFood().setDimensionMappingStudy(dimensionAll);
    }

    public RegionBody colorStudy(ThreeChannelMatrix threeChannelMatrix, int tag, List<Specifications> specificationsList
            , String url, boolean isFood) throws Exception {
        Watershed watershed = new Watershed(threeChannelMatrix, specificationsList, templeConfig);
        List<RegionBody> regionBodies = watershed.rainfall();
        RegionBody regionBodyMax = null;
        double max = 0;
        for (RegionBody regionBody : regionBodies) {
            int minX = regionBody.getMinX();
            int minY = regionBody.getMinY();
            int maxX = regionBody.getMaxX();
            int maxY = regionBody.getMaxY();
            int s = (maxX - minX) * (maxY - minY);
            if (s > max) {
                max = s;
                regionBodyMax = regionBody;
            }
        }
        if (max > 0) {
            //直接选择面积最大的区域
            int minX = regionBodyMax.getMinX();
            int minY = regionBodyMax.getMinY();
            int maxX = regionBodyMax.getMaxX();
            int maxY = regionBodyMax.getMaxY();
            int xSize = maxX - minX;
            int ySize = maxY - minY;
            ThreeChannelMatrix threeChannelMatrix1 = convolution.getRegionMatrix(threeChannelMatrix, minX, minY, xSize, ySize);
            List<Double> feature = convolution.getCenterTexture(threeChannelMatrix1, templeConfig, templeConfig.getFeatureNub(), true, tag
                    , isFood);
            Matrix veck = MatrixOperation.listToRowVector(feature);//将特征转化为矩阵
            knnStudy(tag, veck);
            return regionBodyMax;
        } else {
            throw new Exception("Parameter exception region size 0 url:" + url);
        }
    }

    private void knnStudy(int tagging, Matrix vector) throws Exception {
        Knn knn = templeConfig.getKnn();
        knn.insertMatrix(vector, tagging);
    }

    private void avgStudy(int tagging, Matrix myMatrix) throws Exception {//特征矩阵均值学习
        VectorK vectorK = templeConfig.getVectorK();
        vectorK.insertMatrix(tagging, myMatrix);
    }

    private void lvqStudy(int tagging, Matrix myMatrix) throws Exception {//LVQ学习
        LVQ lvq = templeConfig.getLvq();
        MatrixBody matrixBody = new MatrixBody();
        matrixBody.setMatrix(myMatrix);
        matrixBody.setId(tagging);
        lvq.insertMatrixBody(matrixBody);
    }

    public List<RegionBody> colorLook(ThreeChannelMatrix threeChannelMatrix, List<Specifications> specificationsList) throws Exception {
        Watershed watershed = new Watershed(threeChannelMatrix, specificationsList, templeConfig);
        List<RegionBody> regionList = watershed.rainfall();
        for (RegionBody regionBody : regionList) {
            int minX = regionBody.getMinX();
            int minY = regionBody.getMinY();
            int maxX = regionBody.getMaxX();
            int maxY = regionBody.getMaxY();
            int xSize = maxX - minX;
            int ySize = maxY - minY;
            ThreeChannelMatrix threeChannelMatrix1 = convolution.getRegionMatrix(threeChannelMatrix, minX, minY, xSize, ySize);
            List<Double> feature = convolution.getCenterTexture(threeChannelMatrix1, templeConfig, templeConfig.getFeatureNub(), false, 0,
                    false);
            int id;
            Food food = templeConfig.getFood();
            int[] foodTypes = food.getFoodType();
            Matrix myMatrix = MatrixOperation.listToRowVector(feature);
            DimensionMappingStudy deepMapping = templeConfig.getFood().getDimensionMappingStudy();
            id = deepMapping.getType(myMatrix);
            //判断该类别是否属于干食
            boolean isFood = false;
            if (foodTypes != null) {
                for (int myType : foodTypes) {
                    if (id == myType) {
                        isFood = true;
                        break;
                    }
                }
            }
            if (isFood) {//判断类别，获取积分
                Map<Integer, GMClustering> foods = food.getFoodMeanMap();
                Map<Integer, GMClustering> test = new HashMap<>();
                test.put(1, foods.get(1));
                test.put(id, foods.get(id));
                CutFood cutFood = new CutFood(templeConfig, test);
                regionBody.setTypeNub(cutFood.getTypeNub(threeChannelMatrix1, id));
            }
            regionBody.setType(id);
            System.out.println("类别" + id);
        }
        return regionList;
    }

    private int getIdByCos(Matrix myVector) throws Exception {//VAG获取分类
        Map<Integer, Matrix> matrixK = templeConfig.getVectorK().getMatrixK();
        double maxCos = 0;
        int id = 0;
        for (Map.Entry<Integer, Matrix> entry : matrixK.entrySet()) {
            Matrix matrix = entry.getValue();
            double cos = MatrixOperation.getNormCos(matrix, myVector);
            //System.out.println("距离===" + dist + ",类别==" + entry.getKey()+",核心:"+matrix.getString());
            if (cos > maxCos) {
                maxCos = cos;
                id = entry.getKey();
            }
        }
        return id;
    }

    private int getIdByVag(Matrix myVector) throws Exception {//VAG获取分类
        Map<Integer, Matrix> matrixK = templeConfig.getVectorK().getMatrixK();
        double minDist = 0;
        int id = 0;
        for (Map.Entry<Integer, Matrix> entry : matrixK.entrySet()) {
            Matrix matrix = entry.getValue();
            double dist = MatrixOperation.getEDist(matrix, myVector);
            //System.out.println("距离===" + dist + ",类别==" + entry.getKey()+",核心:"+matrix.getString());
            if (minDist == 0 || dist < minDist) {
                minDist = dist;
                id = entry.getKey();
            }
        }
        //System.out.println("=======================");
        return id;
    }

    private int getIdByLVQ(Matrix myVector) throws Exception {//LVQ获取分类
        int id = 0;
        double distEnd = 0;
        LVQ lvq = templeConfig.getLvq();
        MatrixBody[] matrixBodies = lvq.getModel();
        for (int i = 0; i < matrixBodies.length; i++) {
            MatrixBody matrixBody = matrixBodies[i];
            Matrix vector = matrixBody.getMatrix();
            double dist = lvq.vectorEqual(myVector, vector);
            if (distEnd == 0 || dist < distEnd) {
                id = matrixBody.getId();
                distEnd = dist;
            }
        }
        return id;
    }

    public void coverStudy(Map<Integer, ThreeChannelMatrix> matrixMap, int sqNub, int regionSize) throws Exception {
        if (templeConfig.getStudyPattern() == StudyPattern.Cover_Pattern) {
            int size = 0;
            List<CoverBody> coverBodies = new ArrayList<>();
            for (Map.Entry<Integer, ThreeChannelMatrix> entry : matrixMap.entrySet()) {
                //先进行切图
                CoverBody coverBody = new CoverBody();
                Map<Integer, Double> tag = new HashMap<>();
                tag.put(entry.getKey(), 1.0);
                List<List<Double>> lists = convolution.kAvg(entry.getValue(), sqNub, regionSize, templeConfig);
                size = lists.size();
                coverBody.setFeature(lists);
                coverBody.setTag(tag);
                coverBodies.add(coverBody);
            }
            //特征塞入容器完毕
            for (int i = 0; i < size; i++) {
                for (CoverBody coverBody : coverBodies) {
                    List<Double> list = coverBody.getFeature().get(i);
                    if (templeConfig.isShowLog()) {
                        System.out.println("feature:" + list);
                    }
                    intoDnnNetwork(1, list, templeConfig.getSensoryNerves(), true, coverBody.getTag(), null);
                }
            }

        }
    }

    public Map<Integer, Double> coverPoint(ThreeChannelMatrix matrix, int sqNub, int regionSize) throws Exception {
        if (templeConfig.getStudyPattern() == StudyPattern.Cover_Pattern) {
            Map<Integer, Double> coverMap = new HashMap<>();
            Map<Integer, Integer> typeNub = new HashMap<>();
            List<List<Double>> lists = convolution.kAvg(matrix, sqNub, regionSize, templeConfig);
            //特征塞入容器完毕
            int size = lists.size();
            int all = 0;
            for (int i = 0; i < size; i++) {
                List<Double> list = lists.get(i);
                MaxPoint maxPoint = new MaxPoint();
                long pid = IdCreator.get().nextId();
                intoDnnNetwork(pid, list, templeConfig.getSensoryNerves(), false, null, maxPoint);
                int id = maxPoint.getId();
                if (typeNub.containsKey(id)) {
                    typeNub.put(id, typeNub.get(id) + 1);
                } else {
                    typeNub.put(id, 1);
                }
                all++;
            }
            for (Map.Entry<Integer, Integer> entry : typeNub.entrySet()) {
                int nub = entry.getValue();
                coverMap.put(entry.getKey(), ArithUtil.div(nub, all));
            }
            return coverMap;
        } else {
            throw new Exception("PATTERN IS NOT COVER");
        }
    }

    //模板学习
    public void study(Matrix matrix, Map<Integer, Double> tagging) throws Exception {
        if (templeConfig.getStudyPattern() == StudyPattern.Speed_Pattern) {
            List<Double> list = convolution(matrix, tagging);
            intoDnnNetwork(1, list, templeConfig.getSensoryNerves(), true, tagging, null);
        } else {
            throw new Exception("pattern is wrong");
        }
    }

    public int toThreeSee(ThreeChannelMatrix threeChannelMatrix) throws Exception {//三通道
        NerveManager convolutionNerveManagerR = templeConfig.getConvolutionNerveManagerR();
        NerveManager convolutionNerveManagerB = templeConfig.getConvolutionNerveManagerB();
        NerveManager convolutionNerveManagerG = templeConfig.getConvolutionNerveManagerG();
        Matrix matrixR = threeChannelMatrix.getMatrixR();
        Matrix matrixG = threeChannelMatrix.getMatrixG();
        Matrix matrixB = threeChannelMatrix.getMatrixB();
        //进卷积网络
        MatrixBack matrixBackR = new MatrixBack();
        MatrixBack matrixBackG = new MatrixBack();
        MatrixBack matrixBackB = new MatrixBack();
        intoConvolutionNetwork(1, matrixR, convolutionNerveManagerR.getSensoryNerves(),
                false, 0, matrixBackR);
        intoConvolutionNetwork(1, matrixG, convolutionNerveManagerG.getSensoryNerves(),
                false, 0, matrixBackG);
        intoConvolutionNetwork(1, matrixB, convolutionNerveManagerB.getSensoryNerves(),
                false, 0, matrixBackB);
        Matrix myMatrixR = matrixBackR.getMatrix();
        Matrix myMatrixG = matrixBackG.getMatrix();
        Matrix myMatrixB = matrixBackB.getMatrix();
        List<Double> featureALL = new ArrayList<>();
        List<Double> featureR = getFeature(myMatrixR);
        List<Double> featureG = getFeature(myMatrixG);
        List<Double> featureB = getFeature(myMatrixB);
        featureALL.addAll(featureR);
        featureALL.addAll(featureG);
        featureALL.addAll(featureB);
        MaxPoint maxPoint = new MaxPoint();
        long id = IdCreator.get().nextId();
        intoDnnNetwork(id, featureALL, templeConfig.getSensoryNerves(), false, null, maxPoint);
        return maxPoint.getId();
    }

    public void threeLearning(ThreeChannelMatrix threeChannelMatrix, int tagging, boolean isNerveStudy) throws Exception {
        boolean isKernelStudy = true;
        if (isNerveStudy) {
            isKernelStudy = false;
        }
        NerveManager convolutionNerveManagerR = templeConfig.getConvolutionNerveManagerR();
        NerveManager convolutionNerveManagerB = templeConfig.getConvolutionNerveManagerB();
        NerveManager convolutionNerveManagerG = templeConfig.getConvolutionNerveManagerG();
        Matrix matrixR = threeChannelMatrix.getMatrixR();
        Matrix matrixG = threeChannelMatrix.getMatrixG();
        Matrix matrixB = threeChannelMatrix.getMatrixB();
        //进卷积网络
        MatrixBack matrixBackR = new MatrixBack();
        MatrixBack matrixBackG = new MatrixBack();
        MatrixBack matrixBackB = new MatrixBack();
        intoConvolutionNetwork(1, matrixR, convolutionNerveManagerR.getSensoryNerves(),
                isKernelStudy, tagging, matrixBackR);
        intoConvolutionNetwork(1, matrixG, convolutionNerveManagerG.getSensoryNerves(),
                isKernelStudy, tagging, matrixBackG);
        intoConvolutionNetwork(1, matrixB, convolutionNerveManagerB.getSensoryNerves(),
                isKernelStudy, tagging, matrixBackB);
        if (isNerveStudy) {
            Matrix myMatrixR = matrixBackR.getMatrix();
            Matrix myMatrixG = matrixBackG.getMatrix();
            Matrix myMatrixB = matrixBackB.getMatrix();
            List<Double> featureALL = new ArrayList<>();
            List<Double> featureR = getFeature(myMatrixR);
            List<Double> featureG = getFeature(myMatrixG);
            List<Double> featureB = getFeature(myMatrixB);
            featureALL.addAll(featureR);
            featureALL.addAll(featureG);
            featureALL.addAll(featureB);
            Map<Integer, Double> map = new HashMap<>();
            map.put(tagging, 1.0);
            intoDnnNetwork(1, featureALL, templeConfig.getSensoryNerves(), true, map, null);
        }

    }

    public void threeNormalization(ThreeChannelMatrix threeChannelMatrix) throws Exception {
        normalization(threeChannelMatrix.getMatrixR(), templeConfig.getConvolutionNerveManagerR());
        normalization(threeChannelMatrix.getMatrixG(), templeConfig.getConvolutionNerveManagerG());
        normalization(threeChannelMatrix.getMatrixB(), templeConfig.getConvolutionNerveManagerB());

    }

    public void normalization(Matrix matrix, NerveManager nerveManager) throws Exception {
        Normalization normalization = templeConfig.getNormalization();
        intoConvolutionNetwork(1, matrix, nerveManager.getSensoryNerves(),
                false, 0, matrixBack);
        Matrix myMatrix = matrixBack.getMatrix();
        for (int i = 0; i < myMatrix.getX(); i++) {
            for (int j = 0; j < myMatrix.getY(); j++) {
                normalization.putFeature(myMatrix.getNumber(i, j));
            }
        }
    }

    //卷积核学习
    public void learning(Matrix matrix, int tagging, boolean isNerveStudy) throws Exception {
        if (templeConfig.getStudyPattern() == StudyPattern.Accuracy_Pattern) {
            Border border = null;
            if (templeConfig.isHavePosition() && isNerveStudy && tagging > 0) {
                outBack = imageBack;
                border = convolution.borderOnce(matrix, templeConfig);
            }
            boolean isKernelStudy = true;
            if (isNerveStudy) {
                isKernelStudy = false;
            }
            //进卷积网络
            intoConvolutionNetwork(1, matrix, templeConfig.getConvolutionNerveManager().getSensoryNerves(),
                    isKernelStudy, tagging, matrixBack);
            if (isNerveStudy) {
                //卷积后的结果
                Matrix myMatrix = matrixBack.getMatrix();
                if (templeConfig.isHavePosition() && tagging > 0) {
                    border.end(myMatrix, tagging);
                }
                int classifier = templeConfig.getClassifier();
                switch (classifier) {
                    case Classifier.DNN:
                        dnn(tagging, myMatrix);
                        break;
                    case Classifier.LVQ:
                        lvq(tagging, myMatrix);
                        break;
                    case Classifier.VAvg:
                        vectorAvg(tagging, myMatrix);
                        break;
                }
            }
        } else {
            throw new Exception("pattern is wrong");
        }
    }

    private void dnn(int tagging, Matrix myMatrix) throws Exception {//DNN网络学习
        Map<Integer, Double> map = new HashMap<>();
        map.put(tagging, 1.0);
        List<Double> feature = getFeature(myMatrix);
        if (templeConfig.isShowLog()) {
            System.out.println(feature);
        }
        intoDnnNetwork(1, feature, templeConfig.getSensoryNerves(), true, map, null);
    }

    private void vectorAvg(int tagging, Matrix myMatrix) throws Exception {//特征矩阵均值学习
        Matrix vector = MatrixOperation.matrixToVector(myMatrix, true);
        VectorK vectorK = templeConfig.getVectorK();
        vectorK.insertMatrix(tagging, vector);
    }

    private void lvq(int tagging, Matrix myMatrix) throws Exception {//LVQ学习
        LVQ lvq = templeConfig.getLvq();
        Matrix vector = MatrixOperation.matrixToVector(myMatrix, true);
        if (templeConfig.isShowLog()) {
            System.out.println(vector.getString());
        }
        MatrixBody matrixBody = new MatrixBody();
        matrixBody.setMatrix(vector);
        matrixBody.setId(tagging);
        lvq.insertMatrixBody(matrixBody);
    }

    private List<Double> getFeatures(Matrix matrix) throws Exception {
        List<Double> list = new ArrayList<>();
        for (int i = 0; i < matrix.getX(); i++) {
            for (int j = 0; j < matrix.getY(); j++) {
                double nub = matrix.getNumber(i, j);
                list.add(nub);
            }
        }
        return list;
    }

    private List<Double> getFeature(Matrix matrix) throws Exception {//将特征矩阵转化为集合并除10
        List<Double> list = new ArrayList<>();
        Normalization normalization = templeConfig.getNormalization();
        double middle = normalization.getAvg();
        for (int i = 0; i < matrix.getX(); i++) {
            for (int j = 0; j < matrix.getY(); j++) {
                double nub = matrix.getNumber(i, j);
                if (nub != 0) {
                    nub = ArithUtil.sub(nub, middle);
                    list.add(nub);
                } else {
                    list.add(0.0);
                }
            }
        }
        return list;
    }

    private List<List<Double>> getFeatures(Matrix matrix, int size) throws Exception {
        List<List<Double>> lists = new ArrayList<>();
        int x = matrix.getX() - size;//求导后矩阵的行数
        int y = matrix.getY() - size;//求导后矩阵的列数
        for (int i = 0; i < x; i += size) {//遍历行
            for (int j = 0; j < y; j += size) {//遍历每行的列
                Matrix myMatrix = matrix.getSonOfMatrix(i, j, size, size);
                lists.add(getListFeature(myMatrix));
            }
        }
        return lists;
    }

    private List<Double> getListFeature(Matrix matrix) throws Exception {
        List<Double> list = new ArrayList<>();
        int x = matrix.getX();
        int y = matrix.getY();
        for (int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++) {
                double nub = matrix.getNumber(i, j) / 255;
                list.add(nub);
            }
        }
        return list;
    }

    //图像视觉 speed 模式
    public void look(Matrix matrix, long eventId) throws Exception {
        if (templeConfig.getStudyPattern() == StudyPattern.Speed_Pattern) {
            List<Double> list = convolution(matrix, null);
            intoDnnNetwork(eventId, list, templeConfig.getSensoryNerves(), false, null, outBack);
        } else if (templeConfig.getStudyPattern() == StudyPattern.Accuracy_Pattern) {
            throw new Exception("studyPattern not right");
        }
    }

    public List<Integer> manyLook(Matrix matrix, long eventId) throws Exception {//无定位多物体识别
        if (templeConfig.getStudyPattern() == StudyPattern.Accuracy_Pattern) {
            List<Integer> list = new ArrayList<>();
            Frame frame = templeConfig.getFrame();
            List<FrameBody> frameBodies = convolution.getRegion(matrix, frame);
            MatrixBack matrixBack = new MatrixBack();
            for (FrameBody frameBody : frameBodies) {
                intoConvolutionNetwork(eventId, frameBody.getMatrix(), templeConfig.getConvolutionNerveManager().getSensoryNerves(),
                        false, -1, matrixBack);
                Matrix myMatrix = matrixBack.getMatrix();
                int classifier = templeConfig.getClassifier();
                int id = 0;
                switch (classifier) {
                    case Classifier.LVQ:
                        id = getClassificationIdByLVQ(myMatrix);
                        break;
                    case Classifier.DNN:
                        id = getClassificationIdByDnn(myMatrix);
                        break;
                    case Classifier.VAvg:
                        id = getClassificationIdByVag(myMatrix);
                        break;
                }
                list.add(id);
            }
            return list;
        } else {
            throw new Exception("wrong model");
        }
    }

    //边框检测+识别分类
    public Map<Integer, List<FrameBody>> lookWithPosition(Matrix matrix, long eventId) throws Exception {
        Frame frame = templeConfig.getFrame();
        if (templeConfig.isHavePosition() && frame != null && frame.isReady()) {
            //区域分割
            List<FrameBody> frameBodies = convolution.getRegion(matrix, frame);
            if (templeConfig.getStudyPattern() == StudyPattern.Speed_Pattern) {
                int maxNub = 0;
                if (templeConfig.getRow() >= templeConfig.getColumn()) {
                    maxNub = templeConfig.getRow();
                } else {
                    maxNub = templeConfig.getColumn();
                }
                //坐标回调类
                for (FrameBody frameBody : frameBodies) {
                    //Speed 模式下的最后卷积结果
                    Matrix matrix1 = convolution.getFeatures(frameBody.getMatrix(), maxNub, templeConfig, -1);
                    //卷积层输出即边框回归的输入的特征向量
                    frameBody.setEndMatrix(matrix1);
                    List<Double> list = sub(matrix1);
                    imageBack.setFrameBody(frameBody);
                    //进入神经网络判断
                    intoDnnNetwork(eventId, list, templeConfig.getSensoryNerves(), false, null, imageBack);
                }
                return toPosition(frameBodies, frame.getWidth(), frame.getHeight());
            } else if (templeConfig.getStudyPattern() == StudyPattern.Accuracy_Pattern) {
                MatrixBack matrixBack = new MatrixBack();
                for (FrameBody frameBody : frameBodies) {
                    intoConvolutionNetwork(eventId, frameBody.getMatrix(), templeConfig.getConvolutionNerveManager().getSensoryNerves(),
                            false, -1, matrixBack);
                    Matrix myMatrix = matrixBack.getMatrix();
                    //卷积层输出即边框回归的输入的特征向量
                    frameBody.setEndMatrix(myMatrix);
                    int classifier = templeConfig.getClassifier();
                    int id = 0;
                    switch (classifier) {
                        case Classifier.LVQ:
                            id = getClassificationIdByLVQ(myMatrix);
                            break;
                        case Classifier.DNN:
                            id = getClassificationIdByDnn(myMatrix);
                            break;
                        case Classifier.VAvg:
                            id = getClassificationIdByVag(myMatrix);
                            break;
                    }
                    frameBody.setId(id);
                }
                return toPosition(frameBodies, frame.getWidth(), frame.getHeight());
            } else {
                throw new Exception("wrong model");
            }
        } else {
            throw new Exception("position not study or frame is not ready");
        }
    }

    private Map<Integer, List<FrameBody>> toPosition(List<FrameBody> frameBodies, int width, int height) throws Exception {//把分类都拿出来
        for (FrameBody frameBody : frameBodies) {
            if (frameBody.getPoint() > templeConfig.getTh()) {//存在一个识别分类
                getBox(frameBody, width, height);
            }
        }
        return result(frameBodies);
    }

    private Map<Integer, List<FrameBody>> result(List<FrameBody> frameBodies) {
        Map<Integer, List<FrameBody>> map = new HashMap<>();
        for (FrameBody frameBody : frameBodies) {
            if (frameBody.getPoint() > templeConfig.getTh()) {//存在一个识别分类
                int id = frameBody.getId();
                if (map.containsKey(id)) {
                    List<FrameBody> frameBodies1 = map.get(id);
                    boolean isHere = false;
                    for (FrameBody frameBody1 : frameBodies1) {
                        double iou = getIou(frameBody1, frameBody);
                        if (iou > templeConfig.getIouTh()) {
                            isHere = true;
                            break;
                        }
                    }
                    if (!isHere) {
                        frameBodies1.add(frameBody);
                    }
                } else {
                    List<FrameBody> frameBodyList = new ArrayList<>();
                    frameBodyList.add(frameBody);
                    map.put(id, frameBodyList);
                }
            }
        }
        return map;
    }

    private Matrix getBoxMatrix(Matrix matrix, Map<Integer, Box> boxMap) throws Exception {
        Matrix positionMatrix = null;
        double endDist = -1;
        for (Map.Entry<Integer, Box> entry : boxMap.entrySet()) {
            Box box = entry.getValue();
            Matrix boxMatrix = box.getMatrix();
            double dist = MatrixOperation.getEDist(matrix, boxMatrix);
            if (endDist == -1 || dist < endDist) {
                endDist = dist;
                positionMatrix = box.getMatrixPosition();
            }
        }
        return positionMatrix;
    }

    //获得预测边框
    private void getBox(FrameBody frameBody, int width, int height) throws Exception {
        if (templeConfig.isBoxReady()) {
            Matrix matrix = frameBody.getEndMatrix();
            int id = frameBody.getId();
            int x = frameBody.getX();
            int y = frameBody.getY();
            KClustering kClustering = templeConfig.getKClusteringMap().get(id);
            Map<Integer, Box> boxMap = kClustering.getPositionMap();
            //将矩阵化为向量
            matrix = MatrixOperation.matrixToVector(matrix, true);
            Matrix positionMatrix = getBoxMatrix(matrix, boxMap);
            //锚点坐标及长宽预测值
            double tx = positionMatrix.getNumber(0, 0);
            double ty = positionMatrix.getNumber(0, 1);
            double th = positionMatrix.getNumber(0, 3);
            double tw = positionMatrix.getNumber(0, 2);
            //修正相对位置
            double realX = ArithUtil.add(ArithUtil.mul(tx, height), x);
            double realY = ArithUtil.add(ArithUtil.mul(ty, width), y);
            double realWidth = ArithUtil.mul(Math.exp(tw), width);
            double realHeight = ArithUtil.mul(Math.exp(th), height);
            frameBody.setRealX(realX);
            frameBody.setRealY(realY);
            frameBody.setRealWidth(realWidth);
            frameBody.setRealHeight(realHeight);
        } else {
            throw new Exception("box is not study");
        }
    }

    //计算两个边框的IOU
    private double getIou(FrameBody frameBody1, FrameBody frameBody2) {
        double iou = 1;
        double s1 = ArithUtil.mul(frameBody1.getRealHeight(), frameBody1.getRealWidth());
        double s2 = ArithUtil.mul(frameBody2.getRealHeight(), frameBody2.getRealWidth());
        double s = ArithUtil.add(s1, s2);
        double minX1 = frameBody1.getRealX();
        double minY1 = frameBody1.getRealY();
        double maxX1 = ArithUtil.add(minX1, frameBody1.getRealHeight());
        double maxY1 = ArithUtil.add(minY1, frameBody1.getRealWidth());
        double minX2 = frameBody2.getRealX();
        double minY2 = frameBody2.getRealY();
        double maxX2 = ArithUtil.add(minX2, frameBody2.getRealHeight());
        double maxY2 = ArithUtil.add(minY2, frameBody2.getRealWidth());
        double maxMinX, minMaxX, maxMinY, minMaxY;
        if (maxX2 > maxX1) {
            maxMinX = maxX1;
        } else {
            maxMinX = maxX2;
        }
        if (minX2 > minX1) {
            minMaxX = minX2;
        } else {
            minMaxX = minX1;
        }
        if (maxY2 > maxY1) {
            maxMinY = maxY1;
        } else {
            maxMinY = maxY2;
        }
        if (minY2 > minY1) {
            minMaxY = minY2;
        } else {
            minMaxY = minY1;
        }
        double intersectX = ArithUtil.sub(maxMinX, minMaxX);//相交X
        double intersectY = ArithUtil.sub(maxMinY, minMaxY);//相交Y
        if (intersectX < 0) {
            intersectX = 0;
        }
        if (intersectY < 0) {
            intersectY = 0;
        }
        double intersectS = ArithUtil.mul(intersectX, intersectY);//相交面积
        double mergeS = ArithUtil.sub(s, intersectS);//相并面积
        iou = ArithUtil.div(intersectS, mergeS);
        return iou;
    }

    public double toSeeById(Matrix matrix, int id) throws Exception {//返回某一个分类的概率
        intoConvolutionNetwork(2, matrix, templeConfig.getConvolutionNerveManager().getSensoryNerves(),
                false, 0, matrixBack);
        List<Double> list = getFeature(matrixBack.getMatrix());
        MaxPoint maxPoint = new MaxPoint();
        maxPoint.setPid(id);
        long t = IdCreator.get().nextId();
        intoDnnNetwork(t, list, templeConfig.getSensoryNerves(), false, null, maxPoint);
        return maxPoint.getpPoint();
    }

    //图像视觉 Accuracy 模式
    public int toSee(Matrix matrix) throws Exception {
        if (templeConfig.getStudyPattern() == StudyPattern.Accuracy_Pattern) {
            intoConvolutionNetwork(2, matrix, templeConfig.getConvolutionNerveManager().getSensoryNerves(),
                    false, 0, matrixBack);
            Matrix myMatrix = matrixBack.getMatrix();
            int classifier = templeConfig.getClassifier();
            int id = -1;
            switch (classifier) {
                case Classifier.LVQ:
                    id = getClassificationIdByLVQ(myMatrix);
                    break;
                case Classifier.DNN:
                    id = getClassificationIdByDnn(myMatrix);
                    break;
                case Classifier.VAvg:
                    id = getClassificationIdByVag(myMatrix);
                    break;
            }
            return id;
        } else {
            throw new Exception("pattern is wrong");
        }
    }

    private int getClassificationIdByDnn(Matrix myMatrix) throws Exception {
        List<Double> list = getFeature(myMatrix);
        MaxPoint maxPoint = new MaxPoint();
        maxPoint.setTh(templeConfig.getTh());
        long id = IdCreator.get().nextId();
        intoDnnNetwork(id, list, templeConfig.getSensoryNerves(), false, null, maxPoint);
        return maxPoint.getId();
    }

    private int getClassificationIdByVag(Matrix myMatrix) throws Exception {//VAG获取分类
        Matrix myVector = MatrixOperation.matrixToVector(myMatrix, true);
        Map<Integer, Matrix> matrixK = templeConfig.getVectorK().getMatrixK();
        double minDist = 0;
        int id = 0;
        for (Map.Entry<Integer, Matrix> entry : matrixK.entrySet()) {
            Matrix matrix = entry.getValue();
            double dist = MatrixOperation.getEDist(matrix, myVector);
            //System.out.println("距离===" + dist + ",类别==" + entry.getKey());
            if (minDist == 0 || dist < minDist) {
                minDist = dist;
                id = entry.getKey();
            }
        }
        return id;
    }

    private int getClassificationIdByLVQ(Matrix myMatrix) throws Exception {//LVQ获取分类
        Matrix myVector = MatrixOperation.matrixToVector(myMatrix, true);
        int id = 0;
        double distEnd = 0;
        LVQ lvq = templeConfig.getLvq();
        MatrixBody[] matrixBodies = lvq.getModel();
        for (int i = 0; i < matrixBodies.length; i++) {
            MatrixBody matrixBody = matrixBodies[i];
            Matrix vector = matrixBody.getMatrix();
            double dist = lvq.vectorEqual(myVector, vector);
            if (distEnd == 0 || dist < distEnd) {
                id = matrixBody.getId();
                distEnd = dist;
            }
        }
        return id;
    }

    public double isCover(ThreeChannelMatrix threeChannelMatrix) throws Exception {//固定背景覆盖率计算
        ThreeChannelMatrix backGround = templeConfig.getBackGround();
        double errorBack = templeConfig.getBackGroundError();
        if (backGround != null && errorBack >= 0 && errorBack <= 255) {
            Matrix matrixR = threeChannelMatrix.getMatrixR();
            Matrix matrixG = threeChannelMatrix.getMatrixG();
            Matrix matrixB = threeChannelMatrix.getMatrixB();
            Matrix matrixRBg = backGround.getMatrixR();
            Matrix matrixGBg = backGround.getMatrixG();
            Matrix matrixBBg = backGround.getMatrixB();
            int x = matrixR.getX();
            int y = matrixR.getY();
            double size = x * y;
            double cover = 0;
            if (x == matrixRBg.getX() && y == matrixRBg.getY()) {
                for (int i = 0; i < x; i++) {
                    for (int j = 0; j < y; j++) {
                        double rB = matrixRBg.getNumber(i, j);
                        double gB = matrixGBg.getNumber(i, j);
                        double bB = matrixBBg.getNumber(i, j);
                        double r = matrixR.getNumber(i, j);
                        double g = matrixG.getNumber(i, j);
                        double b = matrixB.getNumber(i, j);
                        double subR = Math.abs(r - rB);
                        double subG = Math.abs(g - gB);
                        double subB = Math.abs(b - bB);
                        double error = (subR + subB + subG) / 3;
                        if (error > errorBack) {
                            cover++;
                        }
                    }
                }
                return cover / size;
            } else {
                throw new Exception("Temple matrix is different");
            }
        } else {
            throw new Exception("value is null");
        }
    }

    private List<Double> sub(Matrix matrix) throws Exception {//
        List<Double> list = new ArrayList<>();
        int x = matrix.getX() - 1;
        int y = matrix.getY() - 1;
        for (int i = 0; i < templeConfig.getRow(); i++) {
            for (int j = 0; j < templeConfig.getColumn(); j++) {
                if (i > x || j > y) {
                    list.add(0.0);
                } else {
                    list.add(matrix.getNumber(i, j));
                }
            }
        }
        return list;
    }

    /**
     * @param eventId          事件ID
     * @param featureList      特征集合
     * @param sensoryNerveList 感知神经元集合
     * @param isStudy          是否学习
     * @param map              标注
     * @param outBack          输出结果回调类
     */

    private void intoDnnNetwork(long eventId, List<Double> featureList, List<SensoryNerve> sensoryNerveList
            , boolean isStudy, Map<Integer, Double> map, OutBack outBack) throws Exception {//进入DNN 神经网络
        for (int i = 0; i < sensoryNerveList.size(); i++) {
            sensoryNerveList.get(i).postMessage(eventId, featureList.get(i), isStudy, map
                    , outBack);
        }
    }

    /**
     * @param eventId          事件ID
     * @param feature          特征矩阵
     * @param sensoryNerveList 感知神经元集合
     * @param isKernelStudy    是否进行核学习
     * @param E                期望矩阵
     * @param outBack          输出结果回调类
     */
    private void intoConvolutionNetwork(long eventId, Matrix feature, List<SensoryNerve> sensoryNerveList
            , boolean isKernelStudy, int E, OutBack outBack) throws Exception {//进入卷积神经网络
        for (int i = 0; i < sensoryNerveList.size(); i++) {
            sensoryNerveList.get(i).postMatrixMessage(eventId, feature, isKernelStudy, E, outBack);
        }
    }
}