From a264e638a00bbb38bd744b229dabaa23b08fce35 Mon Sep 17 00:00:00 2001 From: WookCheolShin Date: Tue, 17 Dec 2019 22:18:28 +0900 Subject: [PATCH] Initial Commit --- Run_FeatureMatching.m | 31 ++ Run_MetricsEvaluation.m | 85 ++++ Run_NMbasedControl.m | 31 ++ Utils_Control/FindClosestPoint.m | 86 ++++ Utils_Control/Metric_our.m | 91 ++++ Utils_Control/Test_nelder_mead_AE.m | 142 +++++++ Utils_Control/nelder_mead_AE.m | 394 ++++++++++++++++++ .../main_feature_matching_analysis.m | 258 ++++++++++++ .../subfunctions/KeyPointNMS.m | 40 ++ .../subfunctions/SymmetricEpipolarDistance.m | 29 ++ .../subfunctions/ValidCameraPosition.m | 73 ++++ .../subfunctions/calculateReprojectionError.m | 46 ++ .../subfunctions/calibrated_fivepoint.m | 100 +++++ .../calibrated_fivepoint_helper.c | 380 +++++++++++++++++ .../calibrated_fivepoint_helper.mexa64 | Bin 0 -> 147728 bytes Utils_Metric/Eval_Metric.m | 224 ++++++++++ Utils_Metric/Extract_Result.m | 144 +++++++ Utils_Metric/Metric_Our.m | 183 ++++++++ Utils_Metric/Test_HyperParam.m | 105 +++++ 19 files changed, 2442 insertions(+) create mode 100644 Run_FeatureMatching.m create mode 100644 Run_MetricsEvaluation.m create mode 100644 Run_NMbasedControl.m create mode 100644 Utils_Control/FindClosestPoint.m create mode 100644 Utils_Control/Metric_our.m create mode 100644 Utils_Control/Test_nelder_mead_AE.m create mode 100644 Utils_Control/nelder_mead_AE.m create mode 100644 Utils_FeatureMatching/main_feature_matching_analysis.m create mode 100644 Utils_FeatureMatching/subfunctions/KeyPointNMS.m create mode 100644 Utils_FeatureMatching/subfunctions/SymmetricEpipolarDistance.m create mode 100644 Utils_FeatureMatching/subfunctions/ValidCameraPosition.m create mode 100644 Utils_FeatureMatching/subfunctions/calculateReprojectionError.m create mode 100644 Utils_FeatureMatching/subfunctions/calibrated_fivepoint.m create mode 100644 Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.c create mode 100644 Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.mexa64 create mode 100644 Utils_Metric/Eval_Metric.m create mode 100644 Utils_Metric/Extract_Result.m create mode 100644 Utils_Metric/Metric_Our.m create mode 100644 Utils_Metric/Test_HyperParam.m diff --git a/Run_FeatureMatching.m b/Run_FeatureMatching.m new file mode 100644 index 0000000..08ac70b --- /dev/null +++ b/Run_FeatureMatching.m @@ -0,0 +1,31 @@ +% Type your dataset path +Path_to_result = './Results\Result_img'; + +addpath('./Utils_FeatureMatching'); + +% Run feature extraction & matching +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_class_room1_340Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_class_room2_401Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_class_room3_320Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_class_room4_263Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_common_room1_177Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_common_room2_95Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_lounage1_200Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_meeting_room1_198Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_meeting_room3_213Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\indoor_meeting_room2_191Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_bench1_6420Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_bench2_5530Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_bicycle1_14230Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_bicycle2_2680Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car1_15310Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car2_5530Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car3_4080Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car4_5520Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car5_5290Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car6_4539Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_car7_8490Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_scene1_7380Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_scene2_7710Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_weed1_3350Lux')); +main_feature_matching_analysis(strcat(Path_to_result,'\outdoor_weed2_3010Lux')); \ No newline at end of file diff --git a/Run_MetricsEvaluation.m b/Run_MetricsEvaluation.m new file mode 100644 index 0000000..f8eec29 --- /dev/null +++ b/Run_MetricsEvaluation.m @@ -0,0 +1,85 @@ +% Type your dataset path +Path_to_datset = './DataSet_AE'; + +addpath('./Utils_metric'); + +% Run Metric Evaluator +Eval_Metric(strcat(Path_to_datset,'\indoor_class_room1_340Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_class_room2_401Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_class_room3_320Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_class_room4_263Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_common_room1_177Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_common_room2_95Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_lounage1_200Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_meeting_room1_198Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_meeting_room3_213Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\indoor_meeting_room2_191Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_bench1_6420Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_bench2_5530Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_bicycle1_14230Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_bicycle2_2680Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car1_15310Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car2_5530Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car3_4080Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car4_5520Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car5_5290Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car6_4539Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_car7_8490Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_scene1_7380Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_scene2_7710Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_weed1_3350Lux\left')); +Eval_Metric(strcat(Path_to_datset,'\outdoor_weed2_3010Lux\left')); + +% Run hyper paramter tester +% Test_HyperParam(strcat(Path_to_datset,'\indoor_class_room1_340Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_class_room2_401Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_class_room3_320Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_class_room4_263Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_common_room1_177Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_common_room2_95Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_lounage1_200Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_meeting_room1_198Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_meeting_room3_213Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\indoor_meeting_room2_191Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_bench1_6420Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_bench2_5530Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_bicycle1_14230Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_bicycle2_2680Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car1_15310Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car2_5530Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car3_4080Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car4_5520Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car5_5290Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car6_4539Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_car7_8490Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_scene1_7380Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_scene2_7710Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_weed1_3350Lux\left')); +% Test_HyperParam(strcat(Path_to_datset,'\outdoor_weed2_3010Lux\left')); + +% Extract result img +Extract_Result(strcat(Path_to_datset,'\indoor_class_room1_340Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_class_room2_401Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_class_room3_320Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_class_room4_263Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_common_room1_177Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_common_room2_95Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_lounage1_200Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_meeting_room1_198Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_meeting_room3_213Lux\left')); +Extract_Result(strcat(Path_to_datset,'\indoor_meeting_room2_191Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_bench1_6420Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_bench2_5530Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_bicycle1_14230Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_bicycle2_2680Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car1_15310Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car2_5530Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car3_4080Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car4_5520Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car5_5290Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car6_4539Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_car7_8490Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_scene1_7380Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_scene2_7710Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_weed1_3350Lux\left')); +Extract_Result(strcat(Path_to_datset,'\outdoor_weed2_3010Lux\left')); diff --git a/Run_NMbasedControl.m b/Run_NMbasedControl.m new file mode 100644 index 0000000..5040bdf --- /dev/null +++ b/Run_NMbasedControl.m @@ -0,0 +1,31 @@ +% Type your dataset path +Path_to_result = './Results\Result_Exp'; + +addpath('./Utils_control'); + +% Run Test +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_class_room1_340Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_class_room2_401Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_class_room3_320Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_class_room4_263Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_common_room1_177Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_common_room2_95Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_lounage1_200Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_meeting_room1_198Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_meeting_room3_213Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\indoor_meeting_room2_191Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_bench1_6420Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_bench2_5530Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_bicycle1_14230Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_bicycle2_2680Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car1_15310Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car2_5530Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car3_4080Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car4_5520Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car5_5290Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car6_4539Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_car7_8490Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_scene1_7380Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_scene2_7710Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_weed1_3350Lux\workspace_upsampled_result.mat')); +Test_nelder_mead_AE(strcat(Path_to_result,'\outdoor_weed2_3010Lux\workspace_upsampled_result.mat')); diff --git a/Utils_Control/FindClosestPoint.m b/Utils_Control/FindClosestPoint.m new file mode 100644 index 0000000..0de2684 --- /dev/null +++ b/Utils_Control/FindClosestPoint.m @@ -0,0 +1,86 @@ +function x_ = FindClosestPoint(x, Flag_dataset) +%% Camera Exposure Control for Robust Robot Vision with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Name : +% FindClosestPoint.m +% +% Returns the nearest point to the input point based on the interval previously used to upsample the dataset. +% +% Modified: +% +% 04 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Parameters: +% +% Input : x - Input point +% : Flag_dataset - flag to select the setttings for each dataset +% +% output : x_ - The point closest to the input point present in the upsampled data set +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + if ( nargin == 1 ) + Flag_dataset = 1; + end + + if(Flag_dataset == 0) % Outdoor dataset + Interval_gain = 2; + Interval_expt = 150; + Limit_gain = 20; + Lower_limit_expt = 100; + Upper_limit_expt = 7450; + elseif(Flag_dataset == 1) % Indoor dataset + Interval_gain = 1; + Interval_expt = 3000; + Limit_gain = 24; + Lower_limit_expt = 4000; + Upper_limit_expt = 67000; + end + + Gain = x(1,1); + Expt = x(1,2); + + if(mod(Gain,Interval_gain) >= Interval_gain/2) + Gain = Gain - mod(Gain,Interval_gain) + Interval_gain; + elseif(mod(Gain,Interval_gain) < Interval_gain/2) + Gain = Gain - mod(Gain,Interval_gain); + end + + if(mod(Expt,Interval_expt) >= Interval_expt/2) + Expt = Expt - mod(Expt,Interval_expt) + Interval_expt + Lower_limit_expt; + elseif(mod(Expt,Interval_expt) < Interval_expt/2) + Expt = Expt - mod(Expt,Interval_expt) + Lower_limit_expt; + end + + if(Gain > Limit_gain) + Gain = Limit_gain; + elseif(Gain < 0) + Gain = 0; + end + + if(Expt > Upper_limit_expt) + Expt = Upper_limit_expt; + elseif(Expt < Lower_limit_expt) + Expt = Lower_limit_expt; + end + + x_ = zeros(1,2); + x_(1,1) = Gain; + x_(1,2) = Expt; +end diff --git a/Utils_Control/Metric_our.m b/Utils_Control/Metric_our.m new file mode 100644 index 0000000..8fe12be --- /dev/null +++ b/Utils_Control/Metric_our.m @@ -0,0 +1,91 @@ +function f = Metric_our ( x , Path_UpsampledData) +%% Camera Exposure Control for Robust Robot Vision with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Name : +% Metric_our +% +% Returns a value based on the proposed image evaluation method for the input point, +% which value is returned based on the " _upsample.mat" generated by +% the previous "Metric_Evaluaotr.m" and "Data_Interpolation.m" . +% +% Modified: +% +% 04 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Parameters: +% +% Input : x - input point, the dimension of x is 2x1, +% we assume x(1) component is "gain", x(2) component is "exposure time". +% output : f_x - Evaluated value based on our metric +% with given input parameter (gain, exposure time) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + if ( length ( x ) ~= 2 ) + error ( 'Error: function expects a two dimensional input\n' ); + end + + % load upsampled dataset. + % In this code, we use pre-calculated datapoint and evaluated value of each dataset. + persistent Xq Yq Zq Interval_Up_Gain Interval_Up_ExpT result_txt; + if ( nargin == 2 ) + load(Path_UpsampledData,'Xq','Yq','Zq', 'interval_ExpT','interval_dB'); + Interval_Up_Gain = interval_dB; + Interval_Up_ExpT = interval_ExpT; + result_txt = strcat(Path_UpsampledData(1:regexp(Path_UpsampledData,'workspace')-1), 'Traj_ExpTGain.txt'); + fileID = fopen(result_txt,'w'); + fclose(fileID); + else + fileID = fopen(result_txt,'a'); + fprintf(fileID , '%4.5f %4.5f\n' , x(1) , x(2)); + fclose(fileID); + end + + Gain = x(1); + Expt = x(2); + + if(mod(Gain, Interval_Up_Gain) >= Interval_Up_Gain/2) + Approxi_Gain = Gain - mod(Gain, Interval_Up_Gain) + Interval_Up_Gain; + elseif(mod(Gain, Interval_Up_Gain) < Interval_Up_Gain/2) + Approxi_Gain = Gain - mod(Gain, Interval_Up_Gain); + end + + if(mod(Expt, Interval_Up_ExpT) >= Interval_Up_ExpT/2) + Approxi_Expt = Expt - mod(Expt, Interval_Up_ExpT) + Interval_Up_ExpT; + elseif(mod(Expt, Interval_Up_ExpT) < Interval_Up_ExpT/2) + Approxi_Expt = Expt - mod(Expt, Interval_Up_ExpT); + end + + Gain_index = find(abs(Xq(1,:) - Approxi_Gain) < 0.001); + ExpT_index = find(abs(Yq(:,1) - Approxi_Expt) < 0.001); + + f = -Zq(ExpT_index,Gain_index); + + % Exception handler for out of range or nonexistent values. + if(isnan(f)) + f = 10^10; % instead of using "inf", use some large number + elseif(isempty(f)) + f = 10^10; + end + + fprintf ( 1, ' %9.3f', Approxi_Gain ); + fprintf ( 1, ' %9.3f', Approxi_Expt ); + fprintf ( 1, ' %9.3e\n', f ); + + return +end diff --git a/Utils_Control/Test_nelder_mead_AE.m b/Utils_Control/Test_nelder_mead_AE.m new file mode 100644 index 0000000..0fac5e7 --- /dev/null +++ b/Utils_Control/Test_nelder_mead_AE.m @@ -0,0 +1,142 @@ +function Test_nelder_mead_AE (Path_UpsampledData) +%% Camera Exposure Control for Robust Robot Vision with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Name : +% Run_NelderMead_ExposureControl.m +% +% Modified: +% +% 17 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Reference: +% +% We refer and modify the matlab code written by Jeff Borggaard +% "https://people.sc.fsu.edu/~jburkardt/m_src/nelder_mead/nelder_mead.html". +% the paper reference is follows : +% +% John Nelder, Roger Mead, +% A simplex method for function minimization, +% Computer Journal, +% Volume 7, Number 4, January 1965, pages 308-313. +% +% Parameters: +% +% Input : Path_UpsampledData - Path of upsampled dataset file, +% this dataset is generated by +% "Extract_Result.m" file +% output : None +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + close all; + + fprintf ( 1, '\n' ); + fprintf ( 1, 'AE_NELDER_MEAD_TEST:\n' ); + + % Load saved result mat file + load(Path_UpsampledData, 'path_name', 'dataset_flag'); + + n = 2; + Alpha = 1.7; % Alpha decides the initial simplex size + flag_draw = true; + Flag_Dataset = dataset_flag; % Flag to select the setting for dataset type. + + %% 1. Construct initial simplex + % Generate random initial point + if(Flag_Dataset == 0) % Outdoor dataset + Init_Points = zeros(3,2); + Init_Points(1,1) = 2*(randi(11)-1); + Init_Points(1,2) = 150*(randi(50)-1) + 100; + elseif(Flag_Dataset == 1) % Indoor dataset + Init_Points = zeros(3,2); + Init_Points(1,1) = 1*(randi(25)-1); + Init_Points(1,2) = 3000*(randi(22)-1) + 4000; + end + + % Read initial image based on random generated point + Str_Init_Img = strcat('Param-ISO-',int2str(Init_Points(1,1)), '-ExpT-',int2str(Init_Points(1,2)), '.jpg'); + Path_Init_Img = strcat(path_name,'\',Str_Init_Img); + Initial_image = imread(Path_Init_Img); + + % Decide exporing points based on a intensity of current captured image. + Intensity = mean2(rgb2gray(Initial_image)); + + if(Intensity >= 128) + h = -1/Alpha*(Intensity/255); + elseif(Intensity < 128) + h = Alpha*(1 - Intensity/255); + end + + Init_Points(2,:) = FindClosestPoint(Init_Points(1,:).*(1 + h*[1,0]), Flag_Dataset); + Init_Points(3,:) = FindClosestPoint(Init_Points(1,:).*(1 + h*[0,1]), Flag_Dataset); + fprintf(1,'Initial Param : Gain : %d, ExpT : %d\n', Init_Points(1,1), Init_Points(1,2) ); + fprintf(1,'Second Param : Gain : %d, ExpT : %d\n', Init_Points(2,1), Init_Points(2,2) ); + fprintf(1,'Third Param : Gain : %d, ExpT : %d\n', Init_Points(3,1), Init_Points(3,2) ); + + %% 2. Run Nelder-Mead based Exposure Control Algorithm + + fprintf ( 1, '\n' ); + fprintf ( 1, ' Initial data:\n' ); + fprintf ( 1, '\n' ); + + for j = 1 : n + fprintf ( 1, ' ---X(%d)---', j ); + end + fprintf ( 1, ' ---F(X)---\n' ); + fprintf ( 1, '\n' ); + Metric_our( zeros(1,2) , Path_UpsampledData); % initialize + + [ xopt, n_feval ] = nelder_mead_AE ( Init_Points, @Metric_our, flag_draw , Path_UpsampledData); + + fprintf ( 1, '\n' ); + fprintf ( 1, ' Computed optimum after %d evaluations:\n', n_feval ); + fprintf ( 1, '\n' ); + for j = 1 : n + fprintf ( 1, ' ---X(%d)---', j ); + end + fprintf ( 1, ' ---F(X)---\n' ); + fprintf ( 1, '\n' ); + for j = 1 : n + fprintf ( 1, ' %10f', xopt(j) ); + end + fprintf ( 1, ' %10e\n', Metric_our ( xopt) ); + + %% 3. Display the Gain & ExpT trajectory + Result = importdata(strcat(Path_UpsampledData(1:regexp(Path_UpsampledData,'workspace')-1), 'Traj_ExpTGain.txt')); + + Result = Result(4:end,:); + t = 1:length(Result); + GainResult = Result(:,1); + ExpTResult = Result(:,2); + + figure; + plot(t,GainResult,'LineWidth',2.5); + set(gca,'FontName', 'Times New Roman','FontSize',17); + xlabel('Step','fontsize',20, 'fontweight','bold'); ylabel('Gain','fontsize',20, 'fontweight','bold'); grid on; %title('Gain-step graph'); + tt = [1,5,15,25,35,45]; hold on; + plot(tt,GainResult(tt),'r*'); + + figure; + plot(t,ExpTResult,'LineWidth',2.5); + set(gca,'FontName', 'Times New Roman','FontSize',17); + xlabel('Step','fontsize',20, 'fontweight','bold'); ylabel('ExpT','fontsize',20, 'fontweight','bold'); grid on; %title('ExpT-step graph'); + tt = [1,5,15,25,35,45]; hold on; + plot(tt,ExpTResult(tt),'r*'); + +return +end diff --git a/Utils_Control/nelder_mead_AE.m b/Utils_Control/nelder_mead_AE.m new file mode 100644 index 0000000..4cc95ee --- /dev/null +++ b/Utils_Control/nelder_mead_AE.m @@ -0,0 +1,394 @@ +function [ x_opt, n_feval ] = nelder_mead_AE (x, function_handle, flag_draw, UpsampledDataResult) +%% Camera Exposure Control for Robust Robot Vision with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% NELDER_MEAD performs the Nelder-Mead optimization search. +% Name : +% nelder_mead_AE.m +% +% Modified: +% +% 17 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Reference: +% +% We refer and modify the matlab code written by Jeff Borggaard +% "https://people.sc.fsu.edu/~jburkardt/m_src/nelder_mead/nelder_mead.html". +% the paper reference is follows : +% +% John Nelder, Roger Mead, +% A simplex method for function minimization, +% Computer Journal, +% Volume 7, Number 4, January 1965, pages 308-313. +% +% Parameters: +% +% Input, real X(M+1,M), contains a list of distinct points that serve as +% initial guesses for the solution. If the dimension of the space is M, +% then the matrix must contain exactly M+1 points. For instance, +% for a 2D space, you supply 3 points. Each row of the matrix contains +% one point; for a 2D space, this means that X would be a +% 3x2 matrix. +% +% Input, handle FUNCTION_HANDLE, a quoted expression for the function, +% or the name of an M-file that defines the function, preceded by an +% "@" sign; +% +% Input, logical FLAG_DRAW, an optional argument; if present, and set to 1, +% it will cause the program to display a graphical image of the contours +% and solution procedure. Note that this option only makes sense for +% problems in 2D, that is, with N=2. +% +% Input, string UpsampledData , a path of upsampled dataset file, +% this dataset is generated by "Extract_Result.m" file +% +% Output, real X_OPT, the optimal value of X found by the algorithm. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + %% 0. Define algorithm constants + rho = 1; % rho > 0, reflection coefficient + xi = 2; % xi > max(rho, 1), expansion coefficient + gam = 0.5; % 0 < gam < 1, contraction coefficient + sig = 0.5; % 0 < sig < 1, shrink coefficient + + tolerance = 1.0E-05; % end criteria + max_feval = 50; + + global Img_path; + global step; + global Flag_Dataset; + + load(UpsampledDataResult); + Flag_Dataset = dataset_flag; + Img_path = path_name; + step = 1; + + %% 1.Initialization + [ temp, n_dim ] = size ( x ); + + if ( temp ~= n_dim + 1 ) + fprintf ( 1, '\n' ); + fprintf ( 1, 'NELDER_MEAD - Fatal error!\n' ); + error(' Number of points must be = number of design variables + 1\n'); + end + + if ( flag_draw ) + xp = Xq(1,:); + yp = Yq(:,1)'; + fp = -Zq; % minimization + + % Find GT point + [~, idx] = max(Results_Our(:,3)); + GT_value = Results_Our(idx,:); + + figure (2) + subplot(1,2,1); + hold on; + contour(xp,yp,fp,50); + set(gca,'FontName', 'Times New Roman','FontSize',17); + xlabel('Gain','fontsize',20, 'fontweight','bold'); ylabel('ExpT','fontsize',20, 'fontweight','bold'); + set(gcf,'units','normalized','outerposition',[0.5 0.5 0.5 0.5]) + + % Draw starting & GT points + plot(x(1,1),x(1,2),'m*','MarkerSize',14,'linewidth',2.5); % ½ÃÀÛ°ª + plot(GT_value(1),GT_value(2),'g*','MarkerSize',14,'linewidth',2.5); % GT + + draw_image(x(1,:)); + draw_image(x(2,:)); + draw_image(x(3,:)); + + draw_simplex(x); + end + + % Evaluate each point of initial simplex + [f ] = evaluate ( x, function_handle ); + n_feval = n_dim + 1; + + [ f, index ] = sort ( f ); + x = x(index,:); + + % Begin the Nelder Mead iteration. + converged = 0; + diverged = 0; + + while ( ~converged && ~diverged ) + % 1. Compute the midpoint of the simplex opposite the worst point. + x_bar = sum ( x(1:n_dim,:) ) / n_dim; + + % 2. Compute the reflection point. + x_r = ( 1 + rho ) * x_bar - rho * x(n_dim+1,:); + f_r = feval(function_handle,x_r); + n_feval = n_feval + 1; + + if(flag_draw ==1) + draw_image(x_r); + end + + % 3-1. Accept the reflection point + if ( f(1) <= f_r && f_r <= f(n_dim) ) + x(n_dim+1,:) = x_r; + f(n_dim+1 ) = f_r; + + if (flag_draw) + figure(2); subplot(1,2,1); title('reflection', 'fontsize',18, 'fontweight','bold') + end + + % 3-2. Test for possible expansion. + elseif ( f_r < f(1) ) + x_e = ( 1 + rho * xi ) * x_bar - rho * xi * x(n_dim+1,:); + f_e = feval(function_handle,x_e); + n_feval = n_feval+1; + + if(flag_draw ==1) + draw_image(x_e); + end + + % Can we accept the expanded point? + if ( f_e < f_r ) + x(n_dim+1,:) = x_e; + f(n_dim+1 ) = f_e; + if (flag_draw) + figure(2); subplot(1,2,1); title('expansion', 'fontsize',18, 'fontweight','bold') + end + else + x(n_dim+1,:) = x_r; + f(n_dim+1 ) = f_r; + if (flag_draw) + figure(2); subplot(1,2,1); title('eventual reflection', 'fontsize',18, 'fontweight','bold') + end + end + + % 3-3.Outside contraction. + elseif ( f(n_dim) <= f_r && f_r < f(n_dim+1) ) + x_c = (1+rho*gam)*x_bar - rho*gam*x(n_dim+1,:); + f_c = feval(function_handle,x_c); n_feval = n_feval+1; + + if(flag_draw ==1) + draw_image(x_c); + end + + if (f_c <= f_r) % accept the contracted point + x(n_dim+1,:) = x_c; + f(n_dim+1 ) = f_c; + if (flag_draw) + figure(2); subplot(1,2,1); title('outside contraction', 'fontsize',18, 'fontweight','bold') + end + else + [x,f] = shrink(x,function_handle,sig); n_feval = n_feval+n_dim; + if (flag_draw) + figure(2); subplot(1,2,1); title('shrink', 'fontsize',18, 'fontweight','bold') + end + end + + % 3-4. Intra contraction. + else + x_c = ( 1 - gam ) * x_bar + gam * x(n_dim+1,:); + f_c = feval(function_handle,x_c); + n_feval = n_feval+1; + + if(flag_draw ==1) + draw_image(x_c); + end + + % Can we accept the contracted point? + if (f_c < f(n_dim+1)) + x(n_dim+1,:) = x_c; + f(n_dim+1 ) = f_c; + if (flag_draw) + figure(2); subplot(1,2,1); title('inside contraction', 'fontsize',18, 'fontweight','bold') + end + else + [x,f] = shrink(x,function_handle,sig); n_feval = n_feval+n_dim; + if (flag_draw) + figure(2); subplot(1,2,1); title('shrink', 'fontsize',18, 'fontweight','bold') + end + end + end + + % Resort the points. Note that we are not implementing the usual + % Nelder-Mead tie-breaking rules (when f(1) = f(2) or f(n_dim) = + % f(n_dim+1)... + + [ f, index ] = sort ( f ); + x = x(index,:); + + % Test for convergence + converged = f(n_dim+1)-f(1) < tolerance; + + % Test for divergence + diverged = ( max_feval < n_feval ); + + if (flag_draw) + draw_simplex(x); + end + end + + if ( 0 ) + fprintf('The best point x^* was: %d %d\n',x(1,:)); + fprintf('f(x^*) = %d\n',f(1)); + end + + x_opt = x(1,:); + + figure(2); + subplot(1,2,1); + plot(x(1,1),x(1,2),'r*','MarkerSize',14,'linewidth',2.5); + title(''); + + if ( diverged ) + fprintf ( 1, '\n' ); + fprintf ( 1, 'NELDER_MEAD - Warning!\n' ); + fprintf ( 1, ' The maximum number of function evaluations was exceeded\n') + fprintf ( 1, ' without convergence being achieved.\n' ); + end + + return +end + +function f = evaluate ( x, function_handle) + + %*****************************************************************************80 + % + %% EVALUATE handles the evaluation of the function at each point. + % + % Licensing: + % + % This code is distributed under the GNU LGPL license. + % + % Modified: + % + % 19 January 2009 + % + % Author: + % + % Jeff Borggaard + % + % Reference: + % + % John Nelder, Roger Mead, + % A simplex method for function minimization, + % Computer Journal, + % Volume 7, Number 4, January 1965, pages 308-313. + % + % Parameters: + % + % Input, real X(N_DIM+1,N_DIM), the points. + % + % Input, real FUNCTION_HANDLE ( X ), the handle of a MATLAB procedure + % to evaluate the function. + % + % Output, real F(1,NDIM+1), the value of the function at each point. + % + [ ~, n_dim ] = size ( x ); + + f = zeros ( 1, n_dim+1 ); + + for i = 1 : n_dim + 1 + f(i) = feval(function_handle,x(i,:)); + end + + return +end + +function [ x, f ] = shrink ( x, function_handle, sig ) + +%*****************************************************************************80 +% +%% SHRINK shrinks the simplex towards the best point. +% +% Discussion: +% +% In the worst case, we need to shrink the simplex along each edge towards +% the current "best" point. This is quite expensive, requiring n_dim new +% function evaluations. +% +% +% Modified: +% +% 19 January 2009 +% +% Author: +% +% Jeff Borggaard +% +% Reference: +% +% John Nelder, Roger Mead, +% A simplex method for function minimization, +% Computer Journal, +% Volume 7, Number 4, January 1965, pages 308-313. +% +% Parameters: +% +% Input, real X(N_DIM+1,N_DIM), the points. +% +% Input, real FUNCTION_HANDLE ( X ), the handle of a MATLAB procedure +% to evaluate the function. +% +% Input, real SIG, ? +% +% Output, real X(N_DIM+1,N_DIM), the points after shrinking was applied. +% +% Output, real F(1,NDIM+1), the value of the function at each point. +% + [ ~, n_dim ] = size ( x ); + + x1 = x(1,:); + f(1) = feval ( function_handle, x1 ); + + for i = 2 : n_dim + 1 + x(i,:) = sig * x(i,:) + ( 1.0 - sig ) * x(1,:); + f(i) = feval ( function_handle, x(i,:) ); + end + + return +end + + +function draw_image(x) + global Img_path step Flag_Dataset; + step = step + 1; + + figure (2) + subplot(1,2,1); + plot(x(1,1), x(1,2), 'k*', 'MarkerSize', 10, 'linewidth', 1.2); + + subplot(1,2,2); + x_close = FindClosestPoint(x(1,:), Flag_Dataset); + name_Initial_img = strcat('Param-ISO-', int2str(x_close(1,1)), '-ExpT-', int2str(x_close(1,2)), '.jpg'); + path_Initial_image = strcat(Img_path,'\',name_Initial_img); + + Initial_image = imread(path_Initial_image); + imshow(Initial_image); + title_str = strcat('Step : ',num2str(step),' Gain : ', num2str(x(1,1),2) ,'dB,',' ExpT : ', num2str(x(1,2)/1000,4), 'ms' ); + title(title_str, 'fontsize',16, 'fontweight','bold'); + pause(0.1); +end + +function draw_simplex(x) + figure (2) + subplot(1,2,1); + plot(x(1:2,1),x(1:2,2),'r') + plot(x(2:3,1),x(2:3,2),'r') + plot(x([1 3],1),x([1 3],2),'r') + pause(0.1); + plot(x(1:2,1),x(1:2,2),'k') + plot(x(2:3,1),x(2:3,2),'k') + plot(x([1 3],1),x([1 3],2),'k') +end \ No newline at end of file diff --git a/Utils_FeatureMatching/main_feature_matching_analysis.m b/Utils_FeatureMatching/main_feature_matching_analysis.m new file mode 100644 index 0000000..d3e8022 --- /dev/null +++ b/Utils_FeatureMatching/main_feature_matching_analysis.m @@ -0,0 +1,258 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Camera Exposure Control for Robust Robot Vision +% with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Name : feature_matching_analysis +% : conduct feature extraction & matching expeeriments. +% +% Modified: +% +% 17 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Input : path_name - path of each metric's result +% output : None +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [] = main_feature_matching_analysis(path_name) +close all; +clc; + +addpath(genpath('subfunctions')); +result_folder = strcat(path_name,'/result_matching'); +mkdir(result_folder); + +% GT Intrinsic / Extrinsic Parameters +% plz refer the "GT_CameraParameter.txt" of dataset. +K1 = [814.889003, -0.384418, 764.659138; + 0.000000, 814.206990, 576.541219; + 0.000000, 0.000000, 1.000000]; +K2 = [816.254045, -0.516877, 767.769055; + 0.000000, 815.958860, 580.307083; + 0.000000, 0.000000, 1.000000]; + +D1 = [-0.055030, 0.122773, 0.001917, -0.001426, -0.065038]; +D2 = [-0.052789, 0.123278, 0.000337, -0.001296, -0.067356]; + +R = [0.999887, -0.004519, -0.014343; + 0.004515, 0.999990, -0.000323; + 0.014345, 0.000259, 0.999897]; +T = [-0.201597, -0.001746, 0.000769]'; + +width = 1600; +height = 1200; + +%% Initialize rectification map +stereo_rect = cv.stereoRectify(K1, D1, K2, D2, [width, height], R, T, 'Alpha', 0); + +R1 = stereo_rect.R1; +R2 = stereo_rect.R2; +P1 = stereo_rect.P1; +P2 = stereo_rect.P2; + +[map1_1, map1_2] = cv.initUndistortRectifyMap(K1, D1, [width, height], 'R', R1, 'NewCameraMatrix', P1); +[map2_1, map2_2] = cv.initUndistortRectifyMap(K2, D2, [width, height], 'R', R2, 'NewCameraMatrix', P2); + +% Intrinsics and rotation are changed after rectification +K1 = P1(1:3, 1:3); +K2 = P2(1:3, 1:3); +R = eye(3); +T = K2\P2; +T = T(:, 4); +baseline = norm(T); + +%% Parameters for experiment +num_features_max = 100000; +num_features = 1000; + +th_dist = 0.02; % Inlier epipolar distance threshold +th_reproject = 0.1; +th_fast = 10; + +LeftFiles=dir(strcat(path_name,'/left/','*.jpg')); +RightFiles = dir(strcat(path_name,'/right/','*.jpg')); + +if(length(LeftFiles) ~= length(RightFiles)) + error('incorrect folder !!!'); + return; +end + +%% Do feature extractiong & matching +file_name = strcat(result_folder,'/','FeatureMactching_Result.txt'); +fileID = fopen(file_name,'a'); + +for k=1 : length(LeftFiles) + % Check image name consistency + LeftFileNames = LeftFiles(k).name; + RightFileNames = RightFiles(k).name; + + path_image_left = strcat(path_name,'/left/',LeftFileNames); + path_image_right = strcat(path_name,'/right/',RightFileNames); + + index = regexp(LeftFileNames,'_ISO-'); + My_name_left = LeftFileNames(1:index); + index = regexp(RightFileNames,'_ISO-'); + My_name_right = RightFileNames(1:index); + + if(~strcmp(My_name_left,My_name_right)) + error('incorrect file matching!!!'); + break; + end + + % Load images + image_left_orig = imread(path_image_left); + image_right_orig = imread(path_image_right); + + image_left = cv.remap(image_left_orig, map1_1, map1_2); + image_right = cv.remap(image_right_orig, map2_1, map2_2); + + result = struct(); + + %% Comparison 1. Number of FAST extracted + detector_fast = cv.ORB('MaxFeatures', num_features_max, 'ScoreType', 'FAST'); + detector_fast.FastThreshold = th_fast; + + % FAST extraction without limitation + fast_left_max_num = detector_fast.detect(image_left); + fast_right_max_num = detector_fast.detect(image_right); + + result.NumFASTLeftUnlimited = numel(fast_left_max_num); + result.NumFASTRightUnlimited = numel(fast_right_max_num); + + % FAST extraction with limitation + detector = cv.ORB('MaxFeatures', num_features, 'ScoreType', 'FAST'); + detector.FastThreshold = th_fast; + + fast_left_init = detector.detect(image_left); + fast_right_init = detector.detect(image_right); + + num_left_init = numel(fast_left_init); + num_right_init = numel(fast_right_init); + + result.NumFASTLeftInit = num_left_init; + result.NumFASTRightInit = num_right_init; + + % Feature extraction + [desc_left, kp_left] = detector.compute(image_left, fast_left_init); + [desc_right, kp_right] = detector.compute(image_right, fast_right_init); + + result.NumberOfKeyPointsLeft = numel(kp_left); + result.NumberOfKeyPointsRight = numel(kp_right); + + % matcher = cv.DescriptorMatcher('BFMatcher', 'CrossCheck', true); + matcher = cv.DescriptorMatcher('BFMatcher', 'NormType', 'Hamming', 'CrossCheck', true); + + % Initial feature matching + matches = matcher.match(desc_left, desc_right); + num_initial_matches = numel(matches); + + result.NumMatchesInitial = num_initial_matches; + + image_matches_init = cv.drawMatches(image_left, kp_left, image_right, kp_right, matches); + + % Matched left / right indices + pts_left = zeros(3, num_initial_matches); + pts_right = zeros(3, num_initial_matches); + + pts_right_gt = zeros(2, num_initial_matches); + + for k=1:num_initial_matches + % MexOpenCV (Zero-based) -> MATLAB (One-based) + % To normalized coordinates + pts_left(:, k) = K1\[kp_left(matches(k).queryIdx+1).pt'; 1]; + pts_right(:, k) = K2\[kp_right(matches(k).trainIdx+1).pt'; 1]; + + pts_right_gt_tmp = [R, T]*[pts_left(:, k); 1]; + + pts_right_gt(:, k) = [pts_right_gt_tmp(1)/pts_right_gt_tmp(3); ... + pts_right_gt_tmp(2)/pts_right_gt_tmp(3)]; + + end + + pts_left = pts_left(1:2, :)./repmat(pts_left(3, :), [2, 1]); + pts_right = pts_right(1:2, :)./repmat(pts_right(3, :), [2, 1]); + + dist_err = sqrt(sum((pts_right_gt - pts_right).^2, 1)); + flag_match_correct = dist_err < th_reproject; + matches_correct = matches(flag_match_correct); + + num_correct_matches = sum(flag_match_correct); + + result.NumMatchesInitialCorrect = num_correct_matches; + + image_matches_correct = cv.drawMatches(image_left, kp_left, image_right, kp_right, matches_correct); + + %% Step 2. Pose Estimation + E = cv.findEssentialMat(pts_left', pts_right', 'Method', 'LMedS'); + % E = cv.findEssentialMat(pts_left', pts_right', 'Method', 'Ransac', 'Threshold', 0.1); + + [R_init, T_init, num_matches_ransac, flag_good] = cv.recoverPose(E, pts_left', pts_right'); + flag_good = flag_good > 0; + + matches_ransac = matches(flag_good); + pts_left_ransac = pts_left(:, flag_good); + pts_right_ransac = pts_right(:, flag_good); + + result.NumMatchesRANSAC = num_matches_ransac; + + image_matches_ransac = cv.drawMatches(image_left, kp_left, ... + image_right, kp_right, matches_ransac); + + figure(5); + imagesc([image_matches_init; image_matches_ransac; image_matches_correct]); + title(sprintf('Number of initial / LMedS / correct matches : %d -> %d -> %d', ... + result.NumMatchesInitial, result.NumMatchesRANSAC, result.NumMatchesInitialCorrect)); + drawnow; + output = strcat(result_folder,'/',My_name_left); + saveas(gcf,output,'fig'); + saveas(gcf,output,'jpg'); + + % Translation is up-to-scale + T_init = T_init*baseline/norm(T_init); + + R_err_init = real(acosd(0.5*trace(R'*R_init) - 0.5)); + T_err_init = norm(T - T_init); + + result.R_err_init = R_err_init; + result.T_err_init = T_err_init; + + result.R = R; + result.T = T; + result.R_init = R_init; + result.T_init = T_init; + + + %% Result + fprintf(fileID, '==========================================\n'); + fprintf(fileID, '\nMatching and Pose Estimation results\n'); + fprintf(fileID, 'Dataset Path : %s \n', path_name); + fprintf(fileID, 'Result of %s \n', My_name_left); + fprintf(fileID, 'Number of FAST from the left : %d\n', result.NumFASTLeftUnlimited); + fprintf(fileID, 'Number of FAST from the right : %d\n', result.NumFASTRightUnlimited); + fprintf(fileID, 'Number of keypoints from the left : %d\n', result.NumberOfKeyPointsLeft); + fprintf(fileID, 'Number of keypoints from the right : %d\n', result.NumberOfKeyPointsRight); + fprintf(fileID, 'Number of initial matches : %d\n', result.NumMatchesInitial); + fprintf(fileID, 'Number of correct matches : %d\n', result.NumMatchesInitialCorrect); + fprintf(fileID, 'Number of RANSAC matches : %d\n', result.NumMatchesRANSAC); + fprintf(fileID, 'Initial rotation error : %f (deg)\n', result.R_err_init); + fprintf(fileID, 'Initial translation error : %f (m)\n', result.T_err_init); + fprintf(fileID, '==========================================\n'); +end + +fclose(fileID); +end \ No newline at end of file diff --git a/Utils_FeatureMatching/subfunctions/KeyPointNMS.m b/Utils_FeatureMatching/subfunctions/KeyPointNMS.m new file mode 100644 index 0000000..4bacd58 --- /dev/null +++ b/Utils_FeatureMatching/subfunctions/KeyPointNMS.m @@ -0,0 +1,40 @@ +% KEYPOINTNMS Do non-maximum suppression on keypoints inside a grid +% +% Inputs +% grid_range - Grid range [x1, y1, x2, y2] +% pt - Keypoints +% num - Number of keypoints to preserve +% Outputs +% idx - Indices of the survived keypoint +function idx = KeyPointNMS(grid_range, kp, num) + x1 = grid_range(1); + y1 = grid_range(2); + x2 = grid_range(3); + y2 = grid_range(4); + + num_kp = numel(kp); + + x = zeros(num_kp, 1); + y = zeros(num_kp, 1); + s = zeros(num_kp, 1); + + for k=1:num_kp + x(k) = kp(k).pt(1); + y(k) = kp(k).pt(2); + s(k) = kp(k).response; + end + + idx_inside = find((x >= x1) & (x < x2) & (y >= y1) & (y < y2)); + + if(numel(idx_inside) <= num) + idx = idx_inside; + return; + end + + score_inside = s(idx_inside); + + [~, idx_sorted] = sort(score_inside, 'descend'); + + idx = idx_inside(idx_sorted(1:num)); + +end \ No newline at end of file diff --git a/Utils_FeatureMatching/subfunctions/SymmetricEpipolarDistance.m b/Utils_FeatureMatching/subfunctions/SymmetricEpipolarDistance.m new file mode 100644 index 0000000..ef750f8 --- /dev/null +++ b/Utils_FeatureMatching/subfunctions/SymmetricEpipolarDistance.m @@ -0,0 +1,29 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Name : SymmetricEpipolarDistance +% Input : E - Essential matrix +% x1 - normalized image points from the 1st camera [3 x N] +% x2 - normalized image points from the 2nd camera [3 x N] +% th - distance threshold for inliers +% Output : D - sum of distances +% flag_inliers - flags of inliners +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [D, flag_inliers] = SymmetricEpipolarDistance(F, x1, x2, th) + +% Epipolar lines +l1 = F'*x2; +l2 = F*x1; + +l1 = l1./repmat(sqrt(sum(l1(1:2,:).^2, 1)), [3, 1]); +l2 = l2./repmat(sqrt(sum(l2(1:2,:).^2, 1)), [3, 1]); + +% Distance +d1 = sqrt(sum(l1.*x1, 1).^2); +d2 = sqrt(sum(l2.*x2, 1).^2); + +d = (d1 + d2); + +flag_inliers = d < th; + +D = sum(d(:)); + +return \ No newline at end of file diff --git a/Utils_FeatureMatching/subfunctions/ValidCameraPosition.m b/Utils_FeatureMatching/subfunctions/ValidCameraPosition.m new file mode 100644 index 0000000..ce8eea8 --- /dev/null +++ b/Utils_FeatureMatching/subfunctions/ValidCameraPosition.m @@ -0,0 +1,73 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Name : ValidCameraPosition +% Input : E - essential matrix +% P1 - normalized camera matrix of the 1st camera [R | T] +% x1 - normalized points of the 1st camera [2 x N] +% x2 - normalized points of the 2nd camera [2 x N] +% Output : P2 - normalized camera matrix of the 2nd camera [R | T] +% R - rotation matrix +% T - translation matrix +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [P2, R, T] = ValidCameraPosition(E, P1, x1, x2) +[U, ~, V] = svd(E); + +W = [0, -1, 0; 1, 0, 0; 0, 0, 1]; +u3 = U(:,3); + +% 4 possible positions +P21 = [U*W*V', u3]; +P22 = [U*W*V', -u3]; +P23 = [U*W'*V', u3]; +P24 = [U*W'*V', -u3]; + +P = {P21, P22, P23, P24}; + +P_ref = [eye(3,3), zeros(3,1)]; + +P2 = []; +R = []; +T = []; + +N = size(x1, 2); +num_valid = 0; + +for k=1:4 + X = zeros(4,N); + + for n=1:N + A = [x1(1)*P_ref(3,:) - P_ref(1,:); + x1(2)*P_ref(3,:) - P_ref(2,:); + x2(1)*P{k}(3,:) - P{k}(1,:); + x2(2)*P{k}(3,:) - P{k}(2,:)]; + + [~, ~, V] = svd(A); + X(:,n) = V(:,end); + end + + % Projected points + xp1 = P_ref*X; + xp2 = P{k}*X; + + d1 = (sign(det(squeeze(P_ref(:,1:3))))*xp1(3,:))./(X(4,:)*norm(P_ref(3,:))); + d2 = (sign(det(squeeze(P{k}(:,1:3))))*xp2(3,:))./(X(4,:)*norm(P{k}(3,:))); + + num_pos = sum((d1 > 0) & (d2 > 0)); + + if((num_pos > 0) && (num_pos > num_valid)) + num_valid = num_pos; + + P_tmp = P{k}*[P1; [0, 0, 0, 1]]; + + R = P_tmp(:,1:3); + T = P_tmp(:,4); + + R_det = det(R); + + R = R/R_det; + T = T/R_det; + + P2 = [R, T]; + end +end + +return; \ No newline at end of file diff --git a/Utils_FeatureMatching/subfunctions/calculateReprojectionError.m b/Utils_FeatureMatching/subfunctions/calculateReprojectionError.m new file mode 100644 index 0000000..1510640 --- /dev/null +++ b/Utils_FeatureMatching/subfunctions/calculateReprojectionError.m @@ -0,0 +1,46 @@ +% CALCULATEREPROJECTIONERROR Calculate reprojection error +% +% Inputs +% params - Input rotation and translation vectors [R(3), T(3)] +% pts_left - Left keypoints [3 x N] +% pts_right - Right keypoints [3 x N] +% +% Outputs +% err - Calculated reprojection error +function err = calculateReprojectionError(params, T, pts_left, pts_right) + R = rotationVectorToMatrix(params(1:3))'; +% T = params(4:6)'; + + T_mat = [ 0, -T(3), T(2); + T(3), 0, -T(1); + -T(2), T(1), 0]; + + E = R*T_mat; + + num = size(pts_left, 2); + if(size(pts_right, 2) ~= num) + error('Number of size must be the same'); + end + + pts_left = [pts_left; ones(1, num)]; + pts_right = [pts_right; ones(1, num)]; + + l1 = E'*pts_right; + l2 = E*pts_left; + + l1_norm = sqrt(sum(l1.^2, 1)); + l2_norm = sqrt(sum(l2.^2, 1)); + + l1 = l1./repmat(l1_norm, [3, 1]); + l2 = l2./repmat(l2_norm, [3, 1]); + + d1 = abs(sum(l1.*pts_left, 1)); + d2 = abs(sum(l2.*pts_right, 1)); + + err = (d1(:) + d2(:))/2; +% err = logLoss(err); +end + +% function err_out = logLoss(err_in) +% err_out = log(err_in + 1); +% end \ No newline at end of file diff --git a/Utils_FeatureMatching/subfunctions/calibrated_fivepoint.m b/Utils_FeatureMatching/subfunctions/calibrated_fivepoint.m new file mode 100644 index 0000000..d148808 --- /dev/null +++ b/Utils_FeatureMatching/subfunctions/calibrated_fivepoint.m @@ -0,0 +1,100 @@ +function Evec = calibrated_fivepoint( Q1,Q2) +% Function Evec = calibrated_fivepoint( Q1,Q2) +% Henrik Stewenius 20040722 +% +% +% ARTICLE{stewenius-engels-nister-isprsj-2006, +% AUTHOR = {H. Stew\'enius and C. Engels and D. Nist\'er}, +% TITLE = {Recent Developments on Direct Relative Orientation}, +% JOURNAL = {ISPRS Journal of Photogrammetry and Remote Sensing}, +% URL = {http://dx.doi.org/10.1016/j.isprsjprs.2006.03.005}, +% VOLUME = {60}, +% ISSUE = {4}, +% PAGES = {284--294}, +% MONTH = JUN, +% CODE = {http://vis.uky.edu/~stewe/FIVEPOINT}, +% PDF = {http://www.vis.uky.edu/~stewe/publications/stewenius_engels_nister_5pt_isprs.pdf}, +% YEAR = 2006 +%} +% +% +% For more information please see: +% Grobner Basis Methods for Minimal Problems in Computer Vision +% Henrik Stewenius, +% PhD Thesis, Lund University, 2005 +% http://www.maths.lth.se/matematiklth/personal/stewe/THESIS/ +% +% +% If this implementation is too slow for your needs please see: +% An Efficient Solution to the Five-Point Relative Pose +% +%@Article{ nister-itpam-04, +% author = {Nist\'er, D.}, +% journal = pami, +% month = {June}, +% number = {6}, +% title = {Problem}, +% pages = {756-770}, +% volume = {26}, +% year = {2004} +%} +% +% +% +% +% Code to veryfy that it works: +% Q1 = rand(3,5); +% Q2 = rand(3,5); +% Evec = calibrated_fivepoint( Q1,Q2); +% for i=1:size(Evec,2) +% E = reshape(Evec(:,i),3,3); +% % Check determinant constraint! +% det( E) +% % Check trace constraint +% 2 *E*transpose(E)*E -trace( E*transpose(E))*E +% % Check reprojection errors +% diag( Q1'*E*Q2) +% end +% +% PS: Please note that due to varying standards of which is Q1 and Q2 +% it is very possible that you get essential matrices which are +% the transpose of what your expected. + + +%1 Pose linear equations for the essential matrix. +Q1 = Q1'; +Q2 = Q2'; + +Q = [Q1(:,1).*Q2(:,1) , ... + Q1(:,2).*Q2(:,1) , ... + Q1(:,3).*Q2(:,1) , ... + Q1(:,1).*Q2(:,2) , ... + Q1(:,2).*Q2(:,2) , ... + Q1(:,3).*Q2(:,2) , ... + Q1(:,1).*Q2(:,3) , ... + Q1(:,2).*Q2(:,3) , ... + Q1(:,3).*Q2(:,3) ] ; + + +[U,S,V] = svd(Q,0); +EE = V(:,6:9); + +A = calibrated_fivepoint_helper( EE ) ; +warning('off', 'MATLAB:nearlySingularMatrix'); +A = A(:,1:10)\A(:,11:20); +warning('on', 'MATLAB:nearlySingularMatrix'); +M = -A([1 2 3 5 6 8], :); + +M(7,1) = 1; +M(8,2) = 1; +M(9,4) = 1; +M(10,7) = 1; + +[V,D] = eig(M ); +SOLS = V(7:9,:)./(ones(3,1)*V(10,:)); + +Evec = EE*[SOLS ; ones(1,10 ) ]; +Evec = Evec./ ( ones(9,1)*sqrt(sum( Evec.^2))); + +I = find(not(imag( Evec(1,:) ))); +Evec = Evec(:,I); diff --git a/Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.c b/Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.c new file mode 100644 index 0000000..cd9db55 --- /dev/null +++ b/Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.c @@ -0,0 +1,380 @@ +/* +Copyright Henrik Stewenius. + + +This Code was written for the paper: + +@ARTICLE{stewenius-engels-nister-isprsj-2006, + AUTHOR = {H. Stew\'enius and C. Engels and D. Nist\'er}, + TITLE = {Recent Developments on Direct Relative Orientation}, + JOURNAL = {ISPRS Journal of Photogrammetry and Remote Sensing}, + URL = {http://dx.doi.org/10.1016/j.isprsjprs.2006.03.005}, + VOLUME = {60}, + ISSUE = {4}, + PAGES = {284--294}, + MONTH = JUN, + CODE = {http://vis.uky.edu/~stewe/FIVEPOINT}, + PDF = {http://www.vis.uky.edu/~stewe/publications/stewenius_engels_nister_5pt_isprs.pdf}, + YEAR = 2006 +} + + You are free to use this code for academic research as long as you + refer to this paper. Commercial licence can be negotiated. Though if + you really want to use this in a product there are certain optimizations + which you would want. +*/ + + + +/************************************************* + Indata : 10x4 matrix + Data out: 10x20 matrix +*************************************************/ +#include "mex.h" +#include + + +void mexFunction(int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +/*nlhs number of expected mxArrays. + plhs pointer to an array of NULL pointers. + nrhs number of input mxArrays. + prhs pointer to an array of input mxArrays. */ +{ + double *EE, *A; + double e00,e01,e02,e03,e04,e05,e06,e07,e08; + double e10,e11,e12,e13,e14,e15,e16,e17,e18; + double e20,e21,e22,e23,e24,e25,e26,e27,e28; + double e30,e31,e32,e33,e34,e35,e36,e37,e38; + + double e002,e012,e022,e032,e042,e052,e062,e072,e082; + double e102,e112,e122,e132,e142,e152,e162,e172,e182; + double e202,e212,e222,e232,e242,e252,e262,e272,e282; + double e302,e312,e322,e332,e342,e352,e362,e372,e382; + + double e003,e013,e023,e033,e043,e053,e063,e073,e083; + double e103,e113,e123,e133,e143,e153,e163,e173,e183; + double e203,e213,e223,e233,e243,e253,e263,e273,e283; + double e303,e313,e323,e333,e343,e353,e363,e373,e383; + + if(nrhs != 1 ) mexErrMsgTxt("EE (10*4)\n"); + EE = mxGetPr( prhs[0] ) ; + plhs[0] = mxCreateDoubleMatrix(10 ,20 , mxREAL); + A = mxGetPr( plhs[0]); + + +e00 = EE[0*9 + 0 ]; +e10 = EE[1*9 + 0 ]; +e20 = EE[2*9 + 0 ]; +e30 = EE[3*9 + 0 ]; +e01 = EE[0*9 + 1 ]; +e11 = EE[1*9 + 1 ]; +e21 = EE[2*9 + 1 ]; +e31 = EE[3*9 + 1 ]; +e02 = EE[0*9 + 2 ]; +e12 = EE[1*9 + 2 ]; +e22 = EE[2*9 + 2 ]; +e32 = EE[3*9 + 2 ]; +e03 = EE[0*9 + 3 ]; +e13 = EE[1*9 + 3 ]; +e23 = EE[2*9 + 3 ]; +e33 = EE[3*9 + 3 ]; +e04 = EE[0*9 + 4 ]; +e14 = EE[1*9 + 4 ]; +e24 = EE[2*9 + 4 ]; +e34 = EE[3*9 + 4 ]; +e05 = EE[0*9 + 5 ]; +e15 = EE[1*9 + 5 ]; +e25 = EE[2*9 + 5 ]; +e35 = EE[3*9 + 5 ]; +e06 = EE[0*9 + 6 ]; +e16 = EE[1*9 + 6 ]; +e26 = EE[2*9 + 6 ]; +e36 = EE[3*9 + 6 ]; +e07 = EE[0*9 + 7 ]; +e17 = EE[1*9 + 7 ]; +e27 = EE[2*9 + 7 ]; +e37 = EE[3*9 + 7 ]; +e08 = EE[0*9 + 8 ]; +e18 = EE[1*9 + 8 ]; +e28 = EE[2*9 + 8 ]; +e38 = EE[3*9 + 8 ]; + + +e002 =e00*e00; +e102 =e10*e10; +e202 =e20*e20; +e302 =e30*e30; +e012 =e01*e01; +e112 =e11*e11; +e212 =e21*e21; +e312 =e31*e31; +e022 =e02*e02; +e122 =e12*e12; +e222 =e22*e22; +e322 =e32*e32; +e032 =e03*e03; +e132 =e13*e13; +e232 =e23*e23; +e332 =e33*e33; +e042 =e04*e04; +e142 =e14*e14; +e242 =e24*e24; +e342 =e34*e34; +e052 =e05*e05; +e152 =e15*e15; +e252 =e25*e25; +e352 =e35*e35; +e062 =e06*e06; +e162 =e16*e16; +e262 =e26*e26; +e362 =e36*e36; +e072 =e07*e07; +e172 =e17*e17; +e272 =e27*e27; +e372 =e37*e37; +e082 =e08*e08; +e182 =e18*e18; +e282 =e28*e28; +e382 =e38*e38; + +e003 =e00*e00*e00; +e103 =e10*e10*e10; +e203 =e20*e20*e20; +e303 =e30*e30*e30; +e013 =e01*e01*e01; +e113 =e11*e11*e11; +e213 =e21*e21*e21; +e313 =e31*e31*e31; +e023 =e02*e02*e02; +e123 =e12*e12*e12; +e223 =e22*e22*e22; +e323 =e32*e32*e32; +e033 =e03*e03*e03; +e133 =e13*e13*e13; +e233 =e23*e23*e23; +e333 =e33*e33*e33; +e043 =e04*e04*e04; +e143 =e14*e14*e14; +e243 =e24*e24*e24; +e343 =e34*e34*e34; +e053 =e05*e05*e05; +e153 =e15*e15*e15; +e253 =e25*e25*e25; +e353 =e35*e35*e35; +e063 =e06*e06*e06; +e163 =e16*e16*e16; +e263 =e26*e26*e26; +e363 =e36*e36*e36; +e073 =e07*e07*e07; +e173 =e17*e17*e17; +e273 =e27*e27*e27; +e373 =e37*e37*e37; +e083 =e08*e08*e08; +e183 =e18*e18*e18; +e283 =e28*e28*e28; +e383 =e38*e38*e38; + + +A[0 + 10*0]=0.5*e003+0.5*e00*e012+0.5*e00*e022+0.5*e00*e032+e03*e01*e04+e03*e02*e05+0.5*e00*e062+e06*e01*e07+e06*e02*e08-0.5*e00*e042-0.5*e00*e052-0.5*e00*e072-0.5*e00*e082; +A[0 + 10*1]=e00*e11*e01+e00*e12*e02+e03*e00*e13+e03*e11*e04+e03*e01*e14+e03*e12*e05+e03*e02*e15+e13*e01*e04+e13*e02*e05+e06*e00*e16+1.5*e10*e002+0.5*e10*e012+0.5*e10*e022+0.5*e10*e062-0.5*e10*e042-0.5*e10*e052-0.5*e10*e072+0.5*e10*e032+e06*e11*e07+e06*e01*e17+e06*e12*e08+e06*e02*e18+e16*e01*e07+e16*e02*e08-e00*e14*e04-e00*e17*e07-e00*e15*e05-e00*e18*e08-0.5*e10*e082; +A[0 + 10*2]=e16*e02*e18+e03*e12*e15+e10*e11*e01+e10*e12*e02+e03*e10*e13+e03*e11*e14+e13*e11*e04+e13*e01*e14+e13*e12*e05+e13*e02*e15+e06*e10*e16+e06*e12*e18+e06*e11*e17+e16*e11*e07+e16*e01*e17+e16*e12*e08-e10*e14*e04-e10*e17*e07-e10*e15*e05-e10*e18*e08+1.5*e00*e102+0.5*e00*e122+0.5*e00*e112+0.5*e00*e132+0.5*e00*e162-0.5*e00*e152-0.5*e00*e172-0.5*e00*e182-0.5*e00*e142; +A[0 + 10*3]=0.5*e103+0.5*e10*e122+0.5*e10*e112+0.5*e10*e132+e13*e12*e15+e13*e11*e14+0.5*e10*e162+e16*e12*e18+e16*e11*e17-0.5*e10*e152-0.5*e10*e172-0.5*e10*e182-0.5*e10*e142; +A[0 + 10*4]=-e00*e28*e08-e00*e25*e05-e00*e27*e07-e00*e24*e04+e26*e02*e08+e26*e01*e07+e06*e02*e28+e06*e22*e08+e06*e01*e27+e06*e21*e07+e23*e02*e05+e23*e01*e04+e03*e02*e25+e03*e22*e05+e03*e01*e24+e03*e21*e04+e00*e22*e02+e00*e21*e01-0.5*e20*e082-0.5*e20*e052-0.5*e20*e072-0.5*e20*e042+e06*e00*e26+0.5*e20*e062+e03*e00*e23+0.5*e20*e022+1.5*e20*e002+0.5*e20*e032+0.5*e20*e012; +A[0 + 10*5]=-e10*e24*e04-e10*e27*e07-e10*e25*e05-e10*e28*e08-e20*e14*e04-e20*e17*e07-e20*e15*e05-e20*e18*e08-e00*e24*e14-e00*e25*e15-e00*e27*e17-e00*e28*e18+e06*e21*e17+e06*e22*e18+e06*e12*e28+e16*e00*e26+e16*e21*e07+e16*e01*e27+e16*e22*e08+e16*e02*e28+e26*e11*e07+e26*e01*e17+e26*e12*e08+e26*e02*e18+e06*e11*e27+e23*e11*e04+e23*e01*e14+e23*e12*e05+e23*e02*e15+e06*e20*e16+e06*e10*e26+e03*e21*e14+e03*e22*e15+e03*e12*e25+e13*e00*e23+e13*e21*e04+e13*e01*e24+e13*e22*e05+e13*e02*e25+e03*e11*e24+e03*e20*e13+e03*e10*e23+e00*e21*e11+3*e00*e20*e10+e00*e22*e12+e20*e12*e02+e20*e11*e01+e10*e22*e02+e10*e21*e01; +A[0 + 10*6]=-0.5*e20*e152+e26*e11*e17-e10*e24*e14-e10*e25*e15-e10*e27*e17-e10*e28*e18+0.5*e20*e162+e13*e10*e23+e13*e22*e15+e23*e12*e15+e23*e11*e14+e16*e10*e26+e16*e21*e17+e16*e11*e27+e16*e22*e18+e16*e12*e28+e26*e12*e18+e13*e12*e25+0.5*e20*e132+1.5*e20*e102+0.5*e20*e122+0.5*e20*e112+e10*e21*e11+e10*e22*e12+e13*e11*e24-0.5*e20*e172-0.5*e20*e182-0.5*e20*e142+e13*e21*e14; +A[0 + 10*7]=-e20*e25*e05-e20*e28*e08-0.5*e00*e272-0.5*e00*e282-0.5*e00*e242+0.5*e00*e262-0.5*e00*e252+e06*e20*e26+0.5*e00*e232+e06*e22*e28+e06*e21*e27+e26*e21*e07+e26*e01*e27+e26*e22*e08+e26*e02*e28-e20*e24*e04-e20*e27*e07+e03*e20*e23+e03*e22*e25+e03*e21*e24+e23*e21*e04+e23*e01*e24+e23*e22*e05+e23*e02*e25+e20*e21*e01+e20*e22*e02+1.5*e00*e202+0.5*e00*e222+0.5*e00*e212; +A[0 + 10*8]=e23*e21*e14+e23*e11*e24+e23*e22*e15+e23*e12*e25+e16*e20*e26+e16*e22*e28+e16*e21*e27+e26*e21*e17+e26*e11*e27+e26*e22*e18+e26*e12*e28+1.5*e10*e202+0.5*e10*e222+0.5*e10*e212+0.5*e10*e232+e20*e21*e11+e20*e22*e12+e13*e20*e23+e13*e22*e25+e13*e21*e24-e20*e24*e14-e20*e25*e15-e20*e27*e17-e20*e28*e18-0.5*e10*e272-0.5*e10*e282-0.5*e10*e242-0.5*e10*e252+0.5*e10*e262; +A[0 + 10*9]=0.5*e203+0.5*e20*e222+0.5*e20*e212+0.5*e20*e232+e23*e22*e25+e23*e21*e24+0.5*e20*e262+e26*e22*e28+e26*e21*e27-0.5*e20*e252-0.5*e20*e272-0.5*e20*e282-0.5*e20*e242; +A[0 + 10*10]=e06*e32*e08-0.5*e30*e082-0.5*e30*e042-0.5*e30*e052-0.5*e30*e072+0.5*e30*e012+0.5*e30*e022+0.5*e30*e032+0.5*e30*e062+1.5*e30*e002+e00*e31*e01+e00*e32*e02+e03*e31*e04+e03*e01*e34+e03*e32*e05+e03*e02*e35+e33*e01*e04+e33*e02*e05+e06*e00*e36+e06*e31*e07+e06*e01*e37+e06*e02*e38+e36*e01*e07+e36*e02*e08-e00*e34*e04-e00*e37*e07-e00*e35*e05-e00*e38*e08+e03*e00*e33; +A[0 + 10*11]=e06*e30*e16+e03*e30*e13+e16*e31*e07+e06*e10*e36-e10*e37*e07+3*e00*e30*e10+e00*e32*e12-e00*e38*e18-e10*e34*e04-e10*e35*e05-e10*e38*e08-e30*e14*e04-e30*e17*e07-e30*e15*e05-e30*e18*e08+e00*e31*e11+e10*e31*e01+e10*e32*e02+e30*e11*e01+e30*e12*e02+e03*e10*e33-e00*e34*e14-e00*e35*e15-e00*e37*e17+e03*e31*e14+e03*e11*e34+e03*e32*e15+e03*e12*e35+e13*e00*e33+e13*e31*e04+e13*e01*e34+e13*e32*e05+e13*e02*e35+e33*e11*e04+e33*e01*e14+e33*e12*e05+e33*e02*e15+e06*e31*e17+e06*e11*e37+e06*e32*e18+e06*e12*e38+e16*e00*e36+e16*e01*e37+e16*e32*e08+e16*e02*e38+e36*e11*e07+e36*e01*e17+e36*e12*e08+e36*e02*e18; +A[0 + 10*12]=e13*e10*e33+e33*e11*e14+e16*e10*e36+e16*e31*e17+e16*e11*e37+e16*e32*e18+e16*e12*e38+e36*e12*e18+e36*e11*e17-e10*e34*e14-e10*e35*e15-e10*e37*e17-e10*e38*e18+e10*e31*e11+e10*e32*e12+e13*e31*e14+e13*e11*e34+e13*e32*e15+e13*e12*e35+e33*e12*e15+1.5*e30*e102+0.5*e30*e122+0.5*e30*e112+0.5*e30*e132+0.5*e30*e162-0.5*e30*e152-0.5*e30*e172-0.5*e30*e182-0.5*e30*e142; +A[0 + 10*13]=e00*e32*e22+3*e00*e30*e20+e00*e31*e21+e20*e31*e01+e20*e32*e02+e30*e21*e01+e30*e22*e02+e03*e20*e33+e03*e32*e25+e03*e22*e35+e03*e31*e24+e03*e21*e34+e23*e00*e33+e23*e31*e04+e23*e01*e34+e23*e32*e05+e23*e02*e35+e33*e21*e04+e33*e01*e24+e33*e22*e05+e33*e02*e25+e06*e30*e26+e06*e20*e36+e06*e32*e28+e06*e22*e38+e06*e31*e27+e06*e21*e37+e26*e00*e36+e26*e31*e07+e03*e30*e23+e26*e01*e37+e26*e32*e08+e26*e02*e38+e36*e21*e07+e36*e01*e27+e36*e22*e08+e36*e02*e28-e00*e35*e25-e00*e37*e27-e00*e38*e28-e00*e34*e24-e20*e34*e04-e20*e37*e07-e20*e35*e05-e20*e38*e08-e30*e24*e04-e30*e27*e07-e30*e25*e05-e30*e28*e08; +A[0 + 10*14]=e16*e30*e26+e13*e21*e34+3*e10*e30*e20+e10*e32*e22+e10*e31*e21+e20*e31*e11+e20*e32*e12+e30*e21*e11+e30*e22*e12+e13*e30*e23+e13*e20*e33+e13*e32*e25+e13*e22*e35+e13*e31*e24+e23*e10*e33+e23*e31*e14+e23*e11*e34+e23*e32*e15+e23*e12*e35+e33*e21*e14+e33*e11*e24+e33*e22*e15+e33*e12*e25+e16*e20*e36+e16*e32*e28+e16*e22*e38+e16*e31*e27+e16*e21*e37+e26*e10*e36+e26*e31*e17+e26*e11*e37+e26*e32*e18+e26*e12*e38+e36*e21*e17+e36*e11*e27+e36*e22*e18+e36*e12*e28-e10*e35*e25-e10*e37*e27-e10*e38*e28-e10*e34*e24-e20*e34*e14-e20*e35*e15-e20*e37*e17-e20*e38*e18-e30*e24*e14-e30*e25*e15-e30*e27*e17-e30*e28*e18; +A[0 + 10*15]=-e20*e34*e24+0.5*e30*e262-0.5*e30*e252-0.5*e30*e272-0.5*e30*e282-0.5*e30*e242+1.5*e30*e202+0.5*e30*e222+0.5*e30*e212+0.5*e30*e232+e20*e32*e22+e20*e31*e21+e23*e20*e33+e23*e32*e25+e23*e22*e35+e23*e31*e24+e23*e21*e34+e33*e22*e25+e33*e21*e24+e26*e20*e36+e26*e32*e28+e26*e22*e38+e26*e31*e27+e26*e21*e37+e36*e22*e28+e36*e21*e27-e20*e35*e25-e20*e37*e27-e20*e38*e28; +A[0 + 10*16]=0.5*e00*e322+e30*e32*e02+e30*e31*e01+1.5*e00*e302+0.5*e00*e312+e03*e32*e35+e33*e31*e04+e33*e01*e34+e33*e32*e05+e33*e02*e35+e06*e30*e36+e06*e31*e37+e06*e32*e38+e36*e31*e07+e36*e01*e37+e36*e32*e08+e36*e02*e38-e30*e34*e04-e30*e37*e07-e30*e35*e05-e30*e38*e08+0.5*e00*e332+0.5*e00*e362-0.5*e00*e382-0.5*e00*e352-0.5*e00*e342-0.5*e00*e372+e03*e30*e33+e03*e31*e34; +A[0 + 10*17]=0.5*e10*e362-0.5*e10*e382-0.5*e10*e352-0.5*e10*e342-0.5*e10*e372+e36*e31*e17+e36*e11*e37+e36*e32*e18+e36*e12*e38-e30*e34*e14-e30*e35*e15-e30*e37*e17-e30*e38*e18+1.5*e10*e302+0.5*e10*e312+0.5*e10*e322+0.5*e10*e332+e30*e31*e11+e30*e32*e12+e13*e30*e33+e13*e31*e34+e13*e32*e35+e33*e31*e14+e33*e11*e34+e33*e32*e15+e33*e12*e35+e16*e30*e36+e16*e31*e37+e16*e32*e38; +A[0 + 10*18]=e33*e31*e24+e33*e21*e34+e26*e30*e36+e26*e31*e37+e26*e32*e38+e36*e32*e28+e36*e22*e38+e36*e31*e27+e36*e21*e37-e30*e35*e25-e30*e37*e27-e30*e38*e28-e30*e34*e24+e33*e22*e35+1.5*e20*e302+0.5*e20*e312+0.5*e20*e322+0.5*e20*e332+0.5*e20*e362-0.5*e20*e382-0.5*e20*e352-0.5*e20*e342-0.5*e20*e372+e30*e32*e22+e30*e31*e21+e23*e30*e33+e23*e31*e34+e23*e32*e35+e33*e32*e25; +A[0 + 10*19]=0.5*e303+0.5*e30*e312+0.5*e30*e322+0.5*e30*e332+e33*e31*e34+e33*e32*e35+0.5*e30*e362+e36*e31*e37+e36*e32*e38-0.5*e30*e382-0.5*e30*e352-0.5*e30*e342-0.5*e30*e372; +A[1 + 10*0]=e00*e01*e04+0.5*e002*e03+e00*e02*e05+0.5*e033+0.5*e03*e042+0.5*e03*e052+0.5*e03*e062+e06*e04*e07+e06*e05*e08-0.5*e03*e012-0.5*e03*e072-0.5*e03*e022-0.5*e03*e082; +A[1 + 10*1]=e03*e14*e04+e10*e01*e04+e16*e05*e08+e00*e10*e03+e00*e11*e04+e00*e01*e14+e00*e12*e05+e00*e02*e15+e10*e02*e05+e03*e15*e05+e06*e03*e16+e06*e14*e07+e06*e04*e17+e06*e15*e08+e06*e05*e18+0.5*e002*e13+1.5*e13*e032+0.5*e13*e042+0.5*e13*e052+0.5*e13*e062-0.5*e13*e012-0.5*e13*e072-0.5*e13*e022-0.5*e13*e082+e16*e04*e07-e03*e12*e02-e03*e11*e01-e03*e17*e07-e03*e18*e08; +A[1 + 10*2]=-e13*e11*e01+e00*e10*e13+e00*e12*e15+e00*e11*e14+e10*e11*e04+e10*e01*e14+e10*e12*e05+e10*e02*e15+e13*e14*e04+e13*e15*e05+e06*e13*e16+e06*e15*e18+e06*e14*e17+e16*e14*e07+e16*e04*e17+e16*e15*e08+e16*e05*e18-e13*e12*e02-e13*e17*e07-e13*e18*e08+0.5*e102*e03+1.5*e03*e132+0.5*e03*e152+0.5*e03*e142+0.5*e03*e162-0.5*e03*e112-0.5*e03*e172-0.5*e03*e122-0.5*e03*e182; +A[1 + 10*3]=0.5*e102*e13+e10*e11*e14+e10*e12*e15+0.5*e133+0.5*e13*e152+0.5*e13*e142+0.5*e13*e162+e16*e15*e18+e16*e14*e17-0.5*e13*e112-0.5*e13*e122-0.5*e13*e172-0.5*e13*e182; +A[1 + 10*4]=-e03*e28*e08-e03*e27*e07-e03*e21*e01-e03*e22*e02+e26*e05*e08+e26*e04*e07+e06*e05*e28+e06*e25*e08+e06*e04*e27+e06*e24*e07+e03*e25*e05+e03*e24*e04+e20*e02*e05+e20*e01*e04+e00*e02*e25+e00*e22*e05+e00*e01*e24+e00*e21*e04+e00*e20*e03-0.5*e23*e072-0.5*e23*e082-0.5*e23*e022-0.5*e23*e012+e06*e03*e26+0.5*e23*e052+0.5*e23*e062+1.5*e23*e032+0.5*e23*e042+0.5*e002*e23; +A[1 + 10*5]=e00*e21*e14+e00*e11*e24+e00*e10*e23+e00*e22*e15+e00*e12*e25+e20*e12*e05+e20*e01*e14+e20*e11*e04+e00*e20*e13+e10*e02*e25+e10*e22*e05+e10*e01*e24+e10*e21*e04+e10*e20*e03+e23*e15*e05+e23*e14*e04+e13*e25*e05+e13*e24*e04+e03*e24*e14+e03*e25*e15+3*e03*e23*e13+e20*e02*e15+e16*e03*e26+e06*e14*e27-e23*e18*e08+e06*e24*e17+e06*e15*e28+e06*e25*e18+e06*e13*e26+e06*e23*e16+e26*e04*e17+e26*e14*e07+e16*e05*e28+e16*e25*e08+e16*e04*e27+e16*e24*e07-e03*e22*e12-e03*e21*e11+e26*e05*e18+e26*e15*e08-e03*e27*e17-e03*e28*e18-e13*e22*e02-e13*e28*e08-e13*e27*e07-e13*e21*e01-e23*e17*e07-e23*e11*e01-e23*e12*e02; +A[1 + 10*6]=-0.5*e23*e182-0.5*e23*e172-0.5*e23*e112-0.5*e23*e122-e13*e22*e12-e13*e27*e17-e13*e28*e18+e26*e15*e18+e26*e14*e17-e13*e21*e11+e20*e12*e15+e13*e25*e15+e13*e24*e14+e16*e13*e26+e16*e25*e18+e16*e15*e28+e16*e24*e17+e16*e14*e27+1.5*e23*e132+0.5*e23*e152+0.5*e23*e142+0.5*e23*e162+e10*e20*e13+e10*e21*e14+e10*e11*e24+e10*e22*e15+e10*e12*e25+e20*e11*e14+0.5*e102*e23; +A[1 + 10*7]=e26*e04*e27+e00*e22*e25-e23*e28*e08+0.5*e03*e262-0.5*e03*e212-0.5*e03*e272-0.5*e03*e222-0.5*e03*e282+e23*e24*e04+e23*e25*e05+0.5*e202*e03+e06*e23*e26+e06*e24*e27+e06*e25*e28+e26*e24*e07+e26*e25*e08+e26*e05*e28-e23*e22*e02-e23*e21*e01-e23*e27*e07+e00*e20*e23+e00*e21*e24+e20*e21*e04+e20*e01*e24+e20*e22*e05+e20*e02*e25+1.5*e03*e232+0.5*e03*e242+0.5*e03*e252; +A[1 + 10*8]=e20*e11*e24-0.5*e13*e212-0.5*e13*e272-0.5*e13*e222-0.5*e13*e282-e23*e27*e17-e23*e28*e18+e26*e25*e18+e26*e24*e17+e26*e14*e27-e23*e21*e11-e23*e22*e12+e26*e15*e28+e23*e25*e15+e23*e24*e14+e16*e23*e26+e16*e24*e27+e16*e25*e28+0.5*e13*e262+e20*e21*e14+e20*e22*e15+e20*e12*e25+0.5*e13*e242+0.5*e13*e252+0.5*e202*e13+1.5*e13*e232+e10*e20*e23+e10*e22*e25+e10*e21*e24; +A[1 + 10*9]=0.5*e202*e23+e20*e22*e25+e20*e21*e24+0.5*e233+0.5*e23*e242+0.5*e23*e252+0.5*e23*e262+e26*e24*e27+e26*e25*e28-0.5*e23*e212-0.5*e23*e272-0.5*e23*e222-0.5*e23*e282; +A[1 + 10*10]=e00*e30*e03+0.5*e33*e062-0.5*e33*e012-0.5*e33*e022-0.5*e33*e072+e03*e35*e05+e06*e03*e36+e06*e34*e07+e06*e04*e37+e06*e35*e08+e06*e05*e38+e36*e04*e07+e36*e05*e08-e03*e32*e02-e03*e31*e01-e03*e37*e07+e00*e31*e04+e00*e01*e34+e00*e32*e05+e00*e02*e35+e30*e01*e04+e30*e02*e05+e03*e34*e04-e03*e38*e08+0.5*e002*e33+1.5*e33*e032+0.5*e33*e042+0.5*e33*e052-0.5*e33*e082; +A[1 + 10*11]=e06*e35*e18+e06*e33*e16+e00*e30*e13+e00*e10*e33+e00*e31*e14+e00*e11*e34+e00*e32*e15+e00*e12*e35+e10*e30*e03-e33*e17*e07-e33*e18*e08+e10*e31*e04+e10*e01*e34+e10*e32*e05+e10*e02*e35+e30*e11*e04+e30*e01*e14+e30*e12*e05+e30*e02*e15+3*e03*e33*e13+e03*e35*e15+e03*e34*e14+e13*e34*e04+e13*e35*e05+e33*e14*e04+e33*e15*e05+e06*e13*e36+e06*e15*e38+e06*e34*e17+e06*e14*e37+e16*e03*e36+e16*e34*e07+e16*e04*e37+e16*e35*e08+e16*e05*e38+e36*e14*e07+e36*e04*e17+e36*e15*e08+e36*e05*e18-e03*e31*e11-e03*e32*e12-e03*e37*e17-e03*e38*e18-e13*e32*e02-e13*e31*e01-e13*e37*e07-e13*e38*e08-e33*e12*e02-e33*e11*e01; +A[1 + 10*12]=e16*e13*e36+e10*e11*e34+0.5*e33*e152+0.5*e33*e142+0.5*e33*e162-0.5*e33*e112-0.5*e33*e122-0.5*e33*e172-0.5*e33*e182+0.5*e102*e33+1.5*e33*e132+e10*e30*e13+e10*e31*e14+e10*e32*e15+e10*e12*e35+e30*e11*e14+e30*e12*e15+e13*e35*e15+e13*e34*e14+e16*e35*e18+e16*e15*e38+e16*e34*e17+e16*e14*e37+e36*e15*e18+e36*e14*e17-e13*e31*e11-e13*e32*e12-e13*e37*e17-e13*e38*e18; +A[1 + 10*13]=e06*e35*e28+e36*e04*e27+e00*e20*e33+e00*e30*e23+3*e03*e33*e23+e03*e34*e24+e03*e35*e25+e23*e34*e04+e23*e35*e05+e33*e24*e04+e33*e25*e05+e06*e33*e26+e06*e23*e36+e06*e34*e27+e06*e24*e37+e06*e25*e38+e26*e03*e36+e26*e34*e07+e26*e04*e37+e26*e35*e08+e26*e05*e38+e36*e24*e07+e36*e25*e08+e36*e05*e28-e03*e31*e21-e03*e37*e27-e03*e32*e22-e03*e38*e28-e23*e32*e02-e23*e31*e01-e23*e37*e07-e23*e38*e08-e33*e22*e02-e33*e21*e01-e33*e27*e07-e33*e28*e08+e00*e32*e25+e00*e22*e35+e00*e31*e24+e00*e21*e34+e20*e30*e03+e20*e31*e04+e20*e01*e34+e20*e32*e05+e20*e02*e35+e30*e21*e04+e30*e01*e24+e30*e22*e05+e30*e02*e25; +A[1 + 10*14]=e10*e30*e23+e10*e20*e33+e10*e22*e35+e10*e32*e25+e10*e31*e24+e10*e21*e34+e20*e30*e13+e20*e31*e14+e20*e11*e34+e20*e32*e15+e20*e12*e35+e30*e21*e14+e30*e11*e24+e30*e22*e15+e30*e12*e25+3*e13*e33*e23+e13*e34*e24+e13*e35*e25+e23*e35*e15+e23*e34*e14+e33*e25*e15+e33*e24*e14+e16*e33*e26+e16*e23*e36+e16*e34*e27+e16*e24*e37+e16*e35*e28+e16*e25*e38+e26*e13*e36+e26*e35*e18+e26*e15*e38+e26*e34*e17+e26*e14*e37+e36*e25*e18+e36*e15*e28+e36*e24*e17+e36*e14*e27-e13*e31*e21-e13*e37*e27-e13*e32*e22-e13*e38*e28-e23*e31*e11-e23*e32*e12-e23*e37*e17-e23*e38*e18-e33*e21*e11-e33*e22*e12-e33*e27*e17-e33*e28*e18; +A[1 + 10*15]=-0.5*e33*e212-0.5*e33*e272-0.5*e33*e222-0.5*e33*e282+e26*e23*e36+e20*e30*e23+e20*e32*e25+e20*e22*e35+e20*e31*e24+e20*e21*e34+e30*e22*e25+e30*e21*e24+e23*e34*e24+e23*e35*e25+e26*e34*e27+e26*e24*e37+e26*e35*e28+e26*e25*e38+e36*e24*e27+e36*e25*e28-e23*e31*e21-e23*e37*e27-e23*e32*e22-e23*e38*e28+0.5*e202*e33+1.5*e33*e232+0.5*e33*e242+0.5*e33*e252+0.5*e33*e262; +A[1 + 10*16]=e33*e35*e05+e30*e32*e05+0.5*e03*e362+0.5*e302*e03+1.5*e03*e332+0.5*e03*e352+0.5*e03*e342+e00*e30*e33+e00*e31*e34+e00*e32*e35+e30*e31*e04+e30*e01*e34+e30*e02*e35+e33*e34*e04+e06*e33*e36+e06*e35*e38+e06*e34*e37+e36*e34*e07+e36*e04*e37+e36*e35*e08+e36*e05*e38-e33*e32*e02-e33*e31*e01-e33*e37*e07-e33*e38*e08-0.5*e03*e322-0.5*e03*e382-0.5*e03*e312-0.5*e03*e372; +A[1 + 10*17]=-e33*e31*e11-e33*e32*e12-e33*e38*e18+e30*e11*e34+e30*e32*e15+e30*e12*e35+e33*e35*e15+e33*e34*e14+e16*e33*e36+e16*e35*e38+e16*e34*e37+e36*e35*e18+e36*e15*e38+e36*e34*e17+e36*e14*e37-e33*e37*e17+0.5*e302*e13+1.5*e13*e332+0.5*e13*e352+0.5*e13*e342+0.5*e13*e362-0.5*e13*e322-0.5*e13*e382-0.5*e13*e312-0.5*e13*e372+e10*e30*e33+e10*e31*e34+e10*e32*e35+e30*e31*e14; +A[1 + 10*18]=e36*e25*e38+0.5*e302*e23+1.5*e23*e332+0.5*e23*e352+0.5*e23*e342+0.5*e23*e362-0.5*e23*e322-0.5*e23*e382-0.5*e23*e312-0.5*e23*e372+e20*e30*e33+e20*e31*e34+e20*e32*e35+e30*e32*e25+e30*e22*e35+e30*e31*e24+e30*e21*e34+e33*e34*e24+e33*e35*e25+e26*e33*e36+e26*e35*e38+e26*e34*e37+e36*e34*e27+e36*e24*e37+e36*e35*e28-e33*e31*e21-e33*e37*e27-e33*e32*e22-e33*e38*e28; +A[1 + 10*19]=0.5*e302*e33+e30*e31*e34+e30*e32*e35+0.5*e333+0.5*e33*e352+0.5*e33*e342+0.5*e33*e362+e36*e35*e38+e36*e34*e37-0.5*e33*e322-0.5*e33*e382-0.5*e33*e312-0.5*e33*e372; +A[2 + 10*0]=0.5*e002*e06+e00*e01*e07+e00*e02*e08+0.5*e032*e06+e03*e04*e07+e03*e05*e08+0.5*e063+0.5*e06*e072+0.5*e06*e082-0.5*e06*e012-0.5*e06*e022-0.5*e06*e042-0.5*e06*e052; +A[2 + 10*1]=e00*e10*e06+0.5*e002*e16+0.5*e032*e16+1.5*e16*e062+0.5*e16*e072+0.5*e16*e082-0.5*e16*e012-0.5*e16*e022-0.5*e16*e042-0.5*e16*e052+e00*e11*e07+e00*e01*e17+e00*e12*e08+e00*e02*e18+e10*e01*e07+e10*e02*e08+e03*e13*e06+e03*e14*e07+e03*e04*e17+e03*e15*e08+e03*e05*e18+e13*e04*e07+e13*e05*e08+e06*e17*e07+e06*e18*e08-e06*e12*e02-e06*e11*e01-e06*e14*e04-e06*e15*e05; +A[2 + 10*2]=e13*e14*e07+0.5*e102*e06+e00*e10*e16+e00*e12*e18+e00*e11*e17+e10*e11*e07+e10*e01*e17+e10*e12*e08+e10*e02*e18+e03*e13*e16+e03*e15*e18+e03*e14*e17+e13*e04*e17+e13*e15*e08+e13*e05*e18+e16*e17*e07+e16*e18*e08-e16*e12*e02-e16*e11*e01-e16*e14*e04-e16*e15*e05+0.5*e132*e06+1.5*e06*e162+0.5*e06*e182+0.5*e06*e172-0.5*e06*e112-0.5*e06*e122-0.5*e06*e142-0.5*e06*e152; +A[2 + 10*3]=0.5*e102*e16+e10*e12*e18+e10*e11*e17+0.5*e132*e16+e13*e15*e18+e13*e14*e17+0.5*e163+0.5*e16*e182+0.5*e16*e172-0.5*e16*e112-0.5*e16*e122-0.5*e16*e142-0.5*e16*e152; +A[2 + 10*4]=e06*e27*e07+e23*e05*e08+e23*e04*e07+e03*e05*e28+e03*e25*e08+e03*e04*e27+e03*e24*e07+e20*e02*e08+e20*e01*e07+e00*e02*e28+e00*e22*e08+e00*e01*e27+e00*e21*e07+e00*e20*e06-e06*e25*e05-e06*e24*e04-e06*e21*e01-e06*e22*e02+e06*e28*e08-0.5*e26*e042-0.5*e26*e052-0.5*e26*e012-0.5*e26*e022+0.5*e26*e082+0.5*e26*e072+1.5*e26*e062+0.5*e002*e26+e03*e23*e06+0.5*e032*e26; +A[2 + 10*5]=e13*e05*e28+e00*e12*e28+e13*e25*e08+e13*e04*e27+e13*e24*e07+e13*e23*e06+e03*e14*e27+e03*e24*e17+e03*e15*e28+e03*e25*e18+e03*e13*e26+e03*e23*e16+e20*e02*e18+e20*e12*e08+e20*e01*e17+e20*e11*e07+e00*e21*e17+e10*e02*e28+e10*e22*e08+e10*e01*e27+e10*e21*e07+e10*e20*e06+e00*e11*e27-e26*e15*e05-e26*e14*e04-e26*e11*e01-e26*e12*e02-e16*e25*e05-e16*e24*e04-e16*e21*e01-e16*e22*e02-e06*e24*e14-e06*e22*e12-e06*e21*e11-e06*e25*e15+e00*e20*e16+e00*e22*e18+e00*e10*e26+e26*e18*e08+e26*e17*e07+e16*e28*e08+e16*e27*e07+e06*e27*e17+e06*e28*e18+3*e06*e26*e16+e23*e05*e18+e23*e15*e08+e23*e04*e17+e23*e14*e07; +A[2 + 10*6]=e10*e22*e18+0.5*e26*e182+0.5*e26*e172+e16*e28*e18+e16*e27*e17-e16*e25*e15-e16*e21*e11-e16*e22*e12+1.5*e26*e162+e13*e15*e28+e13*e24*e17+e13*e14*e27+e23*e15*e18+e23*e14*e17+e10*e12*e28+e10*e21*e17+e10*e11*e27+e20*e12*e18+e20*e11*e17+e13*e23*e16+e13*e25*e18+e10*e20*e16+0.5*e102*e26-0.5*e26*e122-0.5*e26*e142-0.5*e26*e152-e16*e24*e14-0.5*e26*e112+0.5*e132*e26; +A[2 + 10*7]=-0.5*e06*e212-0.5*e06*e252-0.5*e06*e242+0.5*e06*e272+0.5*e06*e282-0.5*e06*e222+e20*e02*e28+e03*e23*e26+e03*e24*e27+e03*e25*e28+e23*e24*e07+e23*e04*e27+e23*e25*e08+e23*e05*e28+e26*e28*e08-e26*e22*e02-e26*e21*e01-e26*e24*e04-e26*e25*e05+e26*e27*e07+e00*e20*e26+e00*e21*e27+e00*e22*e28+e20*e21*e07+e20*e01*e27+e20*e22*e08+0.5*e202*e06+0.5*e232*e06+1.5*e06*e262; +A[2 + 10*8]=-e26*e24*e14-0.5*e16*e212-0.5*e16*e252-0.5*e16*e242-e26*e25*e15-0.5*e16*e222-e26*e21*e11+e26*e28*e18+e26*e27*e17-e26*e22*e12+e23*e15*e28+e23*e24*e17+e23*e14*e27+0.5*e232*e16+1.5*e16*e262+0.5*e16*e272+0.5*e16*e282+e10*e20*e26+e10*e21*e27+e10*e22*e28+e20*e22*e18+e20*e12*e28+e20*e21*e17+e20*e11*e27+e13*e23*e26+e13*e24*e27+e13*e25*e28+e23*e25*e18+0.5*e202*e16; +A[2 + 10*9]=0.5*e202*e26+e20*e21*e27+e20*e22*e28+0.5*e232*e26+e23*e24*e27+e23*e25*e28+0.5*e263+0.5*e26*e272+0.5*e26*e282-0.5*e26*e222-0.5*e26*e212-0.5*e26*e252-0.5*e26*e242; +A[2 + 10*10]=e03*e34*e07+0.5*e032*e36+1.5*e36*e062+e03*e33*e06+e00*e31*e07+e00*e01*e37+e00*e32*e08+e00*e02*e38+e30*e01*e07+e30*e02*e08+e03*e04*e37+e03*e35*e08+e03*e05*e38+0.5*e002*e36-0.5*e36*e022-0.5*e36*e042-0.5*e36*e052+0.5*e36*e072+0.5*e36*e082-0.5*e36*e012+e33*e04*e07+e33*e05*e08+e06*e37*e07+e06*e38*e08-e06*e32*e02-e06*e31*e01-e06*e34*e04-e06*e35*e05+e00*e30*e06; +A[2 + 10*11]=e13*e33*e06+e13*e34*e07+e13*e04*e37+e13*e35*e08+e13*e05*e38+e33*e14*e07+e33*e04*e17+e33*e15*e08+e33*e05*e18+3*e06*e36*e16+e06*e38*e18+e06*e37*e17+e16*e37*e07+e16*e38*e08+e36*e17*e07+e36*e18*e08-e06*e35*e15-e06*e31*e11-e06*e32*e12+e00*e31*e17+e00*e11*e37+e10*e30*e06+e10*e31*e07+e10*e01*e37+e10*e32*e08+e10*e02*e38+e30*e11*e07+e30*e01*e17+e30*e12*e08+e30*e02*e18+e03*e33*e16+e03*e13*e36+e03*e35*e18+e03*e15*e38+e03*e34*e17+e03*e14*e37+e00*e30*e16+e00*e12*e38-e06*e34*e14-e16*e32*e02-e16*e31*e01-e16*e34*e04-e16*e35*e05-e36*e12*e02-e36*e11*e01-e36*e14*e04-e36*e15*e05+e00*e10*e36+e00*e32*e18; +A[2 + 10*12]=0.5*e36*e182+0.5*e36*e172-0.5*e36*e112-0.5*e36*e122-0.5*e36*e142-0.5*e36*e152+0.5*e102*e36+0.5*e132*e36+1.5*e36*e162+e10*e30*e16+e10*e32*e18+e10*e12*e38+e10*e31*e17+e10*e11*e37+e30*e12*e18+e30*e11*e17+e13*e33*e16+e13*e35*e18+e13*e15*e38+e13*e34*e17+e13*e14*e37+e33*e15*e18+e33*e14*e17+e16*e38*e18+e16*e37*e17-e16*e35*e15-e16*e31*e11-e16*e32*e12-e16*e34*e14; +A[2 + 10*13]=e00*e20*e36+e00*e31*e27+e00*e21*e37+e00*e32*e28+e00*e22*e38+e20*e30*e06+e20*e31*e07+e20*e01*e37+e20*e32*e08+e20*e02*e38+e30*e21*e07+e30*e01*e27+e30*e22*e08+e30*e02*e28+e03*e33*e26+e03*e23*e36+e03*e34*e27+e03*e24*e37+e03*e35*e28-e26*e31*e01-e26*e35*e05-e36*e22*e02-e36*e21*e01-e36*e24*e04-e36*e25*e05-e26*e34*e04+e03*e25*e38+e23*e34*e07+e23*e04*e37+e23*e35*e08+e23*e05*e38+e33*e24*e07+e33*e04*e27+e33*e25*e08+e33*e05*e28+3*e06*e36*e26+e06*e37*e27+e06*e38*e28+e26*e37*e07+e26*e38*e08+e36*e27*e07+e36*e28*e08-e06*e32*e22-e06*e31*e21-e06*e35*e25-e06*e34*e24-e26*e32*e02+e00*e30*e26+e23*e33*e06; +A[2 + 10*14]=e10*e30*e26+e10*e20*e36+e10*e31*e27+e10*e21*e37+e10*e32*e28+e10*e22*e38+e20*e30*e16+e20*e32*e18+e20*e12*e38+e20*e31*e17+e20*e11*e37+e30*e22*e18+e30*e12*e28+e30*e21*e17+e30*e11*e27+e13*e33*e26+e13*e23*e36+e13*e34*e27+e13*e24*e37+e13*e35*e28+e13*e25*e38+e23*e33*e16+e23*e35*e18+e23*e15*e38+e23*e34*e17+e23*e14*e37+e33*e25*e18+e33*e15*e28+e33*e24*e17+e33*e14*e27+3*e16*e36*e26+e16*e37*e27+e16*e38*e28+e26*e38*e18+e26*e37*e17+e36*e28*e18+e36*e27*e17-e16*e32*e22-e16*e31*e21-e16*e35*e25-e16*e34*e24-e26*e35*e15-e26*e31*e11-e26*e32*e12-e26*e34*e14-e36*e25*e15-e36*e21*e11-e36*e22*e12-e36*e24*e14; +A[2 + 10*15]=e33*e25*e28+e20*e30*e26+e20*e32*e28+e20*e31*e27+e20*e21*e37+e20*e22*e38+e30*e21*e27+e30*e22*e28+e23*e33*e26+e23*e34*e27+e23*e24*e37+e23*e35*e28+e23*e25*e38+e33*e24*e27+e26*e37*e27+e26*e38*e28-e26*e32*e22-e26*e31*e21-e26*e35*e25-e26*e34*e24+0.5*e202*e36+0.5*e232*e36+1.5*e36*e262+0.5*e36*e272+0.5*e36*e282-0.5*e36*e222-0.5*e36*e212-0.5*e36*e252-0.5*e36*e242; +A[2 + 10*16]=e00*e30*e36+e00*e32*e38+e00*e31*e37+e30*e31*e07+e30*e01*e37+e30*e32*e08+e30*e02*e38+e03*e33*e36-0.5*e06*e342+e03*e35*e38+e33*e34*e07+e33*e04*e37+e33*e35*e08+e33*e05*e38+e36*e37*e07+e36*e38*e08-e36*e32*e02-e36*e31*e01-e36*e34*e04-e36*e35*e05+e03*e34*e37+0.5*e302*e06+0.5*e332*e06+1.5*e06*e362+0.5*e06*e382+0.5*e06*e372-0.5*e06*e352-0.5*e06*e312-0.5*e06*e322; +A[2 + 10*17]=-e36*e35*e15+e10*e30*e36+0.5*e302*e16+0.5*e332*e16+1.5*e16*e362+0.5*e16*e382+0.5*e16*e372-0.5*e16*e352-0.5*e16*e312-0.5*e16*e322-0.5*e16*e342+e10*e32*e38+e10*e31*e37+e30*e32*e18+e30*e12*e38+e30*e31*e17+e30*e11*e37+e13*e33*e36+e13*e35*e38+e13*e34*e37+e33*e35*e18+e33*e15*e38+e33*e34*e17+e33*e14*e37+e36*e38*e18+e36*e37*e17-e36*e31*e11-e36*e32*e12-e36*e34*e14; +A[2 + 10*18]=-e36*e35*e25+e30*e32*e28+0.5*e302*e26+0.5*e332*e26+1.5*e26*e362+0.5*e26*e382+0.5*e26*e372-0.5*e26*e352-0.5*e26*e312-0.5*e26*e322-0.5*e26*e342+e20*e30*e36+e20*e32*e38+e20*e31*e37+e30*e31*e27+e30*e21*e37+e30*e22*e38+e23*e33*e36+e23*e35*e38+e23*e34*e37+e33*e34*e27+e33*e24*e37+e33*e35*e28+e33*e25*e38+e36*e37*e27+e36*e38*e28-e36*e32*e22-e36*e31*e21-e36*e34*e24; +A[2 + 10*19]=0.5*e302*e36+e30*e32*e38+e30*e31*e37+0.5*e332*e36+e33*e35*e38+e33*e34*e37+0.5*e363+0.5*e36*e382+0.5*e36*e372-0.5*e36*e352-0.5*e36*e312-0.5*e36*e322-0.5*e36*e342; +A[3 + 10*0]=0.5*e01*e002+0.5*e013+0.5*e01*e022+e04*e00*e03+0.5*e01*e042+e04*e02*e05+e07*e00*e06+0.5*e01*e072+e07*e02*e08-0.5*e01*e032-0.5*e01*e052-0.5*e01*e062-0.5*e01*e082; +A[3 + 10*1]=1.5*e11*e012+0.5*e11*e002+0.5*e11*e022+0.5*e11*e042+0.5*e11*e072-0.5*e11*e032-0.5*e11*e052-0.5*e11*e062-0.5*e11*e082+e01*e10*e00+e01*e12*e02+e04*e10*e03+e04*e00*e13+e04*e01*e14+e04*e12*e05+e04*e02*e15+e14*e00*e03+e14*e02*e05+e07*e10*e06+e07*e00*e16+e07*e01*e17+e07*e12*e08+e07*e02*e18+e17*e00*e06+e17*e02*e08-e01*e13*e03-e01*e16*e06-e01*e15*e05-e01*e18*e08; +A[3 + 10*2]=e17*e02*e18+e14*e10*e03+e11*e12*e02-e11*e18*e08+0.5*e01*e102+0.5*e01*e122+1.5*e01*e112+0.5*e01*e142+0.5*e01*e172-0.5*e01*e132-0.5*e01*e152-0.5*e01*e162-0.5*e01*e182+e11*e10*e00+e04*e10*e13+e04*e12*e15+e04*e11*e14+e14*e00*e13+e14*e12*e05+e14*e02*e15+e07*e10*e16+e07*e12*e18+e07*e11*e17+e17*e10*e06+e17*e00*e16+e17*e12*e08-e11*e13*e03-e11*e16*e06-e11*e15*e05; +A[3 + 10*3]=0.5*e11*e102+0.5*e11*e122+0.5*e113+e14*e10*e13+e14*e12*e15+0.5*e11*e142+e17*e10*e16+e17*e12*e18+0.5*e11*e172-0.5*e11*e132-0.5*e11*e152-0.5*e11*e162-0.5*e11*e182; +A[3 + 10*4]=-e01*e25*e05-e01*e26*e06-e01*e23*e03+e27*e02*e08+e27*e00*e06+e07*e02*e28+e07*e22*e08+e07*e01*e27+e07*e00*e26+e24*e02*e05+e24*e00*e03+e04*e02*e25+e04*e22*e05+e04*e01*e24+e04*e00*e23+e04*e20*e03+e01*e22*e02+e01*e20*e00-e01*e28*e08+e07*e20*e06+0.5*e21*e072+0.5*e21*e042+0.5*e21*e022+0.5*e21*e002+1.5*e21*e012-0.5*e21*e082-0.5*e21*e052-0.5*e21*e062-0.5*e21*e032; +A[3 + 10*5]=e11*e20*e00+e07*e20*e16+3*e01*e21*e11+e01*e22*e12-e21*e18*e08-e21*e15*e05-e21*e16*e06-e21*e13*e03-e11*e28*e08-e11*e25*e05-e11*e26*e06-e11*e23*e03-e01*e28*e18-e01*e23*e13-e01*e25*e15-e01*e26*e16+e27*e02*e18+e27*e12*e08+e27*e00*e16+e27*e10*e06+e17*e02*e28+e17*e22*e08+e17*e01*e27+e17*e00*e26+e17*e20*e06+e07*e11*e27+e07*e21*e17+e07*e12*e28+e07*e22*e18+e07*e10*e26+e24*e02*e15+e24*e12*e05+e24*e00*e13+e24*e10*e03+e14*e02*e25+e14*e22*e05+e14*e01*e24+e14*e00*e23+e14*e20*e03+e04*e11*e24+e04*e21*e14+e04*e12*e25+e04*e22*e15+e21*e12*e02+e04*e20*e13+e01*e20*e10+e11*e22*e02+e21*e10*e00+e04*e10*e23; +A[3 + 10*6]=1.5*e21*e112+0.5*e21*e102+0.5*e21*e122+e11*e20*e10+e11*e22*e12+e14*e10*e23+e14*e22*e15+e14*e12*e25-0.5*e21*e162-0.5*e21*e152-0.5*e21*e132-0.5*e21*e182+e27*e12*e18-e11*e26*e16-e11*e25*e15-e11*e23*e13-e11*e28*e18+e17*e20*e16+e17*e10*e26+e17*e22*e18+e17*e12*e28+e17*e11*e27+e27*e10*e16+0.5*e21*e172+e14*e11*e24+e24*e10*e13+e24*e12*e15+0.5*e21*e142+e14*e20*e13; +A[3 + 10*7]=-0.5*e01*e262-0.5*e01*e282-0.5*e01*e252-0.5*e01*e232+0.5*e01*e272+e27*e22*e08+e27*e02*e28-e21*e23*e03-e21*e26*e06-e21*e25*e05-e21*e28*e08+e04*e22*e25+e24*e20*e03+e24*e00*e23+e24*e22*e05+e24*e02*e25+e07*e20*e26+e07*e21*e27+e07*e22*e28+e27*e20*e06+e27*e00*e26+e21*e20*e00+e21*e22*e02+e04*e20*e23+e04*e21*e24+0.5*e01*e222+0.5*e01*e242+1.5*e01*e212+0.5*e01*e202; +A[3 + 10*8]=-0.5*e11*e282-0.5*e11*e252-e21*e26*e16+e27*e12*e28-e21*e25*e15-e21*e23*e13-e21*e28*e18+e17*e20*e26+e17*e21*e27+e17*e22*e28+e27*e20*e16+e27*e10*e26+e27*e22*e18+0.5*e11*e242+0.5*e11*e272-0.5*e11*e232-0.5*e11*e262+0.5*e11*e202+1.5*e11*e212+0.5*e11*e222+e21*e20*e10+e14*e20*e23+e14*e21*e24+e14*e22*e25+e24*e20*e13+e24*e10*e23+e24*e22*e15+e24*e12*e25+e21*e22*e12; +A[3 + 10*9]=0.5*e21*e202+0.5*e213+0.5*e21*e222+e24*e20*e23+0.5*e21*e242+e24*e22*e25+e27*e20*e26+0.5*e21*e272+e27*e22*e28-0.5*e21*e232-0.5*e21*e262-0.5*e21*e282-0.5*e21*e252; +A[3 + 10*10]=-0.5*e31*e032-0.5*e31*e052-0.5*e31*e062-0.5*e31*e082+e07*e30*e06+e07*e00*e36+e07*e01*e37+e07*e32*e08+e07*e02*e38+e37*e00*e06+e37*e02*e08-e01*e33*e03-e01*e36*e06-e01*e35*e05-e01*e38*e08+0.5*e31*e072+e04*e30*e03+e04*e00*e33+e04*e01*e34+e04*e32*e05+e04*e02*e35+e34*e00*e03+e34*e02*e05+0.5*e31*e002+0.5*e31*e022+0.5*e31*e042+e01*e30*e00+e01*e32*e02+1.5*e31*e012; +A[3 + 10*11]=e34*e12*e05+e34*e02*e15+e07*e10*e36+e07*e32*e18+e07*e12*e38+e07*e31*e17+e07*e11*e37+e17*e30*e06+e17*e00*e36+e17*e01*e37+e17*e32*e08+e17*e02*e38+e37*e10*e06+e37*e00*e16+e37*e12*e08+e37*e02*e18-e01*e36*e16-e01*e35*e15-e01*e33*e13-e01*e38*e18-e11*e33*e03-e11*e36*e06-e11*e35*e05+e01*e30*e10+e01*e32*e12+3*e01*e31*e11+e11*e30*e00+e11*e32*e02+e31*e10*e00+e31*e12*e02+e04*e30*e13+e04*e10*e33+e04*e32*e15+e04*e12*e35+e04*e31*e14+e04*e11*e34+e14*e30*e03+e14*e00*e33+e14*e01*e34+e14*e32*e05+e14*e02*e35+e34*e10*e03+e34*e00*e13+e07*e30*e16-e11*e38*e08-e31*e13*e03-e31*e16*e06-e31*e15*e05-e31*e18*e08; +A[3 + 10*12]=-e11*e33*e13-e11*e38*e18+0.5*e31*e142+0.5*e31*e172-0.5*e31*e162-0.5*e31*e152-0.5*e31*e132-0.5*e31*e182+0.5*e31*e122+0.5*e31*e102+e11*e30*e10+e11*e32*e12+e14*e30*e13+e14*e10*e33+e14*e32*e15+e14*e12*e35+e14*e11*e34+e34*e10*e13+e34*e12*e15+e17*e30*e16+e17*e10*e36+e17*e32*e18+e17*e12*e38+e17*e11*e37+e37*e10*e16+e37*e12*e18-e11*e36*e16-e11*e35*e15+1.5*e31*e112; +A[3 + 10*13]=-e21*e35*e05+e07*e32*e28+e01*e30*e20-e21*e33*e03-e21*e36*e06-e21*e38*e08-e31*e23*e03-e31*e26*e06-e31*e25*e05-e31*e28*e08+3*e01*e31*e21+e01*e32*e22+e21*e30*e00+e21*e32*e02+e31*e20*e00+e31*e22*e02+e04*e30*e23+e04*e20*e33+e04*e31*e24+e04*e21*e34+e04*e32*e25+e04*e22*e35+e24*e30*e03+e24*e00*e33+e24*e01*e34+e24*e32*e05+e24*e02*e35+e34*e20*e03+e34*e00*e23+e34*e22*e05+e34*e02*e25+e07*e30*e26+e07*e20*e36+e07*e31*e27+e07*e21*e37+e07*e22*e38+e27*e30*e06+e27*e00*e36+e27*e01*e37+e27*e32*e08+e27*e02*e38+e37*e00*e26+e37*e22*e08+e37*e02*e28-e01*e33*e23-e01*e36*e26-e01*e38*e28-e01*e35*e25+e37*e20*e06; +A[3 + 10*14]=e11*e32*e22+e34*e12*e25+e11*e30*e20+3*e11*e31*e21+e21*e30*e10+e21*e32*e12+e34*e10*e23+e34*e22*e15+e17*e30*e26+e17*e20*e36+e17*e31*e27+e17*e21*e37+e17*e32*e28+e17*e22*e38+e27*e30*e16+e27*e10*e36+e27*e32*e18+e27*e12*e38+e27*e11*e37+e37*e20*e16+e37*e10*e26+e37*e22*e18+e37*e12*e28-e11*e33*e23-e11*e36*e26-e11*e38*e28-e11*e35*e25-e21*e36*e16-e21*e35*e15-e21*e33*e13-e21*e38*e18-e31*e26*e16-e31*e25*e15-e31*e23*e13-e31*e28*e18+e31*e20*e10+e31*e22*e12+e14*e30*e23+e14*e20*e33+e14*e31*e24+e14*e21*e34+e14*e32*e25+e14*e22*e35+e24*e30*e13+e24*e10*e33+e24*e32*e15+e24*e12*e35+e24*e11*e34+e34*e20*e13; +A[3 + 10*15]=-e21*e36*e26+e37*e22*e28-e21*e33*e23-e21*e38*e28-e21*e35*e25+0.5*e31*e222+0.5*e31*e242+0.5*e31*e272-0.5*e31*e232-0.5*e31*e262-0.5*e31*e282-0.5*e31*e252+e21*e30*e20+e21*e32*e22+e24*e30*e23+e24*e20*e33+e24*e21*e34+e24*e32*e25+e24*e22*e35+e34*e20*e23+e34*e22*e25+e27*e30*e26+e27*e20*e36+e27*e21*e37+e27*e32*e28+e27*e22*e38+e37*e20*e26+1.5*e31*e212+0.5*e31*e202; +A[3 + 10*16]=e04*e32*e35+0.5*e01*e372-0.5*e01*e352-0.5*e01*e362-0.5*e01*e332-0.5*e01*e382+e04*e31*e34+e34*e30*e03+e34*e00*e33+e34*e32*e05+e34*e02*e35+e07*e30*e36+e07*e32*e38+e07*e31*e37+e37*e30*e06+e37*e00*e36+e37*e32*e08+e04*e30*e33+e37*e02*e38-e31*e33*e03-e31*e36*e06-e31*e35*e05-e31*e38*e08+0.5*e01*e302+0.5*e01*e322+1.5*e01*e312+0.5*e01*e342+e31*e30*e00+e31*e32*e02; +A[3 + 10*17]=e31*e32*e12+e14*e30*e33+e14*e32*e35+e14*e31*e34+e34*e30*e13+e34*e10*e33+e34*e32*e15+e34*e12*e35+e17*e30*e36+e17*e32*e38+e17*e31*e37+e37*e30*e16+e37*e10*e36+e37*e32*e18+e37*e12*e38-e31*e36*e16-e31*e35*e15+0.5*e11*e302+0.5*e11*e322+1.5*e11*e312-e31*e33*e13-e31*e38*e18+0.5*e11*e342+0.5*e11*e372+e31*e30*e10-0.5*e11*e352-0.5*e11*e362-0.5*e11*e332-0.5*e11*e382; +A[3 + 10*18]=e34*e32*e25+0.5*e21*e342+0.5*e21*e372-0.5*e21*e352-0.5*e21*e362-0.5*e21*e332-0.5*e21*e382+0.5*e21*e302+0.5*e21*e322+1.5*e21*e312+e31*e30*e20+e31*e32*e22+e24*e30*e33+e24*e32*e35+e24*e31*e34+e34*e30*e23+e34*e20*e33+e34*e22*e35+e27*e30*e36+e27*e32*e38+e27*e31*e37+e37*e30*e26+e37*e20*e36+e37*e32*e28+e37*e22*e38-e31*e33*e23-e31*e36*e26-e31*e38*e28-e31*e35*e25; +A[3 + 10*19]=0.5*e31*e302+0.5*e31*e322+0.5*e313+e34*e30*e33+e34*e32*e35+0.5*e31*e342+e37*e30*e36+e37*e32*e38+0.5*e31*e372-0.5*e31*e352-0.5*e31*e362-0.5*e31*e332-0.5*e31*e382; +A[4 + 10*0]=e01*e00*e03+0.5*e012*e04+e01*e02*e05+0.5*e04*e032+0.5*e043+0.5*e04*e052+e07*e03*e06+0.5*e04*e072+e07*e05*e08-0.5*e04*e002-0.5*e04*e022-0.5*e04*e062-0.5*e04*e082; +A[4 + 10*1]=e07*e13*e06+e01*e10*e03-0.5*e14*e002-0.5*e14*e022-0.5*e14*e062-0.5*e14*e082+e01*e00*e13+e01*e11*e04+e01*e12*e05+e01*e02*e15+e11*e00*e03+e11*e02*e05+e04*e13*e03+e04*e15*e05+e07*e03*e16+e07*e04*e17+e07*e15*e08+e07*e05*e18+e17*e03*e06+e17*e05*e08-e04*e10*e00-e04*e12*e02-e04*e16*e06-e04*e18*e08+0.5*e012*e14+1.5*e14*e042+0.5*e14*e032+0.5*e14*e052+0.5*e14*e072; +A[4 + 10*2]=e11*e10*e03+0.5*e112*e04+0.5*e04*e132+0.5*e04*e152+1.5*e04*e142+0.5*e04*e172-0.5*e04*e102-0.5*e04*e162-0.5*e04*e122-0.5*e04*e182+e01*e10*e13+e01*e12*e15+e01*e11*e14+e11*e00*e13+e11*e12*e05+e11*e02*e15+e14*e13*e03+e14*e15*e05+e07*e13*e16+e07*e15*e18+e07*e14*e17+e17*e13*e06+e17*e03*e16+e17*e15*e08+e17*e05*e18-e14*e10*e00-e14*e12*e02-e14*e16*e06-e14*e18*e08; +A[4 + 10*3]=e11*e10*e13+e11*e12*e15+0.5*e112*e14+0.5*e14*e132+0.5*e14*e152+0.5*e143+e17*e13*e16+e17*e15*e18+0.5*e14*e172-0.5*e14*e102-0.5*e14*e162-0.5*e14*e122-0.5*e14*e182; +A[4 + 10*4]=-e04*e28*e08-e04*e26*e06-e04*e22*e02-e04*e20*e00+e27*e05*e08+e27*e03*e06+e07*e05*e28+e07*e25*e08+e07*e04*e27+e07*e03*e26+e07*e23*e06+e04*e25*e05+e04*e23*e03+e21*e02*e05+e21*e00*e03+e01*e02*e25+e01*e22*e05+e01*e21*e04+e01*e00*e23+e01*e20*e03+0.5*e012*e24+0.5*e24*e072+0.5*e24*e052+0.5*e24*e032+1.5*e24*e042-0.5*e24*e022-0.5*e24*e002-0.5*e24*e082-0.5*e24*e062; +A[4 + 10*5]=e11*e02*e25+e11*e22*e05+e11*e21*e04-e24*e18*e08-e24*e16*e06-e24*e12*e02-e14*e28*e08-e14*e26*e06-e14*e22*e02-e14*e20*e00-e04*e28*e18-e04*e22*e12-e04*e26*e16-e04*e20*e10+e27*e05*e18+e27*e15*e08+e27*e03*e16+e27*e13*e06+e17*e05*e28+e17*e25*e08+e17*e04*e27+e17*e03*e26+e17*e23*e06+e07*e14*e27+e07*e24*e17+e07*e15*e28+e07*e25*e18+e07*e13*e26+e07*e23*e16+e24*e15*e05+e24*e13*e03+e14*e25*e05+e14*e23*e03+3*e04*e24*e14+e04*e25*e15+e04*e23*e13+e21*e02*e15+e21*e12*e05+e21*e00*e13+e21*e10*e03-e24*e10*e00+e01*e20*e13+e01*e10*e23+e01*e22*e15+e01*e12*e25+e01*e11*e24+e11*e20*e03+e11*e00*e23+e01*e21*e14; +A[4 + 10*6]=e11*e12*e25-0.5*e24*e182-0.5*e24*e102-0.5*e24*e162-0.5*e24*e122+e27*e13*e16+e27*e15*e18-e14*e20*e10-e14*e26*e16-e14*e22*e12-e14*e28*e18+e17*e15*e28+e17*e14*e27+1.5*e24*e142+0.5*e24*e132+0.5*e24*e152+0.5*e112*e24+0.5*e24*e172+e11*e21*e14+e11*e22*e15+e11*e10*e23+e11*e20*e13+e21*e10*e13+e21*e12*e15+e17*e13*e26+e17*e23*e16+e14*e25*e15+e14*e23*e13+e17*e25*e18; +A[4 + 10*7]=e27*e03*e26+e27*e25*e08+e27*e05*e28-e24*e20*e00-e24*e22*e02-e24*e26*e06-e24*e28*e08+0.5*e04*e232+1.5*e04*e242+0.5*e04*e252+0.5*e04*e272-0.5*e04*e202-0.5*e04*e222-0.5*e04*e262-0.5*e04*e282+e24*e23*e03+e24*e25*e05+e07*e23*e26+e07*e24*e27+e07*e25*e28+e27*e23*e06+e21*e20*e03+e21*e00*e23+e21*e22*e05+e21*e02*e25+0.5*e212*e04+e01*e20*e23+e01*e21*e24+e01*e22*e25; +A[4 + 10*8]=-e24*e22*e12-e24*e28*e18+0.5*e14*e272-0.5*e14*e202-0.5*e14*e222-0.5*e14*e262-0.5*e14*e282+e17*e23*e26+e17*e24*e27+e17*e25*e28+e27*e23*e16+e27*e13*e26+e27*e25*e18+e27*e15*e28-e24*e20*e10-e24*e26*e16+0.5*e14*e232+1.5*e14*e242+0.5*e14*e252+e21*e10*e23+e21*e22*e15+e21*e12*e25+e24*e23*e13+e24*e25*e15+e21*e20*e13+0.5*e212*e14+e11*e20*e23+e11*e22*e25+e11*e21*e24; +A[4 + 10*9]=e21*e20*e23+0.5*e212*e24+e21*e22*e25+0.5*e24*e232+0.5*e243+0.5*e24*e252+e27*e23*e26+0.5*e24*e272+e27*e25*e28-0.5*e24*e202-0.5*e24*e222-0.5*e24*e262-0.5*e24*e282; +A[4 + 10*10]=-e04*e38*e08-e04*e32*e02-e04*e36*e06-0.5*e34*e002-0.5*e34*e022-0.5*e34*e062-0.5*e34*e082+e37*e03*e06+e37*e05*e08-e04*e30*e00+0.5*e34*e032+0.5*e34*e052+0.5*e34*e072+1.5*e34*e042+e01*e30*e03+e01*e00*e33+e01*e31*e04+e01*e32*e05+e01*e02*e35+e31*e00*e03+e31*e02*e05+e04*e33*e03+e04*e35*e05+e07*e03*e36+e07*e04*e37+e07*e35*e08+e07*e05*e38+0.5*e012*e34+e07*e33*e06; +A[4 + 10*11]=e07*e13*e36+e01*e12*e35-e04*e30*e10+e17*e04*e37+e17*e35*e08+e17*e05*e38+e37*e13*e06+e37*e03*e16+e37*e15*e08+e37*e05*e18-e04*e36*e16+e17*e33*e06+e04*e33*e13+e04*e35*e15+3*e04*e34*e14+e14*e33*e03+e14*e35*e05+e34*e13*e03+e34*e15*e05+e07*e33*e16+e07*e35*e18+e07*e15*e38+e07*e34*e17+e07*e14*e37+e17*e03*e36+e31*e10*e03+e01*e30*e13+e01*e10*e33+e01*e32*e15+e01*e31*e14+e01*e11*e34+e11*e30*e03+e11*e00*e33+e11*e31*e04+e11*e32*e05+e11*e02*e35+e31*e00*e13+e31*e12*e05+e31*e02*e15-e34*e12*e02-e34*e16*e06-e34*e18*e08-e14*e32*e02-e14*e36*e06-e14*e38*e08-e34*e10*e00-e04*e32*e12-e04*e38*e18-e14*e30*e00; +A[4 + 10*12]=e11*e32*e15-0.5*e34*e102-0.5*e34*e162-0.5*e34*e122-0.5*e34*e182+e37*e13*e16+0.5*e112*e34+1.5*e34*e142+0.5*e34*e132+0.5*e34*e152+0.5*e34*e172+e11*e30*e13+e11*e10*e33+e11*e12*e35+e11*e31*e14+e31*e10*e13+e31*e12*e15+e14*e33*e13+e14*e35*e15+e17*e33*e16+e17*e13*e36+e17*e35*e18+e17*e15*e38+e17*e14*e37+e37*e15*e18-e14*e30*e10-e14*e36*e16-e14*e32*e12-e14*e38*e18; +A[4 + 10*13]=e01*e22*e35-e04*e30*e20-e04*e32*e22+e01*e31*e24+e01*e21*e34+e01*e32*e25+e21*e30*e03+e21*e00*e33+e21*e31*e04+e21*e32*e05+e21*e02*e35+e31*e20*e03+e31*e00*e23+e31*e22*e05+e31*e02*e25+e04*e33*e23+3*e04*e34*e24+e04*e35*e25+e24*e33*e03+e37*e05*e28-e04*e36*e26-e04*e38*e28-e24*e30*e00-e24*e32*e02-e24*e36*e06-e24*e38*e08+e24*e35*e05+e34*e23*e03+e34*e25*e05+e07*e33*e26+e07*e23*e36+e07*e34*e27+e07*e24*e37+e07*e35*e28+e07*e25*e38+e27*e33*e06+e27*e03*e36+e27*e04*e37+e27*e35*e08+e27*e05*e38+e37*e23*e06+e37*e03*e26+e37*e25*e08-e34*e20*e00-e34*e22*e02-e34*e26*e06-e34*e28*e08+e01*e30*e23+e01*e20*e33; +A[4 + 10*14]=e21*e10*e33+e11*e30*e23+e11*e20*e33+e11*e31*e24+e11*e21*e34+e11*e32*e25+e11*e22*e35+e21*e30*e13+e21*e32*e15+e21*e12*e35+e21*e31*e14+e31*e20*e13+e31*e10*e23+e31*e22*e15+e31*e12*e25+e14*e33*e23+3*e14*e34*e24+e14*e35*e25+e24*e33*e13+e24*e35*e15+e34*e23*e13+e34*e25*e15+e17*e33*e26+e17*e23*e36+e17*e34*e27+e17*e24*e37+e17*e35*e28+e17*e25*e38+e27*e33*e16+e27*e13*e36+e27*e35*e18+e27*e15*e38+e27*e14*e37+e37*e23*e16+e37*e13*e26+e37*e25*e18+e37*e15*e28-e34*e28*e18-e34*e22*e12-e14*e32*e22-e14*e36*e26-e14*e38*e28-e24*e30*e10-e24*e36*e16-e24*e32*e12-e24*e38*e18-e34*e20*e10-e34*e26*e16-e14*e30*e20; +A[4 + 10*15]=-0.5*e34*e202-0.5*e34*e222-0.5*e34*e262-0.5*e34*e282+e37*e25*e28-e24*e32*e22-e24*e36*e26-e24*e38*e28-e24*e30*e20+0.5*e212*e34+1.5*e34*e242+0.5*e34*e232+0.5*e34*e252+0.5*e34*e272+e21*e30*e23+e21*e20*e33+e21*e31*e24+e21*e32*e25+e21*e22*e35+e31*e20*e23+e31*e22*e25+e24*e33*e23+e24*e35*e25+e27*e33*e26+e27*e23*e36+e27*e24*e37+e27*e35*e28+e27*e25*e38+e37*e23*e26; +A[4 + 10*16]=e37*e33*e06+e01*e30*e33+e01*e31*e34+e31*e30*e03+e31*e02*e35+e34*e33*e03+e34*e35*e05+e07*e33*e36+e07*e35*e38+e07*e34*e37+e37*e03*e36+e37*e35*e08+e37*e05*e38-e34*e32*e02-e34*e36*e06-e34*e38*e08+e31*e32*e05+e31*e00*e33+0.5*e312*e04+0.5*e04*e332+0.5*e04*e352+1.5*e04*e342+0.5*e04*e372+e01*e32*e35-0.5*e04*e302-0.5*e04*e322-0.5*e04*e362-0.5*e04*e382-e34*e30*e00; +A[4 + 10*17]=0.5*e14*e372-0.5*e14*e302-0.5*e14*e322-0.5*e14*e362-0.5*e14*e382+0.5*e312*e14+0.5*e14*e332+0.5*e14*e352+1.5*e14*e342+e11*e30*e33+e11*e32*e35+e11*e31*e34+e31*e30*e13+e31*e10*e33+e31*e32*e15+e31*e12*e35+e34*e33*e13+e34*e35*e15+e17*e33*e36+e17*e35*e38+e17*e34*e37+e37*e33*e16+e37*e13*e36+e37*e35*e18+e37*e15*e38-e34*e30*e10-e34*e36*e16-e34*e32*e12-e34*e38*e18; +A[4 + 10*18]=-e34*e32*e22-e34*e36*e26-e34*e38*e28+0.5*e24*e332+0.5*e24*e352+1.5*e24*e342+0.5*e24*e372-0.5*e24*e302-0.5*e24*e322-0.5*e24*e362-0.5*e24*e382+e21*e30*e33+0.5*e312*e24+e21*e32*e35+e21*e31*e34+e31*e30*e23+e31*e20*e33+e31*e32*e25+e31*e22*e35+e34*e33*e23+e34*e35*e25+e27*e33*e36+e27*e35*e38+e27*e34*e37+e37*e33*e26+e37*e23*e36+e37*e35*e28+e37*e25*e38-e34*e30*e20; +A[4 + 10*19]=e31*e30*e33+e31*e32*e35+0.5*e312*e34+0.5*e34*e332+0.5*e34*e352+0.5*e343+e37*e33*e36+e37*e35*e38+0.5*e34*e372-0.5*e34*e302-0.5*e34*e322-0.5*e34*e362-0.5*e34*e382; +A[5 + 10*0]=e01*e00*e06+0.5*e012*e07+e01*e02*e08+e04*e03*e06+0.5*e042*e07+e04*e05*e08+0.5*e07*e062+0.5*e073+0.5*e07*e082-0.5*e07*e002-0.5*e07*e022-0.5*e07*e032-0.5*e07*e052; +A[5 + 10*1]=e04*e13*e06+0.5*e042*e17+1.5*e17*e072+0.5*e17*e062+0.5*e17*e082-0.5*e17*e002-0.5*e17*e022-0.5*e17*e032-0.5*e17*e052+e01*e10*e06+e07*e16*e06+e07*e18*e08-e07*e10*e00-e07*e12*e02-e07*e13*e03-e07*e15*e05+e01*e00*e16+e01*e11*e07+e01*e12*e08+e01*e02*e18+e11*e00*e06+e11*e02*e08+e04*e03*e16+e04*e14*e07+e04*e15*e08+e04*e05*e18+e14*e03*e06+e14*e05*e08+0.5*e012*e17; +A[5 + 10*2]=-e17*e10*e00+0.5*e112*e07+0.5*e142*e07+0.5*e07*e162+0.5*e07*e182+1.5*e07*e172-0.5*e07*e102-0.5*e07*e152-0.5*e07*e132-0.5*e07*e122+e01*e10*e16+e01*e12*e18+e01*e11*e17+e11*e10*e06+e11*e00*e16+e11*e12*e08+e11*e02*e18+e04*e13*e16+e04*e15*e18+e04*e14*e17+e14*e13*e06+e14*e03*e16+e14*e15*e08+e14*e05*e18+e17*e16*e06+e17*e18*e08-e17*e12*e02-e17*e13*e03-e17*e15*e05; +A[5 + 10*3]=e11*e10*e16+e11*e12*e18+0.5*e112*e17+e14*e13*e16+e14*e15*e18+0.5*e142*e17+0.5*e17*e162+0.5*e17*e182+0.5*e173-0.5*e17*e102-0.5*e17*e152-0.5*e17*e132-0.5*e17*e122; +A[5 + 10*4]=e01*e22*e08+e07*e28*e08-e07*e20*e00-e07*e23*e03-e07*e22*e02-e07*e25*e05+0.5*e012*e27+0.5*e042*e27+1.5*e27*e072+0.5*e27*e062+0.5*e27*e082-0.5*e27*e002-0.5*e27*e022-0.5*e27*e032-0.5*e27*e052+e07*e26*e06+e01*e20*e06+e01*e00*e26+e01*e21*e07+e01*e02*e28+e21*e00*e06+e21*e02*e08+e04*e23*e06+e04*e03*e26+e04*e24*e07+e04*e25*e08+e04*e05*e28+e24*e03*e06+e24*e05*e08; +A[5 + 10*5]=e14*e24*e07+e14*e03*e26+e14*e23*e06+e04*e14*e27+e04*e24*e17+e04*e15*e28+e04*e25*e18+e04*e13*e26+e04*e23*e16+e21*e02*e18+e21*e12*e08-e27*e15*e05-e27*e13*e03-e27*e12*e02-e27*e10*e00-e17*e25*e05-e17*e23*e03-e17*e22*e02-e17*e20*e00-e07*e22*e12-e07*e23*e13-e07*e25*e15-e07*e20*e10+e27*e18*e08+e27*e16*e06+e17*e28*e08+e17*e26*e06+3*e07*e27*e17+e07*e28*e18+e07*e26*e16+e24*e05*e18+e24*e15*e08+e24*e03*e16+e24*e13*e06+e14*e05*e28+e14*e25*e08+e01*e12*e28+e01*e20*e16+e01*e10*e26+e01*e22*e18+e01*e21*e17+e11*e20*e06+e01*e11*e27+e21*e00*e16+e21*e10*e06+e11*e21*e07+e11*e22*e08+e11*e02*e28+e11*e00*e26; +A[5 + 10*6]=-0.5*e27*e102-0.5*e27*e152-0.5*e27*e132-0.5*e27*e122+0.5*e142*e27+1.5*e27*e172+0.5*e27*e162+0.5*e27*e182+0.5*e112*e27+e11*e22*e18+e11*e10*e26+e11*e20*e16-e17*e22*e12-e17*e23*e13-e17*e25*e15-e17*e20*e10+e17*e28*e18+e17*e26*e16+e24*e15*e18+e24*e13*e16+e14*e24*e17+e14*e15*e28+e14*e25*e18+e14*e13*e26+e14*e23*e16+e21*e12*e18+e21*e10*e16+e11*e21*e17+e11*e12*e28; +A[5 + 10*7]=-0.5*e07*e252+e27*e26*e06+e27*e28*e08-e27*e20*e00-e27*e22*e02-e27*e23*e03-e27*e25*e05+1.5*e07*e272+0.5*e07*e282+e01*e22*e28+e21*e20*e06+e21*e00*e26+e21*e22*e08+e21*e02*e28+e04*e23*e26+e04*e24*e27+e04*e25*e28+e24*e23*e06+e24*e03*e26+e24*e25*e08+e24*e05*e28+0.5*e212*e07+0.5*e242*e07+0.5*e07*e262+e01*e20*e26+e01*e21*e27-0.5*e07*e202-0.5*e07*e232-0.5*e07*e222; +A[5 + 10*8]=-e27*e25*e15-e27*e23*e13-e27*e22*e12-0.5*e17*e252-0.5*e17*e202-0.5*e17*e222-0.5*e17*e232+0.5*e17*e262+1.5*e17*e272+0.5*e17*e282+e24*e23*e16+e24*e13*e26+e24*e25*e18+e24*e15*e28+e27*e26*e16+e27*e28*e18-e27*e20*e10+e14*e24*e27+e14*e25*e28+0.5*e212*e17+0.5*e242*e17+e11*e20*e26+e11*e21*e27+e11*e22*e28+e21*e20*e16+e21*e10*e26+e21*e22*e18+e21*e12*e28+e14*e23*e26; +A[5 + 10*9]=e21*e20*e26+0.5*e212*e27+e21*e22*e28+e24*e23*e26+0.5*e242*e27+e24*e25*e28+0.5*e27*e262+0.5*e273+0.5*e27*e282-0.5*e27*e202-0.5*e27*e222-0.5*e27*e232-0.5*e27*e252; +A[5 + 10*10]=e04*e05*e38+e01*e30*e06-0.5*e37*e002-0.5*e37*e022-0.5*e37*e032-0.5*e37*e052-e07*e32*e02-e07*e35*e05-e07*e33*e03+e07*e36*e06+e07*e38*e08-e07*e30*e00+1.5*e37*e072+0.5*e37*e062+0.5*e37*e082+e01*e02*e38+e31*e00*e06+e31*e02*e08+e04*e33*e06+e04*e03*e36+e04*e34*e07+e04*e35*e08+e34*e03*e06+e34*e05*e08+0.5*e012*e37+0.5*e042*e37+e01*e00*e36+e01*e31*e07+e01*e32*e08; +A[5 + 10*11]=e14*e33*e06+e11*e30*e06+e11*e00*e36+e11*e31*e07+e31*e10*e06+e11*e32*e08+e11*e02*e38+e31*e00*e16+e31*e12*e08+e31*e02*e18+e04*e33*e16+e04*e13*e36+e04*e35*e18+e04*e15*e38+e01*e10*e36+e01*e32*e18+e01*e12*e38+e01*e31*e17+e01*e11*e37+e01*e30*e16-e17*e35*e05-e37*e10*e00-e37*e12*e02-e37*e13*e03-e37*e15*e05+e37*e18*e08-e07*e30*e10-e07*e35*e15-e07*e33*e13-e07*e32*e12-e17*e30*e00-e17*e32*e02-e17*e33*e03+e07*e38*e18+3*e07*e37*e17+e17*e36*e06+e17*e38*e08+e37*e16*e06+e04*e34*e17+e04*e14*e37+e14*e03*e36+e14*e34*e07+e14*e35*e08+e14*e05*e38+e34*e13*e06+e34*e03*e16+e34*e15*e08+e34*e05*e18+e07*e36*e16; +A[5 + 10*12]=e11*e32*e18-0.5*e37*e102-0.5*e37*e152-0.5*e37*e132-0.5*e37*e122+0.5*e112*e37+0.5*e142*e37+1.5*e37*e172+0.5*e37*e162+0.5*e37*e182+e11*e10*e36+e11*e12*e38+e11*e31*e17+e31*e10*e16+e31*e12*e18+e14*e33*e16+e14*e13*e36+e14*e35*e18+e14*e15*e38+e14*e34*e17+e34*e13*e16+e34*e15*e18+e17*e36*e16+e17*e38*e18-e17*e30*e10-e17*e35*e15-e17*e33*e13-e17*e32*e12+e11*e30*e16; +A[5 + 10*13]=e01*e20*e36+e01*e31*e27+e01*e21*e37+e01*e32*e28+e01*e22*e38+e21*e30*e06+e21*e00*e36+e21*e31*e07+e21*e32*e08+e21*e02*e38+e01*e30*e26+e31*e20*e06+e31*e00*e26+e31*e22*e08+e31*e02*e28+e04*e33*e26+e04*e23*e36+e04*e34*e27+e04*e24*e37+e04*e35*e28+e04*e25*e38+e24*e33*e06+e24*e03*e36+e24*e34*e07+e24*e35*e08+e24*e05*e38+e34*e23*e06+e34*e03*e26+e34*e25*e08+e34*e05*e28+e07*e36*e26+3*e07*e37*e27+e07*e38*e28+e27*e36*e06+e27*e38*e08+e37*e26*e06+e37*e28*e08-e07*e30*e20-e07*e32*e22-e07*e33*e23-e07*e35*e25-e27*e30*e00-e27*e32*e02-e27*e33*e03-e27*e35*e05-e37*e20*e00-e37*e22*e02-e37*e23*e03-e37*e25*e05; +A[5 + 10*14]=e11*e30*e26+e11*e20*e36+e11*e31*e27+e11*e21*e37+e11*e32*e28+e11*e22*e38+e21*e10*e36+e21*e32*e18+e21*e12*e38+e21*e31*e17+e31*e20*e16+e31*e10*e26+e31*e22*e18+e31*e12*e28+e14*e33*e26+e14*e23*e36+e14*e34*e27+e14*e24*e37+e14*e35*e28+e14*e25*e38+e24*e33*e16+e24*e13*e36+e24*e35*e18+e24*e15*e38+e24*e34*e17+e34*e23*e16+e34*e13*e26+e34*e25*e18+e34*e15*e28+e17*e36*e26+3*e17*e37*e27+e17*e38*e28+e27*e36*e16+e27*e38*e18+e37*e26*e16+e37*e28*e18-e17*e30*e20-e17*e32*e22-e17*e33*e23-e17*e35*e25-e27*e30*e10-e27*e35*e15-e27*e33*e13-e27*e32*e12-e37*e20*e10-e37*e25*e15-e37*e23*e13-e37*e22*e12+e21*e30*e16; +A[5 + 10*15]=e21*e20*e36+e21*e31*e27+e21*e32*e28+e21*e22*e38+e31*e22*e28+e24*e33*e26+e24*e23*e36+e24*e34*e27+e24*e35*e28+e24*e25*e38+e34*e23*e26+e34*e25*e28+e27*e36*e26+e27*e38*e28-e27*e30*e20-e27*e32*e22-e27*e33*e23-e27*e35*e25+0.5*e242*e37+1.5*e37*e272+0.5*e37*e262+0.5*e37*e282+e31*e20*e26+e21*e30*e26+0.5*e212*e37-0.5*e37*e202-0.5*e37*e222-0.5*e37*e232-0.5*e37*e252; +A[5 + 10*16]=e01*e30*e36+e01*e32*e38+e01*e31*e37+e31*e30*e06+e31*e00*e36+e31*e32*e08+e31*e02*e38+e04*e33*e36+e04*e35*e38+e04*e34*e37+e34*e33*e06+e34*e03*e36+e34*e35*e08+e34*e05*e38+e37*e36*e06+e37*e38*e08-e37*e30*e00-e37*e32*e02-e37*e33*e03-e37*e35*e05+0.5*e312*e07+0.5*e342*e07+0.5*e07*e362+0.5*e07*e382+1.5*e07*e372-0.5*e07*e302-0.5*e07*e352-0.5*e07*e322-0.5*e07*e332; +A[5 + 10*17]=0.5*e312*e17+0.5*e342*e17+0.5*e17*e362+0.5*e17*e382+1.5*e17*e372-0.5*e17*e302-0.5*e17*e352-0.5*e17*e322-0.5*e17*e332-e37*e32*e12-e37*e33*e13+e11*e30*e36+e11*e32*e38+e11*e31*e37+e31*e30*e16+e31*e10*e36+e31*e32*e18+e31*e12*e38+e14*e33*e36+e14*e35*e38+e14*e34*e37+e34*e33*e16+e34*e13*e36+e34*e35*e18+e34*e15*e38+e37*e36*e16+e37*e38*e18-e37*e30*e10-e37*e35*e15; +A[5 + 10*18]=e21*e31*e37-0.5*e27*e332+e21*e30*e36+e21*e32*e38+e31*e30*e26+e31*e20*e36+e31*e32*e28+e31*e22*e38+e24*e33*e36+e24*e35*e38+e24*e34*e37+e34*e33*e26+e34*e23*e36+e34*e35*e28+e34*e25*e38+e37*e36*e26+e37*e38*e28-e37*e30*e20-e37*e32*e22-e37*e33*e23-e37*e35*e25+0.5*e312*e27+0.5*e342*e27+0.5*e27*e362+0.5*e27*e382+1.5*e27*e372-0.5*e27*e302-0.5*e27*e352-0.5*e27*e322; +A[5 + 10*19]=e31*e30*e36+e31*e32*e38+0.5*e312*e37+e34*e33*e36+e34*e35*e38+0.5*e342*e37+0.5*e37*e362+0.5*e37*e382+0.5*e373-0.5*e37*e302-0.5*e37*e352-0.5*e37*e322-0.5*e37*e332; +A[6 + 10*0]=0.5*e02*e002+0.5*e02*e012+0.5*e023+e05*e00*e03+e05*e01*e04+0.5*e02*e052+e08*e00*e06+e08*e01*e07+0.5*e02*e082-0.5*e02*e032-0.5*e02*e042-0.5*e02*e062-0.5*e02*e072; +A[6 + 10*1]=-0.5*e12*e042-0.5*e12*e062-0.5*e12*e072+0.5*e12*e082-0.5*e12*e032+1.5*e12*e022+0.5*e12*e002+0.5*e12*e012+0.5*e12*e052+e02*e10*e00+e02*e11*e01+e05*e10*e03+e05*e00*e13+e05*e11*e04+e05*e01*e14+e05*e02*e15+e15*e00*e03+e15*e01*e04+e08*e10*e06+e08*e00*e16+e08*e11*e07+e08*e01*e17+e08*e02*e18+e18*e00*e06+e18*e01*e07-e02*e13*e03-e02*e14*e04-e02*e16*e06-e02*e17*e07; +A[6 + 10*2]=0.5*e02*e102+1.5*e02*e122+0.5*e02*e112+0.5*e02*e152+0.5*e02*e182-0.5*e02*e162-0.5*e02*e172-0.5*e02*e132-0.5*e02*e142+e12*e10*e00+e12*e11*e01+e05*e10*e13+e05*e12*e15+e05*e11*e14+e15*e10*e03+e15*e00*e13+e15*e11*e04+e15*e01*e14+e08*e10*e16+e08*e12*e18+e08*e11*e17+e18*e10*e06+e18*e00*e16+e18*e11*e07+e18*e01*e17-e12*e13*e03-e12*e14*e04-e12*e16*e06-e12*e17*e07; +A[6 + 10*3]=0.5*e12*e102+0.5*e123+0.5*e12*e112+e15*e10*e13+0.5*e12*e152+e15*e11*e14+e18*e10*e16+0.5*e12*e182+e18*e11*e17-0.5*e12*e162-0.5*e12*e172-0.5*e12*e132-0.5*e12*e142; +A[6 + 10*4]=-0.5*e22*e032-0.5*e22*e042-0.5*e22*e062-0.5*e22*e072+0.5*e22*e082+1.5*e22*e022+0.5*e22*e002+0.5*e22*e012+0.5*e22*e052+e02*e20*e00+e02*e21*e01+e05*e20*e03+e05*e00*e23+e05*e21*e04+e05*e01*e24+e05*e02*e25+e25*e00*e03+e25*e01*e04+e08*e20*e06+e08*e00*e26+e08*e21*e07+e08*e01*e27+e08*e02*e28+e28*e00*e06+e28*e01*e07-e02*e27*e07-e02*e23*e03-e02*e24*e04-e02*e26*e06; +A[6 + 10*5]=-e22*e17*e07-e22*e16*e06-e22*e14*e04-e22*e13*e03-e12*e26*e06-e12*e24*e04-e12*e23*e03-e12*e27*e07-e02*e24*e14-e02*e23*e13-e02*e27*e17-e02*e26*e16+e28*e01*e17+e28*e11*e07+e28*e00*e16+e28*e10*e06+e18*e02*e28+e18*e01*e27+e18*e21*e07+e18*e00*e26+e18*e20*e06+e08*e11*e27+e08*e21*e17+e08*e12*e28+e08*e22*e18+e08*e10*e26+e25*e01*e14+e25*e11*e04+e25*e00*e13+e25*e10*e03+e15*e01*e24+e02*e21*e11+e12*e21*e01+e15*e02*e25+e15*e21*e04+e05*e22*e15+e05*e11*e24+e15*e20*e03+e15*e00*e23+e05*e10*e23+e05*e12*e25+e05*e21*e14+e22*e10*e00+e22*e11*e01+e02*e20*e10+3*e02*e22*e12+e12*e20*e00+e08*e20*e16+e05*e20*e13; +A[6 + 10*6]=-e12*e24*e14-e12*e23*e13-e12*e27*e17-e12*e26*e16+e28*e11*e17+e28*e10*e16+e18*e11*e27+e18*e21*e17+e18*e12*e28+e18*e10*e26+e18*e20*e16+e25*e11*e14+e25*e10*e13+e15*e11*e24+e15*e21*e14+e15*e12*e25+e15*e10*e23+e15*e20*e13+e12*e21*e11+0.5*e22*e182+0.5*e22*e152+1.5*e22*e122+0.5*e22*e102+e12*e20*e10+0.5*e22*e112-0.5*e22*e172-0.5*e22*e132-0.5*e22*e142-0.5*e22*e162; +A[6 + 10*7]=0.5*e02*e282+e28*e01*e27-e22*e27*e07-e22*e23*e03-e22*e24*e04-e22*e26*e06+0.5*e02*e252+e05*e20*e23+e05*e22*e25+e25*e20*e03+e25*e00*e23+e25*e21*e04+e25*e01*e24+e08*e20*e26+e08*e21*e27+e08*e22*e28+e28*e20*e06+e28*e00*e26+e28*e21*e07+e05*e21*e24+0.5*e02*e202+0.5*e02*e212+1.5*e02*e222+e22*e20*e00+e22*e21*e01-0.5*e02*e272-0.5*e02*e242-0.5*e02*e232-0.5*e02*e262; +A[6 + 10*8]=-e22*e27*e17-e22*e23*e13-e22*e24*e14-0.5*e12*e232-0.5*e12*e262-0.5*e12*e242-0.5*e12*e272+0.5*e12*e282+e18*e21*e27+e28*e20*e16+e28*e10*e26+e28*e21*e17+e28*e11*e27-e22*e26*e16+e18*e22*e28+0.5*e12*e252+0.5*e12*e202+0.5*e12*e212+1.5*e12*e222+e22*e20*e10+e15*e20*e23+e15*e21*e24+e15*e22*e25+e25*e20*e13+e25*e10*e23+e25*e21*e14+e25*e11*e24+e18*e20*e26+e22*e21*e11; +A[6 + 10*9]=0.5*e22*e202+0.5*e22*e212+0.5*e223+e25*e20*e23+e25*e21*e24+0.5*e22*e252+e28*e20*e26+e28*e21*e27+0.5*e22*e282-0.5*e22*e232-0.5*e22*e262-0.5*e22*e242-0.5*e22*e272; +A[6 + 10*10]=e08*e31*e07-0.5*e32*e032-e02*e33*e03-e02*e34*e04-e02*e36*e06-0.5*e32*e042-0.5*e32*e062-0.5*e32*e072+e38*e01*e07+e38*e00*e06-e02*e37*e07+e05*e31*e04+e05*e01*e34+e05*e02*e35+e35*e01*e04+e35*e00*e03+e08*e30*e06+e08*e00*e36+e08*e01*e37+e08*e02*e38+0.5*e32*e052+e02*e30*e00+e02*e31*e01+e05*e30*e03+e05*e00*e33+1.5*e32*e022+0.5*e32*e012+0.5*e32*e002+0.5*e32*e082; +A[6 + 10*11]=e05*e32*e15+e32*e11*e01+e38*e10*e06+e08*e12*e38-e32*e14*e04-e32*e16*e06-e32*e17*e07-e12*e36*e06-e32*e13*e03-e02*e34*e14-e12*e37*e07-e12*e33*e03-e12*e34*e04-e02*e37*e17-e02*e33*e13+e38*e01*e17-e02*e36*e16+e18*e01*e37+e18*e02*e38+e38*e00*e16+e38*e11*e07+e08*e30*e16+e08*e10*e36+e08*e32*e18+e08*e31*e17+e08*e11*e37+e18*e30*e06+e18*e00*e36+e18*e31*e07+e35*e10*e03+e35*e00*e13+e35*e11*e04+e35*e01*e14+e15*e02*e35+e05*e10*e33+e05*e12*e35+e05*e31*e14+e05*e11*e34+e15*e30*e03+e15*e00*e33+e15*e31*e04+e15*e01*e34+e05*e30*e13+e02*e30*e10+e02*e31*e11+3*e02*e32*e12+e12*e30*e00+e12*e31*e01+e32*e10*e00; +A[6 + 10*12]=0.5*e32*e102+0.5*e32*e112+e12*e30*e10+1.5*e32*e122+e12*e31*e11+e15*e30*e13+e15*e10*e33+e15*e12*e35+e15*e31*e14+e15*e11*e34+e35*e10*e13-0.5*e32*e162-0.5*e32*e172-0.5*e32*e132-0.5*e32*e142-e12*e37*e17-e12*e33*e13-e12*e34*e14+0.5*e32*e182+0.5*e32*e152+e35*e11*e14+e18*e30*e16+e18*e10*e36+e18*e12*e38+e18*e31*e17+e18*e11*e37+e38*e10*e16+e38*e11*e17-e12*e36*e16; +A[6 + 10*13]=3*e02*e32*e22+e05*e31*e24+e08*e22*e38+e02*e31*e21+e22*e30*e00+e22*e31*e01+e32*e20*e00+e32*e21*e01+e05*e30*e23+e05*e20*e33+e05*e21*e34-e22*e37*e07-e22*e33*e03-e22*e34*e04-e22*e36*e06-e32*e27*e07-e32*e23*e03-e32*e24*e04-e32*e26*e06+e05*e32*e25+e25*e30*e03+e25*e00*e33+e25*e31*e04+e25*e01*e34+e25*e02*e35+e35*e20*e03+e35*e00*e23+e35*e21*e04+e35*e01*e24+e08*e30*e26+e08*e20*e36+e08*e31*e27+e08*e21*e37+e08*e32*e28+e28*e30*e06+e28*e00*e36+e28*e31*e07+e28*e01*e37+e28*e02*e38+e38*e20*e06+e38*e00*e26+e38*e21*e07+e38*e01*e27-e02*e33*e23-e02*e36*e26-e02*e34*e24-e02*e37*e27+e05*e22*e35+e02*e30*e20; +A[6 + 10*14]=e18*e22*e38+e12*e31*e21+3*e12*e32*e22+e22*e30*e10+e22*e31*e11+e32*e20*e10+e32*e21*e11+e15*e30*e23+e15*e20*e33+e15*e31*e24+e15*e21*e34+e15*e32*e25+e15*e22*e35+e25*e30*e13+e25*e10*e33+e25*e12*e35+e25*e31*e14+e25*e11*e34+e35*e20*e13+e35*e10*e23+e35*e21*e14+e35*e11*e24+e18*e30*e26+e18*e20*e36+e18*e31*e27+e18*e21*e37+e18*e32*e28+e28*e30*e16+e28*e10*e36+e28*e12*e38+e28*e31*e17+e28*e11*e37+e38*e20*e16+e38*e10*e26+e12*e30*e20-e22*e37*e17-e22*e33*e13-e22*e34*e14-e32*e26*e16-e32*e27*e17-e32*e23*e13-e32*e24*e14-e22*e36*e16+e38*e21*e17+e38*e11*e27-e12*e33*e23-e12*e36*e26-e12*e34*e24-e12*e37*e27; +A[6 + 10*15]=e25*e30*e23+e22*e30*e20+e22*e31*e21+e25*e20*e33+e25*e31*e24+e25*e21*e34+e25*e22*e35+e35*e20*e23+e35*e21*e24+e28*e30*e26+e28*e20*e36+e28*e31*e27+e28*e21*e37+e28*e22*e38+e38*e20*e26+e38*e21*e27-e22*e33*e23-e22*e36*e26-e22*e34*e24-e22*e37*e27+0.5*e32*e212+0.5*e32*e252+1.5*e32*e222+0.5*e32*e202+0.5*e32*e282-0.5*e32*e232-0.5*e32*e262-0.5*e32*e242-0.5*e32*e272; +A[6 + 10*16]=0.5*e02*e302+1.5*e02*e322+0.5*e02*e312+0.5*e02*e352+0.5*e02*e382-0.5*e02*e342-0.5*e02*e362-0.5*e02*e332-0.5*e02*e372+e38*e30*e06+e32*e30*e00+e32*e31*e01+e05*e30*e33+e05*e32*e35+e05*e31*e34+e35*e30*e03+e35*e00*e33+e35*e31*e04+e35*e01*e34+e08*e30*e36+e08*e32*e38+e08*e31*e37+e38*e00*e36+e38*e31*e07+e38*e01*e37-e32*e37*e07-e32*e33*e03-e32*e34*e04-e32*e36*e06; +A[6 + 10*17]=e32*e30*e10+e32*e31*e11+e15*e30*e33+e15*e32*e35+e15*e31*e34+e35*e30*e13+e35*e10*e33+e35*e31*e14+e35*e11*e34+e18*e30*e36+e18*e32*e38+e18*e31*e37+e38*e30*e16+e38*e10*e36+e38*e31*e17+e38*e11*e37-e32*e36*e16-e32*e37*e17-e32*e33*e13-e32*e34*e14+0.5*e12*e382-0.5*e12*e342-0.5*e12*e362-0.5*e12*e332-0.5*e12*e372+0.5*e12*e352+1.5*e12*e322+0.5*e12*e312+0.5*e12*e302; +A[6 + 10*18]=0.5*e22*e302+0.5*e22*e312+0.5*e22*e352+0.5*e22*e382-0.5*e22*e342-0.5*e22*e362-0.5*e22*e332-0.5*e22*e372+1.5*e22*e322+e32*e30*e20+e32*e31*e21+e25*e30*e33+e25*e32*e35+e25*e31*e34+e35*e30*e23+e35*e20*e33+e35*e31*e24+e35*e21*e34+e28*e30*e36+e28*e32*e38+e28*e31*e37+e38*e30*e26+e38*e20*e36+e38*e31*e27+e38*e21*e37-e32*e33*e23-e32*e36*e26-e32*e34*e24-e32*e37*e27; +A[6 + 10*19]=0.5*e32*e302+0.5*e323+0.5*e32*e312+e35*e30*e33+0.5*e32*e352+e35*e31*e34+e38*e30*e36+0.5*e32*e382+e38*e31*e37-0.5*e32*e342-0.5*e32*e362-0.5*e32*e332-0.5*e32*e372; +A[7 + 10*0]=e02*e01*e04+e02*e00*e03+0.5*e022*e05+0.5*e05*e032+0.5*e05*e042+0.5*e053+e08*e03*e06+e08*e04*e07+0.5*e05*e082-0.5*e05*e002-0.5*e05*e062-0.5*e05*e012-0.5*e05*e072; +A[7 + 10*1]=e08*e13*e06+e02*e10*e03+e02*e00*e13+e02*e11*e04+e02*e01*e14+e02*e12*e05+e12*e01*e04+e12*e00*e03+e05*e13*e03+e05*e14*e04+e08*e03*e16+e08*e14*e07+e08*e04*e17+e08*e05*e18+e18*e03*e06+e18*e04*e07-e05*e10*e00-e05*e11*e01-e05*e16*e06-e05*e17*e07+0.5*e022*e15+1.5*e15*e052+0.5*e15*e032+0.5*e15*e042+0.5*e15*e082-0.5*e15*e002-0.5*e15*e062-0.5*e15*e012-0.5*e15*e072; +A[7 + 10*2]=0.5*e122*e05+0.5*e05*e132+1.5*e05*e152+0.5*e05*e142+0.5*e05*e182-0.5*e05*e102-0.5*e05*e162-0.5*e05*e112-0.5*e05*e172+e02*e10*e13+e02*e12*e15+e02*e11*e14+e12*e10*e03+e12*e00*e13+e12*e11*e04+e12*e01*e14+e15*e13*e03+e15*e14*e04+e08*e13*e16+e08*e15*e18+e08*e14*e17+e18*e13*e06+e18*e03*e16+e18*e14*e07+e18*e04*e17-e15*e11*e01-e15*e16*e06-e15*e17*e07-e15*e10*e00; +A[7 + 10*3]=e12*e10*e13+0.5*e122*e15+e12*e11*e14+0.5*e15*e132+0.5*e153+0.5*e15*e142+e18*e13*e16+0.5*e15*e182+e18*e14*e17-0.5*e15*e102-0.5*e15*e162-0.5*e15*e112-0.5*e15*e172; +A[7 + 10*4]=0.5*e25*e082-0.5*e25*e002-0.5*e25*e062-0.5*e25*e012-0.5*e25*e072+e02*e20*e03+e02*e00*e23+e02*e21*e04+e02*e01*e24+e02*e22*e05+e22*e01*e04+e22*e00*e03+e05*e23*e03+e05*e24*e04+e08*e23*e06+e08*e03*e26+e08*e24*e07+e08*e04*e27+e08*e05*e28+e28*e03*e06+e28*e04*e07-e05*e20*e00-e05*e27*e07-e05*e21*e01-e05*e26*e06+0.5*e022*e25+1.5*e25*e052+0.5*e25*e032+0.5*e25*e042; +A[7 + 10*5]=-e25*e17*e07-e25*e16*e06-e25*e11*e01-e25*e10*e00-e15*e26*e06-e15*e21*e01-e15*e27*e07-e15*e20*e00-e05*e27*e17-e05*e21*e11-e05*e26*e16-e05*e20*e10+e28*e04*e17+e28*e14*e07+e28*e03*e16+e28*e13*e06+e18*e05*e28+e18*e04*e27+e18*e24*e07+e18*e03*e26+e18*e23*e06+e08*e14*e27+e08*e24*e17+e08*e15*e28+e08*e25*e18+e08*e13*e26+e08*e23*e16+e25*e14*e04+e25*e13*e03+e15*e24*e04+e15*e23*e03+e05*e24*e14+3*e05*e25*e15+e05*e23*e13+e22*e01*e14+e22*e11*e04+e22*e00*e13+e22*e10*e03+e12*e22*e05+e12*e01*e24+e12*e21*e04+e12*e00*e23+e12*e20*e03+e02*e11*e24+e02*e21*e14+e02*e12*e25+e02*e22*e15+e02*e10*e23+e02*e20*e13; +A[7 + 10*6]=-e15*e27*e17-e15*e21*e11-e15*e26*e16+e28*e14*e17+e28*e13*e16+e18*e14*e27+e18*e24*e17+e18*e15*e28+e18*e13*e26+e15*e24*e14+e15*e23*e13+e22*e11*e14+e22*e10*e13+e12*e11*e24+e12*e21*e14+e12*e22*e15+e12*e10*e23+e18*e23*e16+0.5*e25*e142+0.5*e25*e182+1.5*e25*e152+0.5*e25*e132+0.5*e122*e25+e12*e20*e13-0.5*e25*e172-0.5*e25*e162-0.5*e25*e112-0.5*e25*e102-e15*e20*e10; +A[7 + 10*7]=e28*e24*e07-0.5*e05*e272-0.5*e05*e262-0.5*e05*e212+0.5*e05*e282-0.5*e05*e202+e28*e23*e06+e08*e23*e26+e08*e25*e28+e08*e24*e27+e28*e03*e26+e28*e04*e27-e25*e27*e07-e25*e21*e01-e25*e26*e06+e02*e20*e23+e02*e22*e25+e02*e21*e24+e22*e20*e03+e22*e00*e23+e22*e21*e04+e22*e01*e24+e25*e23*e03+e25*e24*e04+0.5*e222*e05+0.5*e05*e232+1.5*e05*e252+0.5*e05*e242-e25*e20*e00; +A[7 + 10*8]=-0.5*e15*e202-0.5*e15*e262-0.5*e15*e212-0.5*e15*e272+e18*e23*e26+e18*e25*e28+e18*e24*e27+e28*e23*e16+e28*e13*e26+e28*e24*e17+e28*e14*e27-e25*e20*e10-e25*e26*e16-e25*e21*e11-e25*e27*e17+0.5*e15*e282+0.5*e15*e232+1.5*e15*e252+0.5*e15*e242+0.5*e222*e15+e12*e21*e24+e22*e20*e13+e22*e10*e23+e22*e21*e14+e22*e11*e24+e25*e23*e13+e25*e24*e14+e12*e20*e23+e12*e22*e25; +A[7 + 10*9]=e22*e20*e23+0.5*e222*e25+e22*e21*e24+0.5*e25*e232+0.5*e253+0.5*e25*e242+e28*e23*e26+0.5*e25*e282+e28*e24*e27-0.5*e25*e202-0.5*e25*e262-0.5*e25*e212-0.5*e25*e272; +A[7 + 10*10]=-0.5*e35*e062-0.5*e35*e012-0.5*e35*e072-e05*e30*e00-e05*e31*e01-e05*e36*e06-e05*e37*e07-0.5*e35*e002+0.5*e35*e082+e05*e34*e04+e08*e33*e06+e08*e03*e36+e08*e34*e07+e08*e04*e37+e08*e05*e38+e38*e04*e07+e38*e03*e06+0.5*e022*e35+1.5*e35*e052+0.5*e35*e042+0.5*e35*e032+e02*e30*e03+e02*e00*e33+e02*e31*e04+e02*e01*e34+e02*e32*e05+e32*e01*e04+e32*e00*e03+e05*e33*e03; +A[7 + 10*11]=e08*e33*e16-e35*e16*e06-e35*e17*e07-e15*e30*e00-e15*e37*e07-e15*e31*e01-e15*e36*e06-e35*e10*e00-e35*e11*e01-e05*e37*e17-e05*e31*e11+e38*e04*e17-e05*e30*e10-e05*e36*e16+e18*e33*e06+e18*e03*e36+e18*e34*e07+e18*e04*e37+e18*e05*e38+e38*e13*e06+e38*e03*e16+e38*e14*e07+e35*e14*e04+e08*e13*e36+e08*e35*e18+e08*e15*e38+e08*e34*e17+e08*e14*e37+e35*e13*e03+e05*e33*e13+3*e05*e35*e15+e05*e34*e14+e15*e33*e03+e15*e34*e04+e12*e01*e34+e12*e32*e05+e32*e10*e03+e32*e00*e13+e32*e11*e04+e32*e01*e14+e12*e30*e03+e02*e30*e13+e02*e32*e15+e02*e10*e33+e02*e12*e35+e12*e00*e33+e02*e31*e14+e02*e11*e34+e12*e31*e04; +A[7 + 10*12]=-0.5*e35*e162-0.5*e35*e172-e15*e36*e16-e15*e31*e11-e15*e37*e17-0.5*e35*e102-0.5*e35*e112-e15*e30*e10+e18*e13*e36+e18*e15*e38+e18*e34*e17+e18*e14*e37+e38*e13*e16+e38*e14*e17+e18*e33*e16+1.5*e35*e152+0.5*e35*e132+0.5*e35*e142+0.5*e35*e182+0.5*e122*e35+e32*e10*e13+e32*e11*e14+e15*e33*e13+e15*e34*e14+e12*e10*e33+e12*e32*e15+e12*e31*e14+e12*e11*e34+e12*e30*e13; +A[7 + 10*13]=e05*e33*e23+3*e05*e35*e25+e05*e34*e24+e25*e33*e03+e25*e34*e04+e35*e23*e03+e35*e24*e04+e08*e33*e26+e08*e23*e36+e08*e35*e28+e02*e20*e33+e02*e32*e25+e02*e22*e35+e02*e31*e24+e02*e21*e34+e22*e30*e03+e22*e00*e33+e22*e31*e04+e22*e01*e34+e22*e32*e05+e32*e20*e03+e32*e00*e23+e32*e21*e04+e32*e01*e24+e02*e30*e23-e35*e27*e07-e35*e21*e01-e35*e26*e06+e08*e25*e38+e08*e34*e27+e08*e24*e37+e28*e33*e06+e28*e03*e36+e28*e34*e07+e28*e04*e37+e28*e05*e38+e38*e23*e06+e38*e03*e26+e38*e24*e07+e38*e04*e27-e05*e30*e20-e05*e36*e26-e05*e31*e21-e05*e37*e27-e25*e30*e00-e25*e37*e07-e25*e31*e01-e25*e36*e06-e35*e20*e00; +A[7 + 10*14]=e12*e21*e34+e18*e25*e38+e12*e30*e23+e12*e20*e33+e12*e32*e25+e12*e22*e35+e12*e31*e24+e22*e30*e13+e22*e10*e33+e22*e32*e15+e22*e31*e14+e22*e11*e34+e32*e20*e13+e32*e10*e23+e32*e21*e14-e25*e30*e10-e25*e36*e16-e25*e31*e11-e25*e37*e17-e35*e20*e10-e35*e26*e16-e35*e21*e11-e35*e27*e17+e15*e33*e23+3*e15*e35*e25+e15*e34*e24+e25*e33*e13+e25*e34*e14+e35*e23*e13+e35*e24*e14+e18*e33*e26+e18*e23*e36+e18*e35*e28+e18*e34*e27+e18*e24*e37+e28*e33*e16+e28*e13*e36+e28*e15*e38+e28*e34*e17+e28*e14*e37+e38*e23*e16+e38*e13*e26+e38*e24*e17+e38*e14*e27-e15*e30*e20-e15*e36*e26-e15*e31*e21-e15*e37*e27+e32*e11*e24; +A[7 + 10*15]=-0.5*e35*e202-0.5*e35*e262-0.5*e35*e212-0.5*e35*e272+e25*e34*e24+e28*e23*e36+e28*e25*e38+e28*e34*e27+e28*e24*e37+e38*e23*e26+e38*e24*e27-e25*e30*e20-e25*e36*e26-e25*e31*e21-e25*e37*e27+e25*e33*e23+0.5*e222*e35+1.5*e35*e252+0.5*e35*e232+0.5*e35*e242+0.5*e35*e282+e22*e30*e23+e22*e20*e33+e22*e32*e25+e22*e31*e24+e22*e21*e34+e32*e20*e23+e32*e21*e24+e28*e33*e26; +A[7 + 10*16]=-e35*e30*e00-e35*e31*e01-e35*e36*e06-e35*e37*e07+0.5*e322*e05+0.5*e05*e332+0.5*e05*e342+1.5*e05*e352+0.5*e05*e382-0.5*e05*e302-0.5*e05*e362-0.5*e05*e312-0.5*e05*e372+e02*e30*e33+e02*e31*e34+e02*e32*e35+e32*e30*e03+e32*e00*e33+e32*e31*e04+e32*e01*e34+e35*e33*e03+e35*e34*e04+e08*e33*e36+e08*e34*e37+e08*e35*e38+e38*e33*e06+e38*e03*e36+e38*e34*e07+e38*e04*e37; +A[7 + 10*17]=-e35*e30*e10+e12*e32*e35-0.5*e15*e362-0.5*e15*e312-0.5*e15*e372-e35*e36*e16+0.5*e322*e15+0.5*e15*e332+0.5*e15*e342+1.5*e15*e352+0.5*e15*e382-0.5*e15*e302+e12*e30*e33+e12*e31*e34+e32*e30*e13+e32*e10*e33+e32*e31*e14+e32*e11*e34+e35*e33*e13+e35*e34*e14+e18*e33*e36+e18*e34*e37+e18*e35*e38+e38*e33*e16+e38*e13*e36+e38*e34*e17+e38*e14*e37-e35*e31*e11-e35*e37*e17; +A[7 + 10*18]=-0.5*e25*e302-0.5*e25*e362-0.5*e25*e312-0.5*e25*e372+0.5*e322*e25+0.5*e25*e332+0.5*e25*e342+1.5*e25*e352+0.5*e25*e382+e22*e30*e33+e22*e31*e34+e22*e32*e35+e32*e30*e23+e32*e20*e33+e32*e31*e24+e32*e21*e34+e35*e33*e23+e35*e34*e24+e28*e33*e36+e28*e34*e37+e28*e35*e38+e38*e33*e26+e38*e23*e36+e38*e34*e27+e38*e24*e37-e35*e30*e20-e35*e36*e26-e35*e31*e21-e35*e37*e27; +A[7 + 10*19]=e32*e30*e33+e32*e31*e34+0.5*e322*e35+0.5*e35*e332+0.5*e35*e342+0.5*e353+e38*e33*e36+e38*e34*e37+0.5*e35*e382-0.5*e35*e302-0.5*e35*e362-0.5*e35*e312-0.5*e35*e372; +A[8 + 10*0]=e02*e00*e06+e02*e01*e07+0.5*e022*e08+e05*e04*e07+e05*e03*e06+0.5*e052*e08+0.5*e08*e062+0.5*e08*e072+0.5*e083-0.5*e08*e042-0.5*e08*e002-0.5*e08*e012-0.5*e08*e032; +A[8 + 10*1]=e02*e10*e06+e02*e00*e16+e02*e11*e07+e02*e01*e17+e02*e12*e08+e12*e00*e06+e12*e01*e07+e05*e13*e06+e05*e03*e16+e05*e14*e07+e05*e04*e17+e05*e15*e08+e15*e04*e07+e15*e03*e06+e08*e16*e06+e08*e17*e07-e08*e10*e00-e08*e11*e01-e08*e13*e03-e08*e14*e04+0.5*e022*e18+0.5*e052*e18+1.5*e18*e082+0.5*e18*e062+0.5*e18*e072-0.5*e18*e042-0.5*e18*e002-0.5*e18*e012-0.5*e18*e032; +A[8 + 10*2]=e12*e01*e17+0.5*e152*e08+0.5*e08*e162+1.5*e08*e182+0.5*e08*e172-0.5*e08*e102-0.5*e08*e112-0.5*e08*e132-0.5*e08*e142+e05*e13*e16+e05*e14*e17+e05*e15*e18+e15*e13*e06+e15*e03*e16+e15*e14*e07+e15*e04*e17+e18*e16*e06+e18*e17*e07-e18*e10*e00-e18*e11*e01-e18*e13*e03-e18*e14*e04+0.5*e122*e08+e02*e10*e16+e02*e12*e18+e02*e11*e17+e12*e10*e06+e12*e00*e16+e12*e11*e07; +A[8 + 10*3]=e12*e10*e16+0.5*e122*e18+e12*e11*e17+e15*e13*e16+e15*e14*e17+0.5*e152*e18+0.5*e18*e162+0.5*e183+0.5*e18*e172-0.5*e18*e102-0.5*e18*e112-0.5*e18*e132-0.5*e18*e142; +A[8 + 10*4]=-e08*e20*e00+e08*e27*e07-e08*e21*e01-e08*e23*e03-e08*e24*e04+e02*e20*e06+e02*e00*e26+e02*e21*e07+e02*e01*e27+e02*e22*e08+e22*e00*e06+e22*e01*e07+e05*e23*e06+e05*e03*e26+e05*e24*e07+e05*e04*e27+e05*e25*e08+e25*e04*e07+e25*e03*e06+e08*e26*e06+0.5*e022*e28+0.5*e052*e28+1.5*e28*e082+0.5*e28*e062+0.5*e28*e072-0.5*e28*e042-0.5*e28*e002-0.5*e28*e012-0.5*e28*e032; +A[8 + 10*5]=e22*e10*e06+e22*e11*e07+e22*e01*e17+e05*e23*e16+e05*e13*e26+e05*e25*e18+e05*e15*e28+e05*e24*e17+e05*e14*e27+e15*e23*e06+e15*e03*e26+e15*e24*e07+e15*e04*e27+e15*e25*e08+e25*e13*e06+e25*e03*e16+e25*e14*e07+e25*e04*e17+e08*e26*e16+3*e08*e28*e18+e08*e27*e17+e18*e26*e06+e18*e27*e07+e22*e00*e16+e28*e16*e06+e28*e17*e07-e08*e20*e10-e08*e21*e11-e08*e23*e13-e08*e24*e14-e18*e20*e00-e18*e21*e01-e18*e23*e03-e18*e24*e04-e28*e10*e00-e28*e11*e01-e28*e13*e03-e28*e14*e04+e02*e20*e16+e02*e10*e26+e02*e22*e18+e02*e12*e28+e02*e21*e17+e02*e11*e27+e12*e20*e06+e12*e00*e26+e12*e21*e07+e12*e01*e27+e12*e22*e08; +A[8 + 10*6]=-e18*e24*e14-e18*e21*e11-e18*e23*e13-e18*e20*e10+e18*e27*e17+e18*e26*e16+e25*e14*e17+e25*e13*e16+e15*e25*e18+e15*e14*e27+e15*e24*e17+e15*e13*e26+e15*e23*e16+e22*e11*e17+e22*e10*e16+e12*e11*e27+e12*e21*e17+e12*e22*e18+e12*e10*e26+e12*e20*e16+0.5*e28*e162+0.5*e28*e172+1.5*e28*e182+0.5*e152*e28-0.5*e28*e142-0.5*e28*e112-0.5*e28*e132-0.5*e28*e102+0.5*e122*e28; +A[8 + 10*7]=-e28*e24*e04-e28*e21*e01-e28*e23*e03-e28*e20*e00+e28*e27*e07+e28*e26*e06+e25*e04*e27+e25*e24*e07+e25*e03*e26+e05*e24*e27+e05*e25*e28+e05*e23*e26+e22*e01*e27+e22*e21*e07+e22*e00*e26+e22*e20*e06+e02*e22*e28+e02*e20*e26+e02*e21*e27+0.5*e222*e08-0.5*e08*e242-0.5*e08*e212-0.5*e08*e232-0.5*e08*e202+0.5*e08*e262+0.5*e08*e272+1.5*e08*e282+0.5*e252*e08+e25*e23*e06; +A[8 + 10*8]=e25*e24*e17+e25*e14*e27+e28*e26*e16+e28*e27*e17-e28*e21*e11-e28*e24*e14+e12*e22*e28+e22*e10*e26+e22*e21*e17+e22*e11*e27+e15*e23*e26+e15*e25*e28+e15*e24*e27+e25*e23*e16+e25*e13*e26+e22*e20*e16+0.5*e222*e18+0.5*e252*e18+0.5*e18*e262+0.5*e18*e272+e12*e20*e26+e12*e21*e27-e28*e20*e10-0.5*e18*e232-0.5*e18*e242-e28*e23*e13-0.5*e18*e212+1.5*e18*e282-0.5*e18*e202; +A[8 + 10*9]=e22*e20*e26+e22*e21*e27+0.5*e222*e28+e25*e23*e26+0.5*e252*e28+e25*e24*e27+0.5*e28*e262+0.5*e28*e272+0.5*e283-0.5*e28*e202-0.5*e28*e212-0.5*e28*e232-0.5*e28*e242; +A[8 + 10*10]=-e08*e30*e00-0.5*e38*e042-0.5*e38*e002-0.5*e38*e012-0.5*e38*e032+1.5*e38*e082+0.5*e38*e062+0.5*e38*e072+e32*e01*e07+e05*e33*e06+e05*e03*e36+e05*e34*e07+e05*e04*e37+e05*e35*e08+e35*e04*e07+e35*e03*e06+e08*e36*e06+e08*e37*e07+0.5*e052*e38+e32*e00*e06+e02*e30*e06+e02*e00*e36+e02*e31*e07+e02*e01*e37+e02*e32*e08+0.5*e022*e38-e08*e33*e03-e08*e31*e01-e08*e34*e04; +A[8 + 10*11]=-e38*e11*e01-e38*e14*e04-e38*e10*e00-e38*e13*e03-e18*e30*e00-e18*e33*e03-e18*e31*e01-e18*e34*e04-e08*e30*e10-e08*e33*e13-e08*e31*e11-e08*e34*e14+3*e08*e38*e18+e08*e37*e17+e18*e36*e06+e18*e37*e07+e38*e16*e06+e38*e17*e07+e15*e35*e08+e35*e13*e06+e35*e03*e16+e35*e14*e07+e35*e04*e17+e08*e36*e16+e05*e35*e18+e05*e15*e38+e15*e33*e06+e15*e03*e36+e15*e34*e07+e15*e04*e37+e05*e14*e37+e12*e30*e06+e12*e31*e07+e12*e01*e37+e12*e00*e36+e12*e32*e08+e32*e10*e06+e32*e00*e16+e32*e11*e07+e32*e01*e17+e05*e33*e16+e05*e13*e36+e05*e34*e17+e02*e30*e16+e02*e10*e36+e02*e32*e18+e02*e12*e38+e02*e31*e17+e02*e11*e37; +A[8 + 10*12]=e12*e30*e16+e12*e10*e36+e12*e32*e18+e12*e31*e17+e12*e11*e37+e32*e10*e16+e32*e11*e17+e15*e33*e16+e15*e13*e36-0.5*e38*e102-0.5*e38*e112-0.5*e38*e132-0.5*e38*e142+0.5*e38*e162+0.5*e38*e172+e15*e34*e17+e15*e14*e37+e15*e35*e18+e35*e13*e16+e35*e14*e17+e18*e36*e16+e18*e37*e17-e18*e30*e10-e18*e33*e13-e18*e31*e11-e18*e34*e14+0.5*e122*e38+0.5*e152*e38+1.5*e38*e182; +A[8 + 10*13]=e22*e30*e06-e28*e34*e04+e05*e35*e28+e02*e22*e38+e22*e00*e36+e22*e31*e07+e22*e01*e37+e02*e32*e28+e02*e21*e37-e38*e20*e00-e28*e31*e01-e38*e23*e03-e38*e21*e01-e38*e24*e04-e28*e30*e00-e08*e30*e20-e08*e31*e21-e08*e33*e23-e08*e34*e24-e28*e33*e03+e35*e24*e07+e35*e04*e27+e08*e36*e26+e08*e37*e27+3*e08*e38*e28+e28*e36*e06+e28*e37*e07+e38*e26*e06+e38*e27*e07+e25*e04*e37+e25*e35*e08+e35*e23*e06+e35*e03*e26+e05*e23*e36+e05*e25*e38+e05*e34*e27+e05*e24*e37+e25*e33*e06+e25*e03*e36+e25*e34*e07+e05*e33*e26+e32*e21*e07+e32*e01*e27+e22*e32*e08+e32*e20*e06+e32*e00*e26+e02*e30*e26+e02*e20*e36+e02*e31*e27; +A[8 + 10*14]=e35*e13*e26-e38*e21*e11-e38*e24*e14+e35*e24*e17+e35*e14*e27+e18*e36*e26+e18*e37*e27+3*e18*e38*e28+e28*e36*e16+e28*e37*e17+e38*e26*e16+e38*e27*e17-e18*e30*e20-e18*e31*e21-e18*e33*e23-e18*e34*e24-e28*e30*e10-e28*e33*e13-e28*e31*e11-e28*e34*e14-e38*e20*e10-e38*e23*e13+e35*e23*e16+e12*e20*e36+e12*e30*e26+e12*e31*e27+e12*e21*e37+e12*e32*e28+e12*e22*e38+e22*e30*e16+e22*e10*e36+e22*e32*e18+e22*e31*e17+e22*e11*e37+e32*e20*e16+e32*e10*e26+e32*e21*e17+e32*e11*e27+e15*e33*e26+e15*e23*e36+e15*e35*e28+e15*e25*e38+e15*e34*e27+e15*e24*e37+e25*e33*e16+e25*e13*e36+e25*e34*e17+e25*e14*e37+e25*e35*e18; +A[8 + 10*15]=-e28*e30*e20+e22*e30*e26+e22*e20*e36+e22*e31*e27+e22*e21*e37+e22*e32*e28+e32*e20*e26+e32*e21*e27+e25*e33*e26+e25*e23*e36+e25*e35*e28+e25*e34*e27+e25*e24*e37+e35*e23*e26+e35*e24*e27+e28*e36*e26+e28*e37*e27-e28*e31*e21-e28*e33*e23-e28*e34*e24-0.5*e38*e242+0.5*e252*e38+1.5*e38*e282+0.5*e38*e262+0.5*e38*e272-0.5*e38*e202-0.5*e38*e212-0.5*e38*e232+0.5*e222*e38; +A[8 + 10*16]=-0.5*e08*e312-0.5*e08*e342+0.5*e352*e08+0.5*e08*e362+1.5*e08*e382+0.5*e08*e372-0.5*e08*e302-0.5*e08*e332+e02*e30*e36+e02*e32*e38+e02*e31*e37+e32*e30*e06+e32*e00*e36+e32*e31*e07+e32*e01*e37+e05*e33*e36+e05*e34*e37+e05*e35*e38+e35*e33*e06+e35*e03*e36+e35*e34*e07+e35*e04*e37+0.5*e322*e08+e38*e36*e06+e38*e37*e07-e38*e30*e00-e38*e33*e03-e38*e31*e01-e38*e34*e04; +A[8 + 10*17]=-e38*e30*e10+e38*e36*e16+e38*e37*e17-e38*e33*e13-e38*e31*e11-e38*e34*e14+0.5*e18*e362+e12*e30*e36+e12*e32*e38+e12*e31*e37+e32*e30*e16+e32*e10*e36+e32*e31*e17+e32*e11*e37+e15*e33*e36+e15*e34*e37+e15*e35*e38+e35*e33*e16+e35*e13*e36+e35*e34*e17+e35*e14*e37+0.5*e322*e18+0.5*e352*e18+1.5*e18*e382+0.5*e18*e372-0.5*e18*e302-0.5*e18*e332-0.5*e18*e312-0.5*e18*e342; +A[8 + 10*18]=-e38*e30*e20+e25*e35*e38+e22*e30*e36+e22*e32*e38+e22*e31*e37+e32*e30*e26+e32*e20*e36+e32*e31*e27+e32*e21*e37+e25*e33*e36+e25*e34*e37+e35*e33*e26+e35*e23*e36+e35*e34*e27+e35*e24*e37+e38*e36*e26+e38*e37*e27-e38*e31*e21-e38*e33*e23-e38*e34*e24-0.5*e28*e332-0.5*e28*e312-0.5*e28*e342+0.5*e322*e28+0.5*e352*e28+0.5*e28*e362+1.5*e28*e382+0.5*e28*e372-0.5*e28*e302; +A[8 + 10*19]=e32*e30*e36+0.5*e322*e38+e32*e31*e37+e35*e33*e36+e35*e34*e37+0.5*e352*e38+0.5*e38*e362+0.5*e383+0.5*e38*e372-0.5*e38*e302-0.5*e38*e332-0.5*e38*e312-0.5*e38*e342; +A[9 + 10*0]=e00*e04*e08-e00*e05*e07+e03*e02*e07-e03*e01*e08-e06*e02*e04+e06*e01*e05; +A[9 + 10*1]=e06*e01*e15-e16*e02*e04+e16*e01*e05+e03*e02*e17-e13*e01*e08+e06*e11*e05+e13*e02*e07+e00*e04*e18+e00*e14*e08-e00*e05*e17-e10*e05*e07-e00*e15*e07-e06*e12*e04-e06*e02*e14-e03*e01*e18-e03*e11*e08+e10*e04*e08+e03*e12*e07; +A[9 + 10*2]=-e13*e01*e18-e13*e11*e08+e13*e12*e07+e13*e02*e17+e03*e12*e17-e10*e15*e07+e10*e04*e18+e10*e14*e08-e10*e05*e17-e00*e15*e17+e00*e14*e18+e16*e01*e15+e06*e11*e15-e06*e12*e14-e16*e12*e04-e16*e02*e14+e16*e11*e05-e03*e11*e18; +A[9 + 10*3]=e10*e14*e18-e10*e15*e17-e13*e11*e18+e13*e12*e17+e16*e11*e15-e16*e12*e14; +A[9 + 10*4]=-e20*e05*e07+e03*e22*e07+e06*e21*e05+e06*e01*e25-e23*e01*e08+e23*e02*e07+e00*e24*e08-e00*e25*e07-e00*e05*e27+e00*e04*e28-e06*e22*e04-e06*e02*e24-e03*e21*e08-e03*e01*e28-e26*e02*e04+e26*e01*e05+e03*e02*e27+e20*e04*e08; +A[9 + 10*5]=e23*e12*e07-e26*e02*e14+e16*e21*e05-e23*e11*e08+e10*e24*e08-e20*e05*e17+e26*e11*e05+e26*e01*e15+e10*e04*e28+e00*e24*e18-e00*e15*e27+e03*e22*e17-e13*e01*e28+e23*e02*e17+e16*e01*e25+e20*e04*e18+e06*e11*e25+e13*e02*e27-e23*e01*e18-e20*e15*e07-e10*e25*e07+e13*e22*e07-e06*e22*e14-e26*e12*e04-e03*e11*e28-e03*e21*e18-e16*e22*e04-e16*e02*e24-e06*e12*e24+e06*e21*e15+e00*e14*e28-e00*e25*e17+e20*e14*e08-e13*e21*e08-e10*e05*e27+e03*e12*e27; +A[9 + 10*6]=-e13*e11*e28+e13*e12*e27+e13*e22*e17+e16*e11*e25+e10*e14*e28-e13*e21*e18-e23*e11*e18+e23*e12*e17+e20*e14*e18-e20*e15*e17+e26*e11*e15-e10*e15*e27-e10*e25*e17-e16*e22*e14-e16*e12*e24+e16*e21*e15-e26*e12*e14+e10*e24*e18; +A[9 + 10*7]=e26*e21*e05+e26*e01*e25+e20*e04*e28+e20*e24*e08-e20*e25*e07+e23*e22*e07+e03*e22*e27-e03*e21*e28-e26*e22*e04-e20*e05*e27-e00*e25*e27+e06*e21*e25-e06*e22*e24+e00*e24*e28-e26*e02*e24-e23*e21*e08-e23*e01*e28+e23*e02*e27; +A[9 + 10*8]=-e10*e25*e27+e10*e24*e28-e20*e15*e27-e20*e25*e17+e20*e14*e28+e20*e24*e18+e26*e11*e25+e23*e22*e17-e23*e11*e28+e23*e12*e27-e23*e21*e18-e13*e21*e28+e13*e22*e27-e26*e12*e24+e26*e21*e15-e16*e22*e24+e16*e21*e25-e26*e22*e14; +A[9 + 10*9]=-e20*e25*e27+e20*e24*e28-e23*e21*e28+e23*e22*e27-e26*e22*e24+e26*e21*e25; +A[9 + 10*10]=e03*e02*e37-e03*e31*e08-e03*e01*e38+e03*e32*e07-e00*e35*e07+e30*e04*e08+e06*e31*e05-e36*e02*e04+e36*e01*e05-e06*e32*e04-e06*e02*e34+e06*e01*e35+e00*e04*e38-e00*e05*e37+e33*e02*e07-e33*e01*e08-e30*e05*e07+e00*e34*e08; +A[9 + 10*11]=-e36*e12*e04+e30*e04*e18-e30*e15*e07-e36*e02*e14-e30*e05*e17+e30*e14*e08-e00*e35*e17-e00*e15*e37+e33*e02*e17-e06*e32*e14-e06*e12*e34-e16*e32*e04+e06*e31*e15+e06*e11*e35+e00*e34*e18-e10*e35*e07-e33*e11*e08-e33*e01*e18+e16*e01*e35-e16*e02*e34+e16*e31*e05-e03*e31*e18-e03*e11*e38+e03*e32*e17+e13*e02*e37-e13*e31*e08-e13*e01*e38+e10*e34*e08+e00*e14*e38+e36*e11*e05+e36*e01*e15+e03*e12*e37-e10*e05*e37+e10*e04*e38+e33*e12*e07+e13*e32*e07; +A[9 + 10*12]=-e36*e12*e14-e30*e15*e17+e13*e32*e17-e13*e31*e18-e33*e11*e18+e33*e12*e17+e10*e14*e38+e30*e14*e18-e13*e11*e38+e13*e12*e37-e10*e35*e17+e10*e34*e18-e16*e12*e34-e16*e32*e14+e16*e11*e35+e16*e31*e15+e36*e11*e15-e10*e15*e37; +A[9 + 10*13]=-e06*e22*e34-e06*e32*e24-e00*e25*e37-e00*e35*e27+e23*e02*e37+e00*e24*e38-e23*e01*e38-e03*e31*e28-e33*e01*e28+e03*e22*e37+e03*e32*e27+e33*e02*e27-e03*e21*e38-e26*e32*e04-e33*e21*e08+e36*e01*e25+e36*e21*e05-e20*e05*e37+e20*e04*e38+e30*e04*e28-e20*e35*e07+e33*e22*e07+e30*e24*e08-e30*e25*e07-e23*e31*e08+e23*e32*e07+e00*e34*e28+e06*e21*e35+e06*e31*e25-e36*e02*e24+e26*e01*e35-e36*e22*e04+e26*e31*e05-e26*e02*e34+e20*e34*e08-e30*e05*e27; +A[9 + 10*14]=e33*e22*e17+e33*e12*e27+e16*e21*e35-e16*e22*e34-e16*e32*e24+e23*e32*e17-e23*e11*e38-e23*e31*e18+e23*e12*e37-e13*e21*e38-e13*e31*e28+e13*e22*e37+e36*e21*e15-e36*e12*e24+e36*e11*e25-e26*e12*e34-e20*e35*e17+e20*e14*e38+e20*e34*e18+e30*e24*e18-e30*e15*e27-e30*e25*e17+e30*e14*e28-e33*e21*e18+e10*e34*e28+e10*e24*e38-e10*e35*e27-e10*e25*e37-e20*e15*e37-e26*e32*e14+e26*e11*e35+e26*e31*e15-e36*e22*e14+e13*e32*e27+e16*e31*e25-e33*e11*e28; +A[9 + 10*15]=-e20*e35*e27-e20*e25*e37+e20*e34*e28+e20*e24*e38+e30*e24*e28-e30*e25*e27+e23*e32*e27+e23*e22*e37-e23*e31*e28-e23*e21*e38+e33*e22*e27-e26*e22*e34-e26*e32*e24+e26*e21*e35+e26*e31*e25-e36*e22*e24+e36*e21*e25-e33*e21*e28; +A[9 + 10*16]=-e33*e01*e38-e03*e31*e38+e00*e34*e38+e33*e32*e07+e03*e32*e37+e06*e31*e35-e00*e35*e37-e36*e32*e04-e06*e32*e34-e36*e02*e34+e36*e01*e35+e36*e31*e05+e30*e04*e38+e30*e34*e08-e33*e31*e08+e33*e02*e37-e30*e05*e37-e30*e35*e07; +A[9 + 10*17]=-e33*e31*e18-e33*e11*e38+e10*e34*e38+e30*e14*e38-e10*e35*e37-e30*e15*e37-e13*e31*e38+e13*e32*e37-e30*e35*e17+e33*e12*e37+e30*e34*e18+e33*e32*e17+e16*e31*e35-e16*e32*e34-e36*e12*e34-e36*e32*e14+e36*e11*e35+e36*e31*e15; +A[9 + 10*18]=-e20*e35*e37+e20*e34*e38+e30*e24*e38-e30*e35*e27-e30*e25*e37+e30*e34*e28+e23*e32*e37-e23*e31*e38-e33*e21*e38-e33*e31*e28+e33*e22*e37+e33*e32*e27+e26*e31*e35-e26*e32*e34-e36*e22*e34-e36*e32*e24+e36*e21*e35+e36*e31*e25; +A[9 + 10*19]=-e33*e31*e38-e30*e35*e37+e36*e31*e35+e33*e32*e37+e30*e34*e38-e36*e32*e34; + +} diff --git a/Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.mexa64 b/Utils_FeatureMatching/subfunctions/calibrated_fivepoint_helper.mexa64 new file mode 100644 index 0000000000000000000000000000000000000000..9ce9b8893d210bd63351423d60cdef8fd23ba1eb GIT binary patch literal 147728 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 W|G_>_Yk&3~YX3jbuT=HP_Wy5%$8LN8 literal 0 HcmV?d00001 diff --git a/Utils_Metric/Eval_Metric.m b/Utils_Metric/Eval_Metric.m new file mode 100644 index 0000000..1a77c18 --- /dev/null +++ b/Utils_Metric/Eval_Metric.m @@ -0,0 +1,224 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Camera Exposure Control for Robust Robot Vision +% with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Name : Eval_Metric +% +% Modified: +% +% 17 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Input : path_name - path of dataset +% output : None +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [ ]= Eval_Metric(path_name) +close all; +clc; + +% Check number of inputs. +if nargin >2 + error('myfuns:somefun2:TooManyInputs', ... + 'requires at most 1 optional inputs'); +end + +% Flag for saving results +Save_flag = 1; + +% Read dataset list +output_folder =strcat(path_name(1:regexp(path_name,'DataSet_AE')-2),'\Results\Result_graph',path_name(regexp(path_name,'DataSet_AE')+10:length(path_name)-5)); + +mkdir(output_folder); +Files = dir(strcat(path_name,'\','*.jpg')); + +Results_Our = zeros(length(Files),3); +Results_Gradient = zeros(length(Files),3); +Results_Entropy = zeros(length(Files),3); +Results_Noise = zeros(length(Files),3); + +for k=1:length(Files) + fprintf('Path : %s, Processing %dth / %dth image .... \n',path_name,k,length(Files)); + + % Read files one-by-one + FileNames = Files(k).name; + FilePaths = strcat(path_name,'\',FileNames); + + % Parsing gain & Exposure time + index_iso = regexp(FileNames,'ISO-'); + index_exp = regexp(FileNames,'-ExpT-'); + index_jpg = regexp(FileNames,'.jpg'); + + ISO_ = FileNames(index_iso+4 : index_exp -1); + Exp_time_ = FileNames(index_exp+6 : index_jpg -1); + + % Evalutate images with a Image assessment metrics + [V_Ours, V_Gradient, V_Entropy, V_Noise] = Metric_Our(FilePaths); + + % Save each methods value + Results_Our(k,:) = [str2double(ISO_), str2double(Exp_time_), V_Ours ]; + Results_Entropy(k,:) = [str2double(ISO_), str2double(Exp_time_), V_Entropy ]; + Results_Gradient(k,:) = [str2double(ISO_), str2double(Exp_time_), V_Gradient ]; + Results_Noise(k,:) = [str2double(ISO_), str2double(Exp_time_), -V_Noise ]; +end + +% Write max value +if Save_flag == 1 + file_name = strcat(output_folder,'\','Selected_image_info.txt'); + fileID = fopen(file_name,'a'); + + % Save maximum point with Our metric + [~, idx] = max(Results_Our(:,3)); + MAX_value = Results_Our(idx,:); + str = strcat('Ours : ', ' ISO : ', num2str(MAX_value(1)),' E_T : ', num2str(MAX_value(2)), ' Value : ', num2str(MAX_value(3)), '\r\n'); + fprintf(fileID,str); + + % Save maximum point with Noise metric + [~, idx] = max(Results_Noise(:,3)); + MAX_value = Results_Noise(idx,:); + str = strcat('Noise : ', ' ISO : ', num2str(MAX_value(1)),' E_T : ', num2str(MAX_value(2)), ' Value : ', num2str(MAX_value(3)), '\r\n'); + fprintf(fileID,str); + + % Save maximum point with Entropy metric + [~, idx] = max(Results_Entropy(:,3)); + MAX_value = Results_Entropy(idx,:); + str = strcat('Entropy : ', ' ISO : ', num2str(MAX_value(1)),' E_T : ', num2str(MAX_value(2)), ' Value : ', num2str(MAX_value(3)), '\r\n'); + fprintf(fileID,str); + + % Save maximum point with Gradient metric + [~, idx] = max(Results_Gradient(:,3)); + MAX_value = Results_Gradient(idx,:); + str = strcat('Gradient : ', ' ISO : ', num2str(MAX_value(1)),' E_T : ', num2str(MAX_value(2)), ' Value : ', num2str(MAX_value(3)), '\r\n'); + fprintf(fileID,str); + + fclose(fileID); +end + +% plot values +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 1. Gradient-based Metric +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +x = unique(Results_Gradient(:,1)); +y = unique(Results_Gradient(:,2)); +[X,Y] = meshgrid(x,y); +Z = zeros(size(y,1),size(x,1)); + +for k = 1: size(Results_Gradient,1) + x_index = find( x == Results_Gradient(k,1)); + y_index = find( y == Results_Gradient(k,2)); + Z(y_index,x_index) = Results_Gradient(k,3); +end + +figure(1); +surfc(X,Y,Z); grid on; +xlabel('Gain(ISO)'); ylabel('Exposure Time(us)'); zlabel('Measure value'); title('Spatial Gradient Value Graph'); + +% save the result +if Save_flag == 1 + output = strcat(output_folder,'\','SpatialGradient'); +% saveas(gcf,output,'fig'); +% saveas(gcf,output,'pdf'); + saveas(gcf,output,'jpeg'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 2. Entropy-based Metric +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +x = unique(Results_Entropy(:,1)); +y = unique(Results_Entropy(:,2)); +[X,Y] = meshgrid(x,y); +Z = zeros(size(y,1),size(x,1)); + +for k = 1: size(Results_Entropy,1) + x_index = find( x == Results_Entropy(k,1)); + y_index = find( y == Results_Entropy(k,2)); + Z(y_index,x_index) = Results_Entropy(k,3); +end + +figure(2); +surfc(X,Y,Z); grid on; +xlabel('Gain(ISO)'); ylabel('Exposure Time(us)'); zlabel('Measure value'); title('Entropy Value Graph'); + +% save the result +if Save_flag == 1 + output = strcat(output_folder,'\','Entropy'); +% saveas(gcf,output,'fig'); +% saveas(gcf,output,'pdf'); + saveas(gcf,output,'jpeg'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 3. Noise-based Metric +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +x = unique(Results_Noise(:,1)); +y = unique(Results_Noise(:,2)); +[X,Y] = meshgrid(x,y); +Z = zeros(size(y,1),size(x,1)); + +for k = 1: size(Results_Noise,1) + x_index = find( x == Results_Noise(k,1)); + y_index = find( y == Results_Noise(k,2)); + Z(y_index,x_index) = Results_Noise(k,3); +end + +figure(3); +surfc(X,Y,Z); grid on; +xlabel('Gain(ISO)'); ylabel('Exposure Time(us)'); zlabel('Measure value'); title('Noise Value Graph'); + +% save the result +if Save_flag == 1 + output = strcat(output_folder,'\','Noise'); +% saveas(gcf,output,'fig'); +% saveas(gcf,output,'pdf'); + saveas(gcf,output,'jpeg'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 4. Ours: Grad + Noise + Entropy +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +x = unique(Results_Our(:,1)); +y = unique(Results_Our(:,2)); +[X,Y] = meshgrid(x,y); +Z = zeros(size(y,1),size(x,1)); +for k = 1: size(Results_Our,1) + x_index = find( x == Results_Our(k,1)); + y_index = find( y == Results_Our(k,2)); + Z(y_index,x_index) = Results_Our(k,3); + %fprintf('x: %d, y : %d, z: %d \n',list(k,1), list(k,2), list(k,3)) +end + +figure(4); +surfc(X,Y,Z); grid on; +xlabel('Gain(ISO)'); ylabel('Exposure Time(us)'); zlabel('Measure value'); title('Ours'); + +% save the result +if Save_flag == 1 + output = strcat(output_folder,'\','Ours'); +% saveas(gcf,output,'fig'); +% saveas(gcf,output,'pdf'); + saveas(gcf,output,'jpeg'); +end + +if Save_flag == 1 + output = strcat(output_folder,'\','workspace_result'); + save(output); +end +end + + diff --git a/Utils_Metric/Extract_Result.m b/Utils_Metric/Extract_Result.m new file mode 100644 index 0000000..4ae2943 --- /dev/null +++ b/Utils_Metric/Extract_Result.m @@ -0,0 +1,144 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Camera Exposure Control for Robust Robot Vision +% with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Name : Extract_Result +% : Extract result image of each image assessment metric and upsampled workspace. +% +% Modified: +% +% 17 December 2019 +% +% Author: +% +% Ukcheol Shin +% +% Input : path_name - Path of each dataset +% output : None +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function Extract_Result(path_name) +close all; +clc; + +% Check number of inputs. +if nargin >2 + error('myfuns:somefun2:TooManyInputs', ... + 'requires at most 1 optional inputs'); +end + +% Load workspace matlab file +path_result = strcat(path_name(1:regexp(path_name,'DataSet_AE')-2),'\Results'); +workspace_file = strcat(path_result,'\Result_graph', path_name(regexp(path_name,'DataSet_AE')+10:length(path_name)-5), '\workspace_result.mat'); +load(workspace_file); + +Left_folder = path_name; +Right_folder = strcat(path_name(1:length(path_name)-5),'\right'); + +% Make output directory +Output_folder =strcat(path_result,'\Result_Exp', path_name(regexp(path_name,'DataSet_AE')+10:length(path_name)-5)); +Result_left_folder = strcat(Output_folder,'\left'); +Result_right_folder = strcat(Output_folder,'\right'); + +mkdir(Result_left_folder); +mkdir(Result_right_folder); + +% Copy each algorithms result img +for i = 1 : length(Files) + + % parse ISO/Exposure time + FileNames = Files(i).name; + index = regexp(FileNames,'ISO-'); + index2 = regexp(FileNames,'-ExpT-'); + index3 = regexp(FileNames,'.jpg'); + ISO_ = str2double(FileNames(index+4 : index2 -1)); + Exp_time_ = str2double(FileNames(index2+6 : index3 -1)); + + ImgLeftFile = strcat(Left_folder,'\',Files(i).name); + ImgRightFile = strcat(Right_folder,'\',Files(i).name); + + % If the maximum points of each method are matches, copy the image. + [~, idx] = max(Results_Our(:,3)); + MAX_value = Results_Our(idx,:); + if(ISO_ == MAX_value(1)) + if(Exp_time_ == MAX_value(2)) + saveLeftFile = strcat(Result_left_folder,'\Ours_ISO-',num2str(ISO_),'-ExpT-',num2str(Exp_time_),'.jpg'); + saveRightFile = strcat(Result_right_folder,'\Ours_ISO-',num2str(ISO_),'-ExpT-',num2str(Exp_time_),'.jpg'); + copyfile(ImgLeftFile, saveLeftFile); + copyfile(ImgRightFile, saveRightFile); + end + end + + % Add other alogorithms result + +end + +% Copy camera built-in AutoExposuer result img +path_AE = strcat(path_name(1:length(path_name)-5),'\AE'); +Files_AE = dir(strcat(path_AE,'\','*.jpg')); + +for i = 1 : length(Files_AE) + + % parse ISO/Exposure time + FileNames = Files_AE(i).name; + index = regexp(FileNames,'ExpT-'); + index2 = regexp(FileNames,'-ISO-'); + index3 = regexp(FileNames,'.jpg'); + Exp_time_ = str2double(FileNames(index+5 : index2 -1)); + ISO_ = str2double(FileNames(index2+5 : index3 -1)); + + if(strcmp(FileNames(1:6), 'Param1')) + ImgRightFile = strcat(path_AE,'\',Files_AE(i).name); + saveRightFile = strcat(Result_right_folder,'\AE_ISO-',num2str(ISO_),'-ExpT-',num2str(Exp_time_),'.jpg'); + copyfile(ImgRightFile, saveRightFile); + elseif(strcmp(FileNames(1:6), 'Param2')) + ImgLeftFile = strcat(path_AE,'\',Files_AE(i).name); + saveLeftFile = strcat(Result_left_folder,'\AE_ISO-',num2str(ISO_),'-ExpT-',num2str(Exp_time_),'.jpg'); + copyfile(ImgLeftFile, saveLeftFile); + end + +end + +% Copy workspace file & upsampled results +saveWorkSpaceFile = strcat(Output_folder,'\workspace_result.mat'); +copyfile(workspace_file, saveWorkSpaceFile); + +interval_dB = 0.1; +interval_ExpT = 10; +min_dB = min(x); +max_dB = max(x); +min_ExpT = min(y); +max_ExpT = max(y); + +[Xq, Yq] = meshgrid( min_dB : interval_dB : max_dB, min_ExpT : interval_ExpT : max_ExpT); +Zq= interp2(X,Y,Z,Xq,Yq,'cubic'); + +% Display interpolated surface +%surfc(Xq,Yq,Zq); grid on; hold on; +%set(gca,'FontName', 'Times New Roman','FontSize',17); +%xlabel('Gain','fontsize',20, 'fontweight','bold'); ylabel('ExpT','fontsize',20, 'fontweight','bold'); zlabel('Metric value','fontsize',20, 'fontweight','bold'); +%view(-40,45) + +if(max_dB == 20) dataset_flag = 0; % outdoor +elseif(max_dB == 24) dataset_flag = 1; %indoor + +saveWorkSpaceFile = strcat(Output_folder,'\','workspace_upsampled_result'); +save(saveWorkSpaceFile,'Xq','Yq','Zq','path_name', 'dataset_flag', 'Results_Our','interval_dB', 'interval_ExpT'); + +disp('Done.') +end + + + diff --git a/Utils_Metric/Metric_Our.m b/Utils_Metric/Metric_Our.m new file mode 100644 index 0000000..9d4c635 --- /dev/null +++ b/Utils_Metric/Metric_Our.m @@ -0,0 +1,183 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Camera Exposure Control for Robust Robot Vision +% with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Name : Metric_Our +% Input : Img_path - Path of a image +% output : Value_Ours - Proposed image assessment value of the given image +% : Value_Grad - Gradient-based image assessment value of the given image +% : Value_Entorpy - Entropy-based image assessment value of the given image +% : Value_Noise - Noise-based image assessment value of the given image +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [Value_Ours, Value_Grad, Value_Entropy, Value_Noise] = Metric_Our(Img_path) + +% Set hyper parameters +Resize_factor = 1.0; +Alpha = 0.4; +Beta = 0.4; + +% hyper parameter for gradient-based metric +Kg = 2; +Lambda = 10^3; +Gamma = 0.06; + +% hyper parameter for noise-based metric +Ke = 0.125; % 1/8 +p = 0.10; +T_lower = 15; +T_upper = 235; + +% Set flag for display +plot_flag = 0; + +%% 1. Noise-based Metric +Img = imread(Img_path); +Img = imresize(Img,Resize_factor); +Value_Noise = zeros(size(Img,3),1); + +for Channel = 1 : size(Img,3) + Image = uint8(Img(:,:,Channel)); + + [H,W] = size(Image); + + % 1. Estimate homogenous region mask based on adaptive edge thresholding + [Image_Grad, ] = imgradient(double(Image), 'Sobel').^2; + Grad_1D = reshape(Image_Grad, [1,H*W]); % 1D histogram + Sort_Grad_1D = sort(Grad_1D); + Gth = Sort_Grad_1D(1,int32(H*W*p)); % p% = 0.10 + HomogenousRegionMask = double(Image_Grad <= Gth); + + % 2. Estimate Unsaturated mask + UnsaturatedMask = zeros(H,W); + for i = 1 : H + for j = 1: W + if(T_lower <= Image(i,j) && Image(i,j) <= T_upper) + UnsaturatedMask(i,j) = 1; + else + UnsaturatedMask(i,j) = 0; + end + end + end + + % 3. Get integrated mask + UnSaturatedHomogenousMask = UnsaturatedMask .* HomogenousRegionMask; + + % 4. Estimate Noise level of the image + Ng = [ 1, -2, 1 ; + -2, 4, -2 ; + 1, -2, 1 ]; + + Laplacian_Image = conv2(double(Image),double(Ng)); + Laplacian_Image = Laplacian_Image(2:H+1,2:W+1); + Masked_Laplacian_Image = Laplacian_Image.*UnSaturatedHomogenousMask; + + % In the paper, I was missed the number of "6", plz refer the equation + % from "Immerkaer, John. "Fast noise variance estimation." Computer vision and image understanding 64.2 (1996): 300-302." + Ns = sum(sum(UnSaturatedHomogenousMask)); + Value_Noise(Channel) = sqrt(pi/2) * (1/(6*Ns)) * sum(sum(abs(Masked_Laplacian_Image))); + + % If there are no reliable regions, we follows the original noise + % estimation equation. + if(sum(sum(UnSaturatedHomogenousMask)) < H*W*0.0001) + Value_Noise(Channel) = sqrt(pi/2)*(1/(6*(W-2)*(H-2)))*sum(sum(abs(Laplacian_Image))); + end + + %% 7. Plot + if plot_flag == 1 + figure; + subplot(2,4,1); + imagesc(Image); + title('Input Img'); + + subplot(2,4,2); + imagesc(uint8(255*Image_Grad)); + title('Gradient Map'); + + subplot(2,4,3); + imagesc(uint8(255*HomogenousRegionMask)); + title('homogenous Mask Image'); + + subplot(2,4,4); + imshow(UnsaturatedMask); + title('Unsaturated Mask Image'); + + subplot(2,4,5); + imshow(UnSaturatedHomogenousMask); + title('UnSaturated Homogenous Mask Image'); + + subplot(2,4,6); + imagesc(uint8(Laplacian_Image)); + title('Laplacian image'); + + subplot(2,4,7); + imagesc(uint8(Masked_Laplacian_Image)); + title('Masked Laplacian image'); + end +end + +% the camera we used has a Bayer pattern, so we multiply 2 on the green channel, +% but empirically 'R+G+B/3' shows almost similar results. +if (size(Img_path,3) == 3) + Value_Noise = (Value_Noise(1) + 2*Value_Noise(2) + Value_Noise(3)) / 4; +else + Value_Noise = mean(Value_Noise); +end + + +%% 2. Gradient-based Metric +gray_Image = rgb2gray(Img); +[H,W] = size(gray_Image); + +% 1.normalize gradient image +[Image_Grad,] = imgradient(gray_Image); +G_norm = Image_Grad./sqrt(16 * 255 * 255 + 16 * 255 * 255); % normalize + +% In the paper "Auto-adjusting camera exposure for outdoor robotics using gradient information, IROS2014." +% The author used lambda = 10^3, Gamma = 0.06 in all experiments, so we follow the setup. +Ng = log(Lambda.*(1-Gamma)+1); +Mapped_Grad = zeros(H,W); +for i=1:H + for j=1:W + if G_norm(i,j)>=Gamma + Mapped_Grad(i,j)= log(Lambda * (G_norm(i,j) - Gamma) + 1)./ Ng; + else + Mapped_Grad(i,j) = 0; + end + end +end + +% Estimate grid-level statistics of gradient metric +num = 10; % num x num grid +Gridded_Grad = zeros(num,num); + +for i = 1:num + for j = 1:num + Gridded_Grad(i,j) = mean2(Mapped_Grad(1+H/num * (i-1) : H/num * (i-1) +H/num, 1+W/num * (j-1) :W/num * (j-1) + W/num)); + end +end +Gridded_Grad_1D = reshape(Gridded_Grad, [num*num,1]); +Grad_mean = mean(Gridded_Grad_1D); +Std_num = std(Gridded_Grad_1D); +Value_Grad = Grad_mean / Std_num; + +%% 3. Entropy-based Metric +Value_Entropy = Ke*entropy(gray_Image); + +%% 4. Proposed Metric +% Kg is scalling factor and empirically decided. +Value_Ours = Alpha*Kg*Value_Grad + (1-Alpha)*Value_Entropy - Beta*Value_Noise; +end \ No newline at end of file diff --git a/Utils_Metric/Test_HyperParam.m b/Utils_Metric/Test_HyperParam.m new file mode 100644 index 0000000..3407bd3 --- /dev/null +++ b/Utils_Metric/Test_HyperParam.m @@ -0,0 +1,105 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Camera Exposure Control for Robust Robot Vision +% with Noise-Aware Image Assessment Metric +% +% Ukcheol Shin, Jinsun Park, Gyumin Shim, Francois Rameau, and In So Kweon +% +% IROS 2019 +% +% Please feel free to contact if you have any problems. +% +% E-mail : Ukcheol Shin (shinwc159@gmail.com / shinwc159@kaist.ac.kr) +% Robotics and Computer Vision Lab., EE, +% KAIST, Republic of Korea +% +% Project Page : https://sites.google.com/view/noise-aware-exposure-control +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Name : Test_HyperParam +% : Test hyper parameter of proposed metric +% Input : path_name - Path of each dataset +% output : None +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function Test_HyperParam(path_name) +close all; +clc; + +% Check number of inputs. +if nargin >2 + error('myfuns:somefun2:TooManyInputs', ... + 'requires at most 1 optional inputs'); +end + +% load workspace matlab file +path_result = strcat(path_name(1:regexp(path_name,'DataSet_AE')-2),'\Results'); +workspace_file = strcat(path_result,'\Result_graph', path_name(regexp(path_name,'DataSet_AE')+10:length(path_name)-5), '\workspace_result.mat'); +load(workspace_file); + +Left_folder = path_name; +Right_folder = strcat(path_name(1:length(path_name)-5),'\right'); + +% make output directory +Output_folder =strcat(path_result,'\Result_HypeParam', path_name(regexp(path_name,'DataSet_AE')+10:length(path_name)-5)); +Result_left_folder = strcat(Output_folder,'\left'); +Result_right_folder = strcat(Output_folder,'\right'); + +mkdir(Output_folder); +mkdir(Result_left_folder); +mkdir(Result_right_folder); + +file_name = strcat(Output_folder,'\','max_value.txt'); +fileID = fopen(file_name,'a'); + +Test_Our = Results_Our; +Kg = 2; + +% Test hyper parameter +for Alpha = 0 : 0.2 : 1.0 + for Beta = 0 : 0.1 : 1 + fprintf('alpha : %d , beta : %d \n',Alpha,Beta); + Test_Our(:,3) = Alpha*Kg*Results_Gradient(:,3) + (1-Alpha)*Results_Entropy(:,3) - Beta*Results_Noise(:,3); + + % Write a result + [~, idx] = max(Test_Our(:,3)); + MAX_value = Test_Our(idx,:); + str = strcat('Alpha : ', num2str(Alpha), ' Beta : ', num2str(Beta) , ' ISO : ', num2str(MAX_value(1)),' E_T : ', num2str(MAX_value(2)), ' Value : ', num2str(MAX_value(3)), '\r\n'); + fprintf(fileID,str); + + % Copy left/right images according to the each maximum point + ImgLeftFile = strcat(Left_folder,'\',Files(idx).name); + ImgRightFile = strcat(Right_folder,'\',Files(idx).name); + + saveLeftFile = strcat(Result_left_folder,'\alpha_',num2str(Alpha*10),'_beta_',num2str(Beta*10), '_ISO-',num2str(MAX_value(1)),'-ExpT-',num2str(MAX_value(2)),'.jpg'); + saveRightFile = strcat(Result_right_folder,'\alpha_',num2str(Alpha*10),'_beta_',num2str(Beta*10), '_ISO-',num2str(MAX_value(1)),'-ExpT-',num2str(MAX_value(2)),'.jpg'); + copyfile(ImgLeftFile, saveLeftFile); + copyfile(ImgRightFile, saveRightFile); + + % plot values + figure(1); + x = unique(Test_Our(:,1)); + y = unique(Test_Our(:,2)); + [X,Y] = meshgrid(x,y); + Z = zeros(size(y,1),size(x,1)); + for k = 1: size(Test_Our,1) + x_index = find( x == Test_Our(k,1)); + y_index = find( y == Test_Our(k,2)); + Z(y_index,x_index) = Test_Our(k,3); + %fprintf('x: %d, y : %d, z: %d \n',list(k,1), list(k,2), list(k,3)) + end + + surfc(X,Y,Z); grid on; + xlabel('Gain(ISO)'); ylabel('Exposure Time(us)'); zlabel('Measure value'); + title('Ours'); + output = strcat(Output_folder,'\','Ours_Alpha_', num2str(Alpha*10), '_Beta_', num2str(Beta*10)); + %saveas(gcf,output,'fig'); + %saveas(gcf,output,'pdf'); + saveas(gcf,output,'jpeg'); + end +end + +fclose(fileID); +end + + +