/** 通过SVD定理,计算矩阵的特征向量 传入形参为 <方法:计算协方差矩阵> 的返回值 */
  public static double[][] calFeatureVector(double[][] vec) {
    Matrix vecMat = new Matrix(vec);
    SingularValueDecomposition s = vecMat.svd();

    double[][] featureVector = s.getV().getArray();
    Features.getInstance().setFeatureVector(featureVector);
    return featureVector;
  }
  /**
   * 将X'T*X'的特征向量 转换成 X'*X'T的特征向量 的方法
   *
   * @param eigenValue为特征值
   * @param featureVec为特征向量
   */
  public static double[][] changeFeatureVector() {
    double[][] AveDeviation = Features.getInstance().getAveDev(); // 每幅图的均差
    double[] eigenValue = Features.getInstance().getEigenValue(); // 特征值
    double[][] featureVec = Features.getInstance().getFeatureVector(); // 特征向量

    //		System.out.println("width*height:" + width*height);//4096
    //		System.out.println("featureVec[0].length" + featureVec[0].length);//10
    double[][] resultFeatureVector = new double[width * height][featureVec[0].length];

    for (int i = 0; i < featureVec[0].length; i++) {
      // 将N副图片的特征向量[N][N]分离提取出来,提取第i张图片的特征向量[N][1]
      double[][] temp = new double[featureVec.length][1];
      for (int j = 0; j < featureVec.length; j++) {
        temp[j][0] = featureVec[j][i];
      }

      Matrix xOld = new Matrix(AveDeviation);
      Matrix featureVecOfOneObject = new Matrix(temp);
      //			System.out.println("[" + xOld.getRowDimension() + "]" +
      //					"[" + xOld.getColumnDimension() +"]");//[16384][10]
      //			System.out.println("[" + featureVecOfOneObject.getRowDimension() + "]" +
      //					"[" + featureVecOfOneObject.getColumnDimension() +"]");//[10][1]

      Matrix resultMatrix = xOld.times(featureVecOfOneObject);
      //			System.out.println("[" + resultMatrix.getRowDimension() + "]" +
      //					"[" + resultMatrix.getColumnDimension() +"]");

      double factor = 1 / (Math.sqrt(eigenValue[i]));
      resultMatrix.times(factor);

      double[][] temp2 = new double[1][1];
      temp2 = resultMatrix.getArray();

      //			System.out.println("temp2.length:" + temp2.length);//16384-------------
      //			System.out.println("temp2[0].length:" + temp2[0].length);//1
      // 将构成的[N][1] 复制到[N][i]中
      for (int j = 0; j < temp2.length; j++) {
        resultFeatureVector[j][i] = temp2[j][0];
      }
    }

    Features.getInstance().setResultFeatureVector(resultFeatureVector);
    return resultFeatureVector;
  }
  /** 通过SVD定理,计算矩阵的特征值 传入形参为 <方法:计算协方差矩阵> 的返回值 */
  public static double[] calEigenValue(double[][] vec) {
    // double[] eigenValue;
    Matrix vecMat = new Matrix(vec);
    SingularValueDecomposition s = vecMat.svd();
    Matrix svalues = new Matrix(s.getSingularValues(), 1);

    double[] result = svalues.getRowPackedCopy();
    Features.getInstance().setEigenValue(result);
    return result;
  }
  /** 计算一张图片的均差,仅针对一个人的图像做计算 形参vec中存放的数据为1副人脸图像(一维) */
  public static double[] calAveDeviationOneObject(double[] vec) {
    double[] newVec = new double[vec.length];
    double[] vAve = Features.getInstance().getAveVector(); // 获取平均人脸图像

    // 计算这张图片的均差
    for (int i = 0; i < vec.length; i++) {
      newVec[i] = vec[i] - vAve[i];
    }

    return newVec;
  }
  /** 计算每张图片的均差 形参vec中存放的数据为N副人脸图像(一维)组成的二维向量 形参vAve为平均人脸图像的向量 */
  public static double[][] calAveDeviation(double[][] vec, double[] vAve) {
    int length = vec.length; // length指向量的维数,X={1,2,3,...,length}
    int n = vec[0].length; // n指向量的个数,X1,X2,X3...Xn;
    double[][] newVec = new double[length][n];

    // 计算每张图片的均差
    for (int i = 0; i < length; i++) {
      for (int j = 0; j < n; j++) {
        newVec[i][j] = vec[i][j] - vAve[i];
      }
    }

    Features.getInstance().setAveDev(newVec);

    return newVec; // newVec为每幅图像的均差,同时也可以表示成一个矩阵。维数为:n*length;
  }
  /** 计算平均人脸图像 形参vec中存放的数据为N副人脸图像(一维)合成的二维数据 */
  public static double[] calAveVector(double[][] vec) {
    int length = vec.length; // length指向量的维数,X={1,2,3,...,length}
    int n = vec[0].length; // n指向量的个数,X1,X2,X3...Xn;
    double[] vAve = new double[length]; // 初始化平均向量(的维数)

    // 构建平均向量的值
    for (int i = 0; i < length; i++) {
      double temp = 0;
      for (int j = 0; j < n; j++) {
        temp += vec[i][j];
      }
      temp = temp / n;
      vAve[i] = temp;
    }
    Features.getInstance().setAveVector(vAve);
    return vAve;
  }
  /**
   * 输出特征脸 根据特征向量得出Image类型
   *
   * @param args
   */
  public static Image[] getFeatureFaces() {
    double[][] rfVec = Features.getInstance().getResultFeatureVector();
    Matrix mat = new Matrix(rfVec);
    mat = mat.transpose();
    rfVec = mat.getArray();

    Image[] img = new Image[rfVec.length];
    for (int i = 0; i < rfVec.length; i++) {
      System.out.println("i:" + i);
      // 这一步可能会有压缩损失
      // 最好找一个方法,直接从double[]转换成Image

      // 将double[]转换成int[]
      int[][] rfVecInt = new int[rfVec.length][rfVec[0].length];
      //			System.out.println("[" + rfVec.length + "]" + "[" + rfVec[0].length + "]");
      for (int j = 0; j < rfVec[0].length; j++) {

        //				rfVecInt[i][j] = (int)rfVec[i][j];//无四舍五入
        rfVecInt[i][j] =
            Integer.parseInt(new java.text.DecimalFormat("0").format(rfVec[i][j])); // 四舍五入
        //				System.out.print(rfVecInt[i][j] + " ");

        // ----------------整个if语句是测试语句,要删除
        //				if(i==9)
        //				{
        //					System.out.println("Yes!");
        //					rfVecInt[i][j] = Integer.parseInt(new
        // java.text.DecimalFormat("0").format(rfVec[i][j]));//四舍五入
        //				}
        // ----------------以上为测试语句
      }
      System.out.println("i:" + i);
      img[i] = getImgByPixels(width, height, rfVecInt[i]);
      //			System.out.println();
      //			img[i] = getImgByPixels(128, 128, rfVecInt[i]);
    }
    //		System.out.println("img length:" + img.length);

    return img;
  }
  /** 计算协方差矩阵 传入形参为 <方法:计算每张图片的均差> 的返回值 (其实这并不是协方差矩阵,若需要协方差矩阵,再用该矩阵除以N即可) */
  public static double[][] calCovarianceMatrix(double[][] vec) {
    int length = vec.length; // length指向量的维数,X={1,2,3,...,length}
    int n = vec[0].length; // n指向量的个数,X1,X2,X3...Xn;

    Matrix vecOld = new Matrix(vec);

    //		System.out.println("vecOld:");
    //		vecOld.print(6, 2);

    //		System.out.println();
    Matrix vecTrans = vecOld.transpose(); // 获取转置矩阵
    //		System.out.println("vecTrans:");
    //		vecTrans.print(6, 2);

    double[][] covArr = new double[nOld][nOld]; // 初始化协方差矩阵

    // 构造协方差矩阵
    //		Matrix cov = vecOld.times(vecTrans);
    Matrix cov = vecTrans.times(vecOld);

    covArr = cov.getArray();

    // 由于最终计算并不需要协方差矩阵,仅仅要的是一部分,所以不用除以N
    // 除以N
    //		for(int i=0; i<n; i++)
    //		{
    //			for(int j=0; j<length; j++)
    //			{
    //				covArr[i][j] = covArr[i][j] / n;
    //			}
    //		}

    Features.getInstance().setCovarianceMatrix(covArr);

    return covArr;
  }
  public static void main(String[] args) {
    // 创建图片数组
    ImageIcon[] icon = new ImageIcon[10];
    String source = "Pictures/monkey-test/after";
    for (int i = 0; i < 6; i++) {
      String target = "-" + (i + 1) + ".jpg";
      icon[i] = new ImageIcon(source + target);
    }
    icon[6] = new ImageIcon(source + "1.jpg");
    for (int i = 7; i < 10; i++) {
      String target = (i - 4) + ".jpg";
      icon[i] = new ImageIcon(source + target);
    }

    // 计算图片数组的特征值和特征向量
    // 将结果保存在Features类中
    imageToResult(icon);

    // 测试---------------------------
    // 将特征向量转换成图片
    getFeatureFaces();

    // 从单例中获取数据
    double[] eigenValue = Features.getInstance().getEigenValue();
    double[][] featureVector = Features.getInstance().getFeatureVector();

    System.out.println("特征值的个数:" + eigenValue.length);

    System.out.println(
        "特征向量的维数:"
            + "["
            + Features.getInstance().getResultFeatureVector().length
            + "]"
            + "["
            + Features.getInstance().getResultFeatureVector()[0].length
            + "]");
    //		System.out.println("特征向量的维数:" +
    //				"[" + featureVector.length +"]" + "[" + featureVector[0].length+ "]");

    // 输出测试
    System.out.println("特征值:");
    for (int i = 0; i < eigenValue.length; i++) {
      System.out.print(eigenValue[i] + " ");
    }
    System.out.println();
    System.out.println("---------分割线------------");

    //		System.out.println("特征向量:");
    //		double[][] result = Features.getInstance().getResultFeatureVector();
    //		for(int i=0; i<result.length; i++)
    //		{
    //			for(int j=0; j<result[i].length; j++)
    //			{
    //				System.out.print(result[i][j] + " ");
    //			}
    //			System.out.println();
    //		}

    //		System.out.println("特征向量:");
    //		for(int i=0; i<featureVector.length; i++)
    //		{
    //			for(int j=0; j<featureVector[i].length; j++)
    //			{
    //				System.out.print(featureVector[i][j] + " ");
    //			}
    //			System.out.println();
    //		}

    //		//可以将这里封装成一个方法
    //		//形参为图片数组,返回值为double[][]
    //		ImageIcon icon = new ImageIcon("Pictures/monkey-test/after-1.jpg");
    //		icon = ImageHandle(icon, width, height);
    //		Image img = icon.getImage();
    //		BufferedImage bimg = ImageUtil.ImageToBufferedImage(img);
    //		int[] imgVec = getPixes(bimg);
    //		double[] imgVecD = intToDouble(imgVec);
    //
    ////		System.out.println("length:" + imgVec.length);
    //
    //		//先用一张图片测试,这里实际应该为N张图片
    //		double[][] imgVecD2 = new double[imgVecD.length][1];
    //		for(int i=0; i<imgVecD.length; i++)
    //		{
    //			imgVecD2[i][0] = imgVecD[i];//构造列向量
    //		}
    ////		imgVecD2[0] = imgVecD;
    //
    //		//计算平均人脸图像
    //		double[] aveVec = calAveVector(imgVecD2);
    //
    //		//计算每张图片的均差
    //		double[][] aveDev = calAveDeviation(imgVecD2, aveVec);
    //
    //		//计算协方差矩阵
    //		double[][] covMat = calCovarianceMatrix(aveDev);
    //
    //		//通过SVD定理,计算矩阵的特征值
    //		double[] eigenValue = calEigenValue(covMat);
    //
    //		//通过SVD定理,计算矩阵的特征向量
    //		double[][] featureVector = calFeatureVector(covMat);
    //
    //		//输出测试
    //		System.out.println("特征值:");
    //		for(int i=0; i<eigenValue.length; i++) {
    //			System.out.print(eigenValue[i] + " ");
    //		}
    //		System.out.println();
    //		System.out.println("---------分割线------------");
    //
    //		System.out.println("特征向量:");
    //		for(int i=0; i<featureVector.length; i++)
    //		{
    //			for(int j=0; j<featureVector[i].length; j++)
    //			{
    //				System.out.print(featureVector[i][j] + " ");
    //			}
    //			System.out.println();
    //		}
    //
    // ---------------------真.分割线---------------------------------

    //		 double [][] array = { {4,6,0,3},{-3,-5,0,3},{-3,-6,1,3}};
    //		 System.out.println(array.length);
    //		 System.out.println(array[0].length);
    //
    //
    //		 Matrix a = new Matrix(array);
    //		 double[][] ar = {{3,-2,1},{0,0,0}};
    //		 double[][] ar2 = {{1,0,-1},{0,0,0}};
    //
    //		 Matrix a = new Matrix(ar);
    //		 Matrix a2 = new Matrix(ar2);
    //		 a2 = a2.transpose();
    //
    //		 Matrix a3 = a.times(a2);
    //		 a3.print(4, 1);

    //		 double[][] ar = a.getArray();
    //		 double[][] ar = a.transpose().getArray();
    //		 System.out.println(ar[0][0] + " " +ar[0][1]+" " +ar[0][2]);
    //		 System.out.println(ar[1][0] + " " +ar[1][1]+" " +ar[1][2]);
    //		 System.out.println(ar[2][0] + " " +ar[2][1]+" " +ar[2][2]);
    //		 System.out.println(ar[3][0] + " " +ar[3][1]+" " +ar[3][2]);

    //		 System.out.println(ar[0][0] + " " +ar[0][1]+" " +ar[0][2]+" " +ar[0][3]);
    //		 System.out.println(ar[1][0] + " " +ar[1][1]+" " +ar[1][2]+" " +ar[1][3]);
    //		 System.out.println(ar[2][0] + " " +ar[2][1]+" " +ar[2][2]+" " +ar[2][3]);
    //		 double[] ar = array[0];
    //		 System.out.println(ar[0] + " " +ar[1]+" " +ar[2]+" " +ar[3]);
    //		 double[] arr = {4,2,0,8};
    //		 double[][] ar = new double[3][4];
    //		 ar[0] = arr;
    //		 System.out.println(ar[0][0] + " " +ar[0][1]+" " +ar[0][2]+" " +ar[0][3]);

    // create M-by-N matrix that doesn't have full rank
    //	      int M = 8, N = 5;
    //	      Matrix B = Matrix.random(5, 3);
    //	      Matrix A = Matrix.random(M, N).times(B).times(B.transpose());
    //	      System.out.print("A = ");
    //	      A.print(9, 6);
    //
    //	      // compute the singular vallue decomposition
    //	      System.out.println("A = U S V^T");
    //	      System.out.println();
    //	      SingularValueDecomposition s = A.svd();
    //	      System.out.print("U = ");
    //	      Matrix U = s.getU();
    //	      U.print(9, 6);
    //	      System.out.print("Sigma = ");
    //	      Matrix S = s.getS();
    //	      S.print(9, 6);
    //	      System.out.print("V = ");
    //	      Matrix V = s.getV(); //特征向量
    //	      V.print(9, 6);
    //	      System.out.println("rank = " + s.rank());
    //	      System.out.println("condition number = " + s.cond());
    //	      System.out.println("2-norm = " + s.norm2());
    //
    //	      // print out singular values
    //	      System.out.print("singular values = ");
    //	      Matrix svalues = new Matrix(s.getSingularValues(), 1); //特征值
    //	      svalues.print(9, 6);
  }