Added eval; site now shows clean dataset missing message instead of server error...
[sgn.git] / lib / SGN / Controller / AJAX / DroneImagery / DroneImagery.pm
blobccdb201281e6670e42a5fac4b8066616f76d5715
2 =head1 NAME
4 SGN::Controller::AJAX::DroneImagery::DroneImagery - a REST controller class to provide the
5 functions for uploading and analyzing drone imagery
7 =head1 DESCRIPTION
9 =head1 AUTHOR
11 =cut
13 package SGN::Controller::AJAX::DroneImagery::DroneImagery;
15 use Moose;
16 use Data::Dumper;
17 use LWP::UserAgent;
18 use JSON;
19 use SGN::Model::Cvterm;
20 use DateTime;
21 use CXGN::UploadFile;
22 use SGN::Image;
23 use CXGN::DroneImagery::ImagesSearch;
24 use URI::Encode qw(uri_encode uri_decode);
25 use File::Basename qw | basename dirname|;
26 use File::Slurp qw(write_file);
27 use File::Temp 'tempfile';
28 use CXGN::Calendar;
29 use Image::Size;
30 use Text::CSV;
31 use CXGN::Phenotypes::StorePhenotypes;
32 use CXGN::Phenotypes::PhenotypeMatrix;
33 use CXGN::BrAPI::FileResponse;
34 use CXGN::Onto;
35 use R::YapRI::Base;
36 use R::YapRI::Data::Matrix;
37 use CXGN::Tag;
38 use CXGN::DroneImagery::ImageTypes;
39 use Time::Piece;
40 use POSIX;
41 use Math::Round;
42 use Parallel::ForkManager;
43 use CXGN::NOAANCDC;
44 use CXGN::BreederSearch;
45 use CXGN::Phenotypes::SearchFactory;
46 use CXGN::BreedersToolbox::Accessions;
47 use CXGN::Genotype::GRM;
48 use CXGN::Pedigree::ARM;
49 use CXGN::AnalysisModel::SaveModel;
50 use CXGN::AnalysisModel::GetModel;
51 use Math::Polygon;
52 use Math::Trig;
53 use List::MoreUtils qw(first_index);
54 use List::Util qw(sum);
55 use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
56 use Spreadsheet::WriteExcel;
57 use CXGN::Location;
58 #use Inline::Python;
60 BEGIN { extends 'Catalyst::Controller::REST' }
62 __PACKAGE__->config(
63 default => 'application/json',
64 stash_key => 'rest',
65 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
68 sub raw_drone_imagery_plot_image_count : Path('/api/drone_imagery/raw_drone_imagery_plot_image_count') : ActionClass('REST') { }
69 sub raw_drone_imagery_plot_image_count_GET : Args(0) {
70 my $self = shift;
71 my $c = shift;
72 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
73 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
75 my $drone_run_band_drone_run_relationship_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
77 my $project_image_type_id_hash = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
78 my $sql = join ("," , (keys %$project_image_type_id_hash));
79 my $q = "SELECT drone_run.project_id, project_image_type.name, project_image_type.cvterm_id
80 FROM project AS drone_run_band
81 JOIN project_relationship AS drone_run_band_rel ON(drone_run_band.project_id=drone_run_band_rel.subject_project_id AND drone_run_band_rel.type_id=$drone_run_band_drone_run_relationship_id)
82 JOIN project AS drone_run ON(drone_run.project_id=drone_run_band_rel.object_project_id)
83 JOIN phenome.project_md_image AS project_image ON(drone_run_band.project_id=project_image.project_id)
84 JOIN cvterm AS project_image_type ON(project_image_type.cvterm_id=project_image.type_id)
85 JOIN metadata.md_image AS image ON(image.image_id=project_image.image_id)
86 WHERE project_image.type_id in ($sql) AND image.obsolete='f';";
88 #print STDERR Dumper $q;
89 my $h = $schema->storage->dbh()->prepare($q);
90 $h->execute();
92 my %unique_drone_runs;
93 while (my ($drone_run_project_id, $project_image_type_name, $project_image_type_id) = $h->fetchrow_array()) {
94 $unique_drone_runs{$drone_run_project_id}->{$project_image_type_id_hash->{$project_image_type_id}->{display_name}}++;
95 $unique_drone_runs{$drone_run_project_id}->{total_plot_image_count}++;
97 #print STDERR Dumper \%unique_drone_runs;
99 $c->stash->{rest} = { data => \%unique_drone_runs };
102 sub drone_imagery_analysis_query : Path('/api/drone_imagery/analysis_query') : ActionClass('REST') { }
103 sub drone_imagery_analysis_query_POST : Args(0) {
104 my $self = shift;
105 my $c = shift;
106 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
107 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
108 my ($user_id, $user_name, $user_role) = _check_user_login($c);
109 my $main_production_site = $c->config->{main_production_site_url};
111 my $project_image_type_id_list_all = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
112 my @project_image_type_id_list_array = keys %$project_image_type_id_list_all;
114 my $trait_id_list = $c->req->param('observation_variable_id_list') ? decode_json $c->req->param('observation_variable_id_list') : [];
115 my $return_format = $c->req->param('format') || 'csv';
116 my $trial_name_list = $c->req->param('trial_name_list');
117 my $trial_id_list = $c->req->param('field_trial_id_list') ? decode_json $c->req->param('field_trial_id_list') : [];
118 my $project_image_type_id_list = $c->req->param('project_image_type_id_list') ? decode_json $c->req->param('project_image_type_id_list') : \@project_image_type_id_list_array;
120 my %return;
122 if ($trial_name_list) {
123 my @trial_names = split ',', $trial_name_list;
124 my $trial_search = CXGN::Trial::Search->new({
125 bcs_schema=>$schema,
126 trial_name_list=>\@trial_names
128 my ($result, $total_count) = $trial_search->search();
129 foreach (@$result) {
130 push @$trial_id_list, $_->{trial_id};
134 my @drone_run_band_project_id_list;
135 foreach (@$trial_id_list) {
136 my $trial = CXGN::Trial->new({bcs_schema => $schema, trial_id => $_});
137 my $drone_run_bands = $trial->get_drone_run_bands_from_field_trial();
138 foreach my $d (@$drone_run_bands) {
139 push @drone_run_band_project_id_list, $d->[0];
143 print STDERR Dumper \@drone_run_band_project_id_list;
144 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
145 bcs_schema=>$schema,
146 drone_run_band_project_id_list=>\@drone_run_band_project_id_list,
147 project_image_type_id_list=>$project_image_type_id_list
149 my ($result, $total_count) = $images_search->search();
150 print STDERR "Query found ".scalar(@$result)." Images\n";
152 my %image_data_hash;
153 my %project_image_type_names;
154 foreach (@$result) {
155 my $image_id = $_->{image_id};
156 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
157 my $image_url = $image->get_image_url("original");
158 my $image_fullpath = $image->get_filename('original_converted', 'full');
159 push @{$image_data_hash{$_->{stock_id}}->{$_->{drone_run_band_project_name}.$_->{project_image_type_name}}}, $main_production_site.$image_url;
160 $project_image_type_names{$_->{drone_run_band_project_name}.$_->{project_image_type_name}}++;
162 my @project_image_names_list = sort keys %project_image_type_names;
164 my %data_hash;
165 my $phenotypes_search = CXGN::Phenotypes::PhenotypeMatrix->new(
166 bcs_schema=>$schema,
167 search_type=>'MaterializedViewTable',
168 data_level=>'plot',
169 trait_list=>$trait_id_list,
170 trial_list=>$trial_id_list,
171 include_timestamp=>0,
172 exclude_phenotype_outlier=>0,
174 my @data = $phenotypes_search->get_phenotype_matrix();
176 my $phenotype_header = shift @data;
177 my @total_phenotype_header = (@$phenotype_header, @project_image_names_list);
178 foreach (@data) {
179 $data_hash{$_->[21]} = $_;
182 while (my($stock_id, $image_info_hash) = each %image_data_hash) {
183 foreach (@project_image_names_list) {
184 my $image_string = $image_info_hash->{$_} ? join ',', @{$image_info_hash->{$_}} : '';
185 push @{$data_hash{$stock_id}}, $image_string;
188 #print STDERR Dumper \%data_hash;
189 my @data_array = values %data_hash;
190 my @data_total = (\@total_phenotype_header, @data_array);
192 if ($return_format eq 'csv') {
193 my $dir = $c->tempfiles_subdir('download');
194 my ($download_file_path, $download_uri) = $c->tempfile( TEMPLATE => 'download/drone_imagery_analysis_csv_'.'XXXXX', SUFFIX => ".csv");
195 my $file_response = CXGN::BrAPI::FileResponse->new({
196 absolute_file_path => $download_file_path,
197 absolute_file_uri => $main_production_site.$download_uri,
198 format => $return_format,
199 data => \@data_total
201 my @data_files = $file_response->get_datafiles();
202 $return{file} = $data_files[0];
203 } elsif ($return_format eq 'xls') {
204 my $dir = $c->tempfiles_subdir('download');
205 my ($download_file_path, $download_uri) = $c->tempfile( TEMPLATE => 'download/drone_imagery_analysis_xls_'.'XXXXX', SUFFIX => ".xls");
206 my $file_response = CXGN::BrAPI::FileResponse->new({
207 absolute_file_path => $download_file_path,
208 absolute_file_uri => $main_production_site.$download_uri,
209 format => $return_format,
210 data => \@data_total
212 my @data_files = $file_response->get_datafiles();
213 $return{file} = $data_files[0];
214 } elsif ($return_format eq 'json') {
215 $return{header} = \@total_phenotype_header;
216 $return{data} = \@data_array;
219 $c->stash->{rest} = \%return;
222 sub drone_imagery_calculate_statistics : Path('/api/drone_imagery/calculate_statistics') : ActionClass('REST') { }
223 sub drone_imagery_calculate_statistics_POST : Args(0) {
224 my $self = shift;
225 my $c = shift;
226 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
227 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
228 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
229 my ($user_id, $user_name, $user_role) = _check_user_login($c);
231 my $statistics_select = $c->req->param('statistics_select');
232 my $field_trial_id_list = $c->req->param('field_trial_id_list') ? decode_json $c->req->param('field_trial_id_list') : [];
233 my $field_trial_id_list_string = join ',', @$field_trial_id_list;
235 if (scalar(@$field_trial_id_list) != 1) {
236 $c->stash->{rest} = { error => "Please select one field trial!"};
237 return;
240 my $trait_id_list = $c->req->param('observation_variable_id_list') ? decode_json $c->req->param('observation_variable_id_list') : [];
241 my $compute_relationship_matrix_from_htp_phenotypes = $c->req->param('relationship_matrix_type') || 'genotypes';
242 my $compute_relationship_matrix_from_htp_phenotypes_type = $c->req->param('htp_pheno_rel_matrix_type');
243 my $compute_relationship_matrix_from_htp_phenotypes_time_points = $c->req->param('htp_pheno_rel_matrix_time_points');
244 my $compute_relationship_matrix_from_htp_phenotypes_blues_inversion = $c->req->param('htp_pheno_rel_matrix_blues_inversion');
245 my $compute_from_parents = $c->req->param('compute_from_parents') eq 'yes' ? 1 : 0;
246 my $include_pedgiree_info_if_compute_from_parents = $c->req->param('include_pedgiree_info_if_compute_from_parents') eq 'yes' ? 1 : 0;
247 my $use_parental_grms_if_compute_from_parents = $c->req->param('use_parental_grms_if_compute_from_parents') eq 'yes' ? 1 : 0;
248 my $use_area_under_curve = $c->req->param('use_area_under_curve') eq 'yes' ? 1 : 0;
249 my $protocol_id = $c->req->param('protocol_id');
250 my $tolparinv = $c->req->param('tolparinv');
251 my $legendre_order_number = $c->req->param('legendre_order_number');
252 my $permanent_environment_structure = $c->req->param('permanent_environment_structure');
253 my $permanent_environment_structure_phenotype_correlation_traits = $c->req->param('permanent_environment_structure_phenotype_correlation_traits') ? decode_json $c->req->param('permanent_environment_structure_phenotype_correlation_traits') : [];
255 my $shared_cluster_dir_config = $c->config->{cluster_shared_tempdir};
256 my $tmp_stats_dir = $shared_cluster_dir_config."/tmp_drone_statistics";
257 mkdir $tmp_stats_dir if ! -d $tmp_stats_dir;
258 my ($grm_rename_tempfile_fh, $grm_rename_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
259 $grm_rename_tempfile .= '.grm';
260 my ($permanent_environment_structure_tempfile_fh, $permanent_environment_structure_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
261 my ($stats_tempfile_fh, $stats_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
262 my ($stats_tempfile_rename_fh, $stats_tempfile_rename) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
263 my ($stats_tempfile_2_fh, $stats_tempfile_2) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
264 $stats_tempfile_2 .= '.dat';
265 my ($stats_prep_tempfile_fh, $stats_prep_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
266 my ($stats_prep_factor_tempfile_fh, $stats_prep_factor_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
267 my ($stats_prep2_tempfile_fh, $stats_prep2_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
268 my ($parameter_tempfile_fh, $parameter_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
269 $parameter_tempfile .= '.f90';
270 my ($coeff_genetic_tempfile_fh, $coeff_genetic_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
271 $coeff_genetic_tempfile .= '_genetic_coefficients.csv';
272 my ($coeff_pe_tempfile_fh, $coeff_pe_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
273 $coeff_pe_tempfile .= '_permanent_environment_coefficients.csv';
275 my $dir = $c->tempfiles_subdir('/tmp_drone_statistics');
276 my $stats_out_tempfile_string = $c->tempfile( TEMPLATE => 'tmp_drone_statistics/drone_stats_XXXXX');
277 my $stats_out_tempfile = $c->config->{basepath}."/".$stats_out_tempfile_string;
279 my ($stats_out_htp_rel_tempfile_input_fh, $stats_out_htp_rel_tempfile_input) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
280 my ($stats_out_htp_rel_tempfile_fh, $stats_out_htp_rel_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
282 my $stats_out_htp_rel_tempfile_out_string = $c->tempfile( TEMPLATE => 'tmp_drone_statistics/drone_stats_XXXXX');
283 my $stats_out_htp_rel_tempfile_out = $c->config->{basepath}."/".$stats_out_htp_rel_tempfile_out_string;
285 my ($stats_out_pe_pheno_rel_tempfile_fh, $stats_out_pe_pheno_rel_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
286 my ($stats_out_pe_pheno_rel_tempfile2_fh, $stats_out_pe_pheno_rel_tempfile2) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
288 my ($stats_out_param_tempfile_fh, $stats_out_param_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
289 my ($stats_out_tempfile_row_fh, $stats_out_tempfile_row) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
290 my ($stats_out_tempfile_col_fh, $stats_out_tempfile_col) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
291 my ($stats_out_tempfile_2dspl_fh, $stats_out_tempfile_2dspl) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
292 my ($stats_out_tempfile_residual_fh, $stats_out_tempfile_residual) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
293 my ($stats_out_tempfile_genetic_fh, $stats_out_tempfile_genetic) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
294 my ($stats_out_tempfile_permanent_environment_fh, $stats_out_tempfile_permanent_environment) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
295 my $blupf90_solutions_tempfile;
296 my $yhat_residual_tempfile;
297 my $grm_file;
299 my @results;
300 my $result_blup_data;
301 my $result_blup_data_delta;
302 my $result_blup_spatial_data;
303 my $result_blup_pe_data;
304 my $result_blup_pe_data_delta;
305 my $result_residual_data;
306 my $result_fitted_data;
307 my @sorted_trait_names;
308 my @sorted_trait_names_original;
309 my @sorted_residual_trait_names;
310 my %seen_trait_names;
311 my %trait_to_time_map;
312 my @sorted_scaled_ln_times;
313 my @rep_time_factors;
314 my @ind_rep_factors;
315 my %accession_id_factor_map;
316 my %accession_id_factor_map_reverse;
317 my %plot_id_factor_map_reverse;
318 my %plot_id_count_map_reverse;
319 my %time_count_map_reverse;
320 my @unique_accession_names;
321 my @unique_plot_names;
322 my $statistical_ontology_term;
323 my $analysis_result_values_type;
324 my $analysis_model_language = "R";
325 my $analysis_model_training_data_file_type;
326 my $field_trial_design;
327 my $model_sum_square_residual;
328 my %trait_composing_info;
329 my $time_max;
330 my $time_min;
331 my $min_row = 10000000000;
332 my $max_row = 0;
333 my $min_col = 10000000000;
334 my $max_col = 0;
336 my @legendre_coeff_exec = (
337 '1 * $b',
338 '$time * $b',
339 '(1/2*(3*$time**2 - 1)*$b)',
340 '1/2*(5*$time**3 - 3*$time)*$b',
341 '1/8*(35*$time**4 - 30*$time**2 + 3)*$b',
342 '1/16*(63*$time**5 - 70*$time**2 + 15*$time)*$b',
343 '1/16*(231*$time**6 - 315*$time**4 + 105*$time**2 - 5)*$b'
346 foreach my $field_trial_id (@$field_trial_id_list) {
347 my $field_trial_design_full = CXGN::Trial->new({bcs_schema => $schema, trial_id=>$field_trial_id})->get_layout()->get_design();
348 while (my($plot_number, $plot_obj) = each %$field_trial_design_full) {
349 my $plot_number_unique = $field_trial_id."_".$plot_number;
350 $field_trial_design->{$plot_number_unique} = {
351 stock_name => $plot_obj->{accession_name},
352 block_number => $plot_obj->{block_number},
353 col_number => $plot_obj->{col_number},
354 row_number => $plot_obj->{row_number},
355 plot_name => $plot_obj->{plot_name},
356 plot_number => $plot_number_unique,
357 rep_number => $plot_obj->{rep_number},
358 is_a_control => $plot_obj->{is_a_control}
363 my $drone_run_related_time_cvterms_json_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_related_time_cvterms_json', 'project_property')->cvterm_id();
364 my $drone_run_field_trial_project_relationship_type_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
365 my $drone_run_band_drone_run_project_relationship_type_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
366 my $drone_run_time_q = "SELECT drone_run_project.project_id, project_relationship.object_project_id, projectprop.value
367 FROM project AS drone_run_band_project
368 JOIN project_relationship AS drone_run_band_rel ON (drone_run_band_rel.subject_project_id = drone_run_band_project.project_id AND drone_run_band_rel.type_id = $drone_run_band_drone_run_project_relationship_type_id_cvterm_id)
369 JOIN project AS drone_run_project ON (drone_run_project.project_id = drone_run_band_rel.object_project_id)
370 JOIN project_relationship ON (drone_run_project.project_id = project_relationship.subject_project_id AND project_relationship.type_id=$drone_run_field_trial_project_relationship_type_id_cvterm_id)
371 LEFT JOIN projectprop ON (drone_run_band_project.project_id = projectprop.project_id AND projectprop.type_id=$drone_run_related_time_cvterms_json_cvterm_id)
372 WHERE project_relationship.object_project_id IN ($field_trial_id_list_string) ;";
373 my $h = $schema->storage->dbh()->prepare($drone_run_time_q);
374 $h->execute();
375 my $refresh_mat_views = 0;
376 while( my ($drone_run_project_id, $field_trial_project_id, $related_time_terms_json) = $h->fetchrow_array()) {
377 my $related_time_terms;
378 if (!$related_time_terms_json) {
379 $related_time_terms = _perform_gdd_calculation_and_drone_run_time_saving($c, $schema, $field_trial_project_id, $drone_run_project_id, $c->config->{noaa_ncdc_access_token}, 50, 'average_daily_temp_sum');
380 $refresh_mat_views = 1;
382 else {
383 $related_time_terms = decode_json $related_time_terms_json;
385 if (!exists($related_time_terms->{gdd_average_temp})) {
386 $related_time_terms = _perform_gdd_calculation_and_drone_run_time_saving($c, $schema, $field_trial_project_id, $drone_run_project_id, $c->config->{noaa_ncdc_access_token}, 50, 'average_daily_temp_sum');
387 $refresh_mat_views = 1;
390 if ($refresh_mat_views) {
391 my $bs = CXGN::BreederSearch->new( { dbh=>$c->dbc->dbh, dbname=>$c->config->{dbname}, } );
392 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'fullview', 'nonconcurrent', $c->config->{basepath});
393 sleep(10);
396 my %trait_name_encoder;
397 my %trait_name_encoder_rev;
398 my $trait_name_encoded = 1;
399 my %phenotype_data;
400 my %stock_info;
401 my %stock_name_row_col;
402 my %unique_accessions;
403 my %seen_days_after_plantings;
404 my %seen_times;
405 my @data_matrix;
406 my %obsunit_row_col;
407 my %seen_plot_names;
408 my %plot_id_map;
410 if ($statistics_select eq 'lmer_germplasmname_replicate' || $statistics_select eq 'sommer_grm_spatial_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'sommer_grm_genetic_blups') {
412 if ($statistics_select eq 'lmer_germplasmname_replicate' || $statistics_select eq 'sommer_grm_spatial_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_blups') {
414 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
415 'MaterializedViewTable',
417 bcs_schema=>$schema,
418 data_level=>'plot',
419 trait_list=>$trait_id_list,
420 trial_list=>$field_trial_id_list,
421 include_timestamp=>0,
422 exclude_phenotype_outlier=>0
425 my ($data, $unique_traits) = $phenotypes_search->search();
426 @sorted_trait_names = sort keys %$unique_traits;
427 @sorted_trait_names_original = sort keys %$unique_traits;
429 if (scalar(@$data) == 0) {
430 $c->stash->{rest} = { error => "There are no phenotypes for the trials and traits you have selected!"};
431 return;
434 my %seen_trait_names;
435 foreach my $obs_unit (@$data){
436 my $germplasm_name = $obs_unit->{germplasm_uniquename};
437 my $germplasm_stock_id = $obs_unit->{germplasm_stock_id};
438 my $replicate_number = $obs_unit->{obsunit_rep} || '';
439 my $block_number = $obs_unit->{obsunit_block} || '';
440 my $obsunit_stock_id = $obs_unit->{observationunit_stock_id};
441 my $obsunit_stock_uniquename = $obs_unit->{observationunit_uniquename};
442 my $row_number = $obs_unit->{obsunit_row_number} || '';
443 my $col_number = $obs_unit->{obsunit_col_number} || '';
444 $unique_accessions{$germplasm_name}++;
445 $stock_info{"S".$germplasm_stock_id} = {
446 uniquename => $germplasm_name
448 $stock_name_row_col{$obsunit_stock_uniquename} = {
449 row_number => $row_number,
450 col_number => $col_number,
451 obsunit_stock_id => $obsunit_stock_id,
452 obsunit_name => $obsunit_stock_uniquename,
453 rep => $replicate_number,
454 block => $block_number,
455 germplasm_stock_id => $germplasm_stock_id,
456 germplasm_name => $germplasm_name
459 if ($row_number < $min_row) {
460 $min_row = $row_number;
462 elsif ($row_number >= $max_row) {
463 $max_row = $row_number;
465 if ($col_number < $min_col) {
466 $min_col = $col_number;
468 elsif ($col_number >= $max_col) {
469 $max_col = $col_number;
472 my $observations = $obs_unit->{observations};
473 foreach (@$observations){
474 my $trait_name = $_->{trait_name};
475 $phenotype_data{$obsunit_stock_uniquename}->{$trait_name} = $_->{value};
476 $seen_trait_names{$trait_name}++;
478 if ($_->{associated_image_project_time_json}) {
479 my $related_time_terms_json = decode_json $_->{associated_image_project_time_json};
480 my $time_days_cvterm = $related_time_terms_json->{day};
481 my $time_term_string = $time_days_cvterm;
482 my $time_days = (split '\|', $time_days_cvterm)[0];
483 my $time_value = (split ' ', $time_days)[1];
484 $seen_days_after_plantings{$time_value}++;
485 $trait_to_time_map{$trait_name} = $time_value;
489 @unique_accession_names = sort keys %unique_accessions;
491 foreach my $trait_name (@sorted_trait_names) {
492 if (!exists($trait_name_encoder{$trait_name})) {
493 my $trait_name_e = 't'.$trait_name_encoded;
494 $trait_name_encoder{$trait_name} = $trait_name_e;
495 $trait_name_encoder_rev{$trait_name_e} = $trait_name;
496 $trait_name_encoded++;
500 my %seen_trial_ids;
501 foreach (@$data) {
502 my $germplasm_name = $_->{germplasm_uniquename};
503 my $germplasm_stock_id = $_->{germplasm_stock_id};
504 my $obsunit_stock_id = $_->{observationunit_stock_id};
505 my $obsunit_stock_uniquename = $_->{observationunit_uniquename};
506 my $row_number = $_->{obsunit_row_number} || '';
507 my $col_number = $_->{obsunit_col_number} || '';
508 my @row = ($_->{obsunit_rep}, $_->{obsunit_block}, "S".$germplasm_stock_id, $obsunit_stock_id, $row_number, $col_number, $row_number, $col_number);
509 $obsunit_row_col{$row_number}->{$col_number} = {
510 stock_id => $obsunit_stock_id,
511 stock_uniquename => $obsunit_stock_uniquename
513 $plot_id_map{$obsunit_stock_id} = $obsunit_stock_uniquename;
514 $seen_plot_names{$obsunit_stock_uniquename}++;
515 $seen_trial_ids{$_->{trial_id}}++;
516 foreach my $t (@sorted_trait_names) {
517 if (defined($phenotype_data{$obsunit_stock_uniquename}->{$t})) {
518 push @row, $phenotype_data{$obsunit_stock_uniquename}->{$t} + 0;
519 } else {
520 print STDERR $obsunit_stock_uniquename." : $t : $germplasm_name : NA \n";
521 push @row, 'NA';
524 push @data_matrix, \@row;
527 my %unique_traits_ids;
528 foreach (keys %seen_trial_ids){
529 my $trial = CXGN::Trial->new({bcs_schema=>$schema, trial_id=>$_});
530 my $traits_assayed = $trial->get_traits_assayed('plot', undef, 'time_ontology');
531 foreach (@$traits_assayed) {
532 $unique_traits_ids{$_->[0]} = $_;
535 foreach (values %unique_traits_ids) {
536 foreach my $component (@{$_->[2]}) {
537 if (exists($seen_trait_names{$_->[1]}) && $component->{cv_type} && $component->{cv_type} eq 'time_ontology') {
538 my $time_term_string = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $component->{cvterm_id}, 'extended');
539 push @{$trait_composing_info{$_->[1]}}, $time_term_string;
544 my @phenotype_header = ("replicate", "block", "id", "plot_id", "rowNumber", "colNumber", "rowNumberFactor", "colNumberFactor");
545 my $num_col_before_traits = scalar(@phenotype_header);
546 foreach (@sorted_trait_names) {
547 push @phenotype_header, $trait_name_encoder{$_};
549 my $header_string = join ',', @phenotype_header;
551 open(my $F, ">", $stats_tempfile) || die "Can't open file ".$stats_tempfile;
552 print $F $header_string."\n";
553 foreach (@data_matrix) {
554 my $line = join ',', @$_;
555 print $F "$line\n";
557 close($F);
559 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups') {
561 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
562 'MaterializedViewTable',
564 bcs_schema=>$schema,
565 data_level=>'plot',
566 trait_list=>$trait_id_list,
567 trial_list=>$field_trial_id_list,
568 include_timestamp=>0,
569 exclude_phenotype_outlier=>0
572 my ($data, $unique_traits) = $phenotypes_search->search();
573 @sorted_trait_names = sort keys %$unique_traits;
575 if (scalar(@$data) == 0) {
576 $c->stash->{rest} = { error => "There are no phenotypes for the trials and traits you have selected!"};
577 return;
580 my $q_time = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
581 my $h_time = $schema->storage->dbh()->prepare($q_time);
583 my %seen_plot_names;
584 foreach my $obs_unit (@$data){
585 my $germplasm_name = $obs_unit->{germplasm_uniquename};
586 my $germplasm_stock_id = $obs_unit->{germplasm_stock_id};
587 my $replicate_number = $obs_unit->{obsunit_rep} || '';
588 my $block_number = $obs_unit->{obsunit_block} || '';
589 my $obsunit_stock_id = $obs_unit->{observationunit_stock_id};
590 my $obsunit_stock_uniquename = $obs_unit->{observationunit_uniquename};
591 my $row_number = $obs_unit->{obsunit_row_number} || '';
592 my $col_number = $obs_unit->{obsunit_col_number} || '';
593 $seen_plot_names{$obsunit_stock_uniquename}++;
594 $unique_accessions{$germplasm_name}++;
595 $stock_info{"S".$germplasm_stock_id} = {
596 uniquename => $germplasm_name
598 $stock_name_row_col{$obsunit_stock_uniquename} = {
599 row_number => $row_number,
600 col_number => $col_number,
601 obsunit_stock_id => $obsunit_stock_id,
602 obsunit_name => $obsunit_stock_uniquename,
603 rep => $replicate_number,
604 block => $block_number,
605 germplasm_stock_id => $germplasm_stock_id,
606 germplasm_name => $germplasm_name
609 if ($row_number < $min_row) {
610 $min_row = $row_number;
612 elsif ($row_number >= $max_row) {
613 $max_row = $row_number;
615 if ($col_number < $min_col) {
616 $min_col = $col_number;
618 elsif ($col_number >= $max_col) {
619 $max_col = $col_number;
622 my $observations = $obs_unit->{observations};
623 foreach (@$observations){
624 if ($_->{associated_image_project_time_json}) {
625 my $related_time_terms_json = decode_json $_->{associated_image_project_time_json};
627 my $time_value;
628 my $time_term_string;
629 if ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups') {
630 my $time_days_cvterm = $related_time_terms_json->{day};
631 $time_term_string = $time_days_cvterm;
632 my $time_days = (split '\|', $time_days_cvterm)[0];
633 $time_value = (split ' ', $time_days)[1];
635 $seen_days_after_plantings{$time_value}++;
637 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups') {
638 $time_value = $related_time_terms_json->{gdd_average_temp} + 0;
640 my $gdd_term_string = "GDD $time_value";
641 $h_time->execute($gdd_term_string, 'cxgn_time_ontology');
642 my ($gdd_cvterm_id) = $h_time->fetchrow_array();
644 if (!$gdd_cvterm_id) {
645 my $new_gdd_term = $schema->resultset("Cv::Cvterm")->create_with({
646 name => $gdd_term_string,
647 cv => 'cxgn_time_ontology'
649 $gdd_cvterm_id = $new_gdd_term->cvterm_id();
651 $time_term_string = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $gdd_cvterm_id, 'extended');
653 my $trait_name = $_->{trait_name};
654 $phenotype_data{$obsunit_stock_uniquename}->{$time_value} = $_->{value};
655 $seen_times{$time_value} = $trait_name;
656 $seen_trait_names{$trait_name} = $time_term_string;
657 $trait_to_time_map{$trait_name} = $time_value;
661 if (scalar(keys %seen_times) == 0) {
662 $c->stash->{rest} = { error => "There are no phenotypes with associated days after planting time associated to the traits you have selected!"};
663 return;
666 @unique_accession_names = sort keys %unique_accessions;
667 @sorted_trait_names = sort {$a <=> $b} keys %seen_times;
668 @unique_plot_names = sort keys %seen_plot_names;
669 @sorted_trait_names_original = sort {$a <=> $b} keys %seen_times;
671 my $trait_name_encoded = 1;
672 foreach my $trait_name (@sorted_trait_names) {
673 if (!exists($trait_name_encoder{$trait_name})) {
674 my $trait_name_e = 't'.$trait_name_encoded;
675 $trait_name_encoder{$trait_name} = $trait_name_e;
676 $trait_name_encoder_rev{$trait_name_e} = $trait_name;
677 $trait_name_encoded++;
681 while ( my ($trait_name, $time_term) = each %seen_trait_names) {
682 push @{$trait_composing_info{$trait_name}}, $time_term;
685 foreach (@$data) {
686 my $germplasm_name = $_->{germplasm_uniquename};
687 my $germplasm_stock_id = $_->{germplasm_stock_id};
688 my $obsunit_stock_id = $_->{observationunit_stock_id};
689 my $obsunit_stock_uniquename = $_->{observationunit_uniquename};
690 my $row_number = $_->{obsunit_row_number};
691 my $col_number = $_->{obsunit_col_number};
692 my @row = ($_->{obsunit_rep}, $_->{obsunit_block}, "S".$germplasm_stock_id, "P".$obsunit_stock_id, $row_number, $col_number, $row_number, $col_number);
693 $obsunit_row_col{$row_number}->{$col_number} = {
694 stock_id => $obsunit_stock_id,
695 stock_uniquename => $obsunit_stock_uniquename
697 $plot_id_map{"P".$obsunit_stock_id} = $obsunit_stock_uniquename;
698 $seen_plot_names{$obsunit_stock_uniquename}++;
699 my $current_trait_index = 0;
700 foreach my $t (@sorted_trait_names) {
701 if (defined($phenotype_data{$obsunit_stock_uniquename}->{$t})) {
702 if ($use_area_under_curve) {
703 my $val = 0;
704 foreach my $counter (0..$current_trait_index) {
705 if ($counter == 0) {
706 $val = $val + $phenotype_data{$obsunit_stock_uniquename}->{$sorted_trait_names[$counter]} + 0;
708 else {
709 my $t1 = $sorted_trait_names[$counter-1];
710 my $t2 = $sorted_trait_names[$counter];
711 my $p1 = $phenotype_data{$obsunit_stock_uniquename}->{$t1} + 0;
712 my $p2 = $phenotype_data{$obsunit_stock_uniquename}->{$t2} + 0;
713 my $neg = 1;
714 my $min_val = $p1;
715 if ($p2 < $p1) {
716 $neg = -1;
717 $min_val = $p2;
719 my $area = (($neg*($p2-$p1)*($t2-$t1))/2)+($t2-$t1)*$min_val;
720 $val = $val + $area;
723 push @row, $val;
725 else {
726 push @row, $phenotype_data{$obsunit_stock_uniquename}->{$t} + 0;
728 } else {
729 print STDERR $obsunit_stock_uniquename." : $t : $germplasm_name : NA \n";
730 push @row, 'NA';
732 $current_trait_index++;
734 push @data_matrix, \@row;
737 my @phenotype_header = ("replicate", "block", "id", "plot_id", "rowNumber", "colNumber", "rowNumberFactor", "colNumberFactor");
738 my $num_col_before_traits = scalar(@phenotype_header);
739 push @phenotype_header, @sorted_trait_names;
740 my $header_string = join ',', @phenotype_header;
742 open(my $F, ">", $stats_tempfile) || die "Can't open file ".$stats_tempfile;
743 print $F $header_string."\n";
744 foreach (@data_matrix) {
745 my $line = join ',', @$_;
746 print $F "$line\n";
748 close($F);
750 elsif ($statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups') {
752 $analysis_model_language = "F90";
754 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
755 'MaterializedViewTable',
757 bcs_schema=>$schema,
758 data_level=>'plot',
759 trait_list=>$trait_id_list,
760 trial_list=>$field_trial_id_list,
761 include_timestamp=>0,
762 exclude_phenotype_outlier=>0
765 my ($data, $unique_traits) = $phenotypes_search->search();
766 @sorted_trait_names = sort keys %$unique_traits;
768 if (scalar(@$trait_id_list) < 2) {
769 $c->stash->{rest} = { error => "Select more than 2 time points!"};
770 return;
773 if (scalar(@$data) == 0) {
774 $c->stash->{rest} = { error => "There are no phenotypes for the trials and traits you have selected!"};
775 return;
778 my $q_time = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
779 my $h_time = $schema->storage->dbh()->prepare($q_time);
781 my %seen_plots;
782 my %seen_plot_names;
783 foreach my $obs_unit (@$data){
784 my $germplasm_name = $obs_unit->{germplasm_uniquename};
785 my $germplasm_stock_id = $obs_unit->{germplasm_stock_id};
786 my $replicate_number = $obs_unit->{obsunit_rep} || '';
787 my $block_number = $obs_unit->{obsunit_block} || '';
788 my $obsunit_stock_id = $obs_unit->{observationunit_stock_id};
789 my $obsunit_stock_uniquename = $obs_unit->{observationunit_uniquename};
790 my $row_number = $obs_unit->{obsunit_row_number} || '';
791 my $col_number = $obs_unit->{obsunit_col_number} || '';
792 $unique_accessions{$germplasm_name}++;
793 $stock_info{$germplasm_stock_id} = {
794 uniquename => $germplasm_name
796 $stock_name_row_col{$obsunit_stock_uniquename} = {
797 row_number => $row_number,
798 col_number => $col_number,
799 obsunit_stock_id => $obsunit_stock_id,
800 obsunit_name => $obsunit_stock_uniquename,
801 rep => $replicate_number,
802 block => $block_number,
803 germplasm_stock_id => $germplasm_stock_id,
804 germplasm_name => $germplasm_name
807 if ($row_number < $min_row) {
808 $min_row = $row_number;
810 elsif ($row_number >= $max_row) {
811 $max_row = $row_number;
813 if ($col_number < $min_col) {
814 $min_col = $col_number;
816 elsif ($col_number >= $max_col) {
817 $max_col = $col_number;
820 $seen_plots{$obsunit_stock_id} = $obsunit_stock_uniquename;
821 $seen_plot_names{$obsunit_stock_uniquename}++;
822 my $observations = $obs_unit->{observations};
823 foreach (@$observations){
824 if ($_->{associated_image_project_time_json}) {
825 my $related_time_terms_json = decode_json $_->{associated_image_project_time_json};
826 my $time;
827 my $time_term_string = '';
828 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups') {
829 $time = $related_time_terms_json->{gdd_average_temp} + 0;
831 my $gdd_term_string = "GDD $time";
832 $h_time->execute($gdd_term_string, 'cxgn_time_ontology');
833 my ($gdd_cvterm_id) = $h_time->fetchrow_array();
835 if (!$gdd_cvterm_id) {
836 my $new_gdd_term = $schema->resultset("Cv::Cvterm")->create_with({
837 name => $gdd_term_string,
838 cv => 'cxgn_time_ontology'
840 $gdd_cvterm_id = $new_gdd_term->cvterm_id();
842 $time_term_string = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $gdd_cvterm_id, 'extended');
844 elsif ($statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
845 my $time_days_cvterm = $related_time_terms_json->{day};
846 $time_term_string = $time_days_cvterm;
847 my $time_days = (split '\|', $time_days_cvterm)[0];
848 $time = (split ' ', $time_days)[1] + 0;
850 $seen_days_after_plantings{$time}++;
852 my $trait_name = $_->{trait_name};
853 $phenotype_data{$obsunit_stock_uniquename}->{$time} = $_->{value};
854 $seen_times{$time} = $trait_name;
855 $seen_trait_names{$trait_name} = $time_term_string;
856 $trait_to_time_map{$trait_name} = $time;
860 if (scalar(keys %seen_times) == 0) {
861 $c->stash->{rest} = { error => "There are no phenotypes with associated days after planting time associated to the traits you have selected!"};
862 return;
865 @unique_accession_names = sort keys %unique_accessions;
866 @sorted_trait_names = sort {$a <=> $b} keys %seen_times;
867 @unique_plot_names = sort keys %seen_plot_names;
868 @sorted_trait_names_original = sort {$a <=> $b} keys %seen_times;
869 # print STDERR Dumper \@sorted_trait_names;
871 my $trait_name_encoded = 1;
872 foreach my $trait_name (@sorted_trait_names) {
873 if (!exists($trait_name_encoder{$trait_name})) {
874 my $trait_name_e = 't'.$trait_name_encoded;
875 $trait_name_encoder{$trait_name} = $trait_name_e;
876 $trait_name_encoder_rev{$trait_name_e} = $trait_name;
877 $trait_name_encoded++;
881 while ( my ($trait_name, $time_term) = each %seen_trait_names) {
882 push @{$trait_composing_info{$trait_name}}, $time_term;
885 $time_min = 100000000;
886 $time_max = 0;
887 foreach (@sorted_trait_names) {
888 if ($_ < $time_min) {
889 $time_min = $_;
891 if ($_ > $time_max) {
892 $time_max = $_;
895 print STDERR Dumper [$time_min, $time_max];
897 if ($legendre_order_number >= scalar(@sorted_trait_names)) {
898 $legendre_order_number = scalar(@sorted_trait_names) - 1;
901 my @sorted_trait_names_scaled;
902 my $leg_pos_counter = 0;
903 foreach (@sorted_trait_names) {
904 # my $scaled_time = 2*(($_ - $time_min)/($time_max - $time_min)) - 1;
905 my $scaled_time = ($_ - $time_min)/($time_max - $time_min);
906 print STDERR Dumper $scaled_time;
907 push @sorted_trait_names_scaled, $scaled_time;
908 if ($leg_pos_counter < $legendre_order_number+1) {
909 push @sorted_scaled_ln_times, log($scaled_time+0.0001);
911 $leg_pos_counter++;
913 my $sorted_trait_names_scaled_string = join ',', @sorted_trait_names_scaled;
915 my $cmd = 'R -e "library(sommer); library(orthopolynom);
916 polynomials <- leg(c('.$sorted_trait_names_scaled_string.'), n='.$legendre_order_number.', intercept=TRUE);
917 write.table(polynomials, file=\''.$stats_out_tempfile.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');"';
918 my $status = system("$cmd > /tmp/Rout");
920 my %polynomial_map;
921 my $csv = Text::CSV->new({ sep_char => "\t" });
922 open(my $fh, '<', $stats_out_tempfile)
923 or die "Could not open file '$stats_out_tempfile' $!";
925 print STDERR "Opened $stats_out_tempfile\n";
926 my $header = <$fh>;
927 my @header_cols;
928 if ($csv->parse($header)) {
929 @header_cols = $csv->fields();
932 my $p_counter = 0;
933 while (my $row = <$fh>) {
934 my @columns;
935 if ($csv->parse($row)) {
936 @columns = $csv->fields();
938 my $time = $sorted_trait_names[$p_counter];
939 $polynomial_map{$time} = \@columns;
940 $p_counter++;
942 close($fh);
944 open(my $F_prep, ">", $stats_prep_tempfile) || die "Can't open file ".$stats_prep_tempfile;
945 print $F_prep "accession_id,accession_id_factor,plot_id,plot_id_factor,replicate,time,replicate_time,ind_replicate\n";
946 foreach (@$data) {
947 my $obsunit_stock_id = $_->{observationunit_stock_id};
948 my $replicate = $_->{obsunit_rep};
949 my $germplasm_stock_id = $_->{germplasm_stock_id};
950 foreach my $t (@sorted_trait_names) {
951 print $F_prep "$germplasm_stock_id,,$obsunit_stock_id,,$replicate,$t,$replicate"."_"."$t,$germplasm_stock_id"."_"."$replicate\n";
954 close($F_prep);
956 my $cmd_factor = 'R -e "library(data.table);
957 mat <- fread(\''.$stats_prep_tempfile.'\', header=TRUE, sep=\',\');
958 mat\$replicate_time <- as.numeric(as.factor(mat\$replicate_time));
959 mat\$ind_replicate <- as.numeric(as.factor(mat\$ind_replicate));
960 mat\$accession_id_factor <- as.numeric(as.factor(mat\$accession_id));
961 mat\$plot_id_factor <- as.numeric(as.factor(mat\$plot_id));
962 write.table(mat, file=\''.$stats_prep_factor_tempfile.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');"';
963 print STDERR Dumper $cmd_factor;
964 my $status_factor = system("$cmd_factor > /dev/null");
966 my %plot_factor_map;
967 my %plot_rep_time_factor_map;
968 my %plot_ind_rep_factor_map;
969 my %seen_rep_times;
970 my %seen_ind_reps;
971 $csv = Text::CSV->new({ sep_char => "\t" });
972 open(my $fh_factor, '<', $stats_prep_factor_tempfile)
973 or die "Could not open file '$stats_prep_factor_tempfile' $!";
975 print STDERR "Opened $stats_prep_factor_tempfile\n";
976 $header = <$fh_factor>;
977 if ($csv->parse($header)) {
978 @header_cols = $csv->fields();
981 my $line_factor_count = 0;
982 while (my $row = <$fh_factor>) {
983 my @columns;
984 if ($csv->parse($row)) {
985 @columns = $csv->fields();
987 my $accession_id = $columns[0];
988 my $accession_id_factor = $columns[1];
989 my $plot_id = $columns[2];
990 my $plot_id_factor = $columns[3];
991 my $rep = $columns[4];
992 my $time = $columns[5];
993 my $rep_time = $columns[6];
994 my $ind_rep = $columns[7];
995 $plot_factor_map{$plot_id} = {
996 plot_id => $plot_id,
997 plot_id_factor => $plot_id_factor,
998 accession_id => $accession_id,
999 accession_id_factor => $accession_id_factor,
1000 replicate => $rep,
1001 time => $time,
1002 replicate_time => $rep_time,
1003 ind_replicate => $ind_rep
1005 $plot_rep_time_factor_map{$plot_id}->{$rep}->{$time} = $rep_time;
1006 $plot_ind_rep_factor_map{$plot_id}->{$accession_id}->{$rep} = $ind_rep;
1007 $seen_rep_times{$rep_time}++;
1008 # $seen_ind_reps{$ind_rep}++;
1009 $seen_ind_reps{$plot_id_factor}++;
1010 $accession_id_factor_map{$accession_id} = $accession_id_factor;
1011 $accession_id_factor_map_reverse{$accession_id_factor} = $stock_info{$accession_id}->{uniquename};
1012 # $plot_id_factor_map_reverse{$ind_rep} = $seen_plots{$plot_id};
1013 $plot_id_factor_map_reverse{$plot_id_factor} = $seen_plots{$plot_id};
1014 $plot_id_count_map_reverse{$line_factor_count} = $seen_plots{$plot_id};
1015 $time_count_map_reverse{$line_factor_count} = $time;
1016 $line_factor_count++;
1018 close($fh_factor);
1019 # print STDERR Dumper \%plot_factor_map;
1020 @rep_time_factors = sort keys %seen_rep_times;
1021 @ind_rep_factors = sort keys %seen_ind_reps;
1023 my @data_matrix_phenotypes;
1024 my %stock_row_col;
1025 my @stocks_ordered;
1026 foreach (@$data) {
1027 my $germplasm_name = $_->{germplasm_uniquename};
1028 my $germplasm_stock_id = $_->{germplasm_stock_id};
1029 my $obsunit_stock_id = $_->{observationunit_stock_id};
1030 my $obsunit_stock_uniquename = $_->{observationunit_uniquename};
1031 my $row_number = $_->{obsunit_row_number};
1032 my $replicate_number = $_->{obsunit_rep};
1033 my $col_number = $_->{obsunit_col_number};
1034 $obsunit_row_col{$row_number}->{$col_number} = {
1035 stock_id => $obsunit_stock_id,
1036 stock_uniquename => $obsunit_stock_uniquename
1038 $plot_id_map{$obsunit_stock_id} = $obsunit_stock_uniquename;
1039 $seen_plot_names{$obsunit_stock_uniquename}++;
1040 $stock_row_col{$obsunit_stock_id} = {
1041 row_number => $row_number,
1042 col_number => $col_number
1044 my @data_matrix_phenotypes_row;
1045 my $current_trait_index = 0;
1046 push @stocks_ordered, $obsunit_stock_id;
1047 foreach my $t (@sorted_trait_names) {
1048 my @row = (
1049 $accession_id_factor_map{$germplasm_stock_id},
1050 $obsunit_stock_id,
1051 $replicate_number,
1053 $plot_rep_time_factor_map{$obsunit_stock_id}->{$replicate_number}->{$t},
1054 #$plot_ind_rep_factor_map{$obsunit_stock_id}->{$germplasm_stock_id}->{$replicate_number},
1055 $plot_factor_map{$obsunit_stock_id}->{plot_id_factor}
1058 my $polys = $polynomial_map{$t};
1059 push @row, @$polys;
1061 if (defined($phenotype_data{$obsunit_stock_uniquename}->{$t})) {
1062 if ($use_area_under_curve) {
1063 my $val = 0;
1064 foreach my $counter (0..$current_trait_index) {
1065 if ($counter == 0) {
1066 $val = $val + $phenotype_data{$obsunit_stock_uniquename}->{$sorted_trait_names[$counter]} + 0;
1068 else {
1069 my $t1 = $sorted_trait_names[$counter-1];
1070 my $t2 = $sorted_trait_names[$counter];
1071 my $p1 = $phenotype_data{$obsunit_stock_uniquename}->{$t1} + 0;
1072 my $p2 = $phenotype_data{$obsunit_stock_uniquename}->{$t2} + 0;
1073 my $neg = 1;
1074 my $min_val = $p1;
1075 if ($p2 < $p1) {
1076 $neg = -1;
1077 $min_val = $p2;
1079 $val = $val + (($neg*($p2-$p1)*($t2-$t1))/2)+($t2-$t1)*$min_val;
1082 push @row, $val;
1083 push @data_matrix_phenotypes_row, $val;
1085 else {
1086 push @row, $phenotype_data{$obsunit_stock_uniquename}->{$t} + 0;
1087 push @data_matrix_phenotypes_row, $phenotype_data{$obsunit_stock_uniquename}->{$t} + 0;
1089 } else {
1090 print STDERR $obsunit_stock_uniquename." : $t : $germplasm_name : NA \n";
1091 push @row, '';
1092 push @data_matrix_phenotypes_row, 'NA';
1095 push @data_matrix, \@row;
1096 push @data_matrix_phenotypes, \@data_matrix_phenotypes_row;
1098 $current_trait_index++;
1101 # print STDERR Dumper \@data_matrix;
1102 my @legs_header;
1103 for (0..$legendre_order_number) {
1104 push @legs_header, "legendre$_";
1106 my @phenotype_header = ("id", "plot_id", "replicate", "time", "replicate_time", "ind_replicate", @legs_header, "phenotype");
1107 open(my $F, ">", $stats_tempfile_2) || die "Can't open file ".$stats_tempfile_2;
1108 # print $F $header_string."\n";
1109 foreach (@data_matrix) {
1110 my $line = join ' ', @$_;
1111 print $F "$line\n";
1113 close($F);
1115 open(my $F2, ">", $stats_prep2_tempfile) || die "Can't open file ".$stats_prep2_tempfile;
1116 # print $F $header_string."\n";
1117 foreach (@data_matrix_phenotypes) {
1118 my $line = join ',', @$_;
1119 print $F2 "$line\n";
1121 close($F2);
1123 if ($permanent_environment_structure eq 'euclidean_rows_and_columns') {
1124 my $data = '';
1125 my %euclidean_distance_hash;
1126 my $min_euc_dist = 10000000000000000000;
1127 my $max_euc_dist = 0;
1128 foreach my $s (sort { $a <=> $b } @stocks_ordered) {
1129 foreach my $r (sort { $a <=> $b } @stocks_ordered) {
1130 my $s_factor = $plot_factor_map{$s}->{plot_id_factor};
1131 my $r_factor = $plot_factor_map{$r}->{plot_id_factor};
1132 if (!exists($euclidean_distance_hash{$s_factor}->{$r_factor}) && !exists($euclidean_distance_hash{$r_factor}->{$s_factor})) {
1133 my $row_1 = $stock_row_col{$s}->{row_number};
1134 my $col_1 = $stock_row_col{$s}->{col_number};
1135 my $row_2 = $stock_row_col{$r}->{row_number};
1136 my $col_2 = $stock_row_col{$r}->{col_number};
1137 my $dist = sqrt( ($row_2 - $row_1)**2 + ($col_2 - $col_1)**2 );
1138 if ($dist != 0) {
1139 $dist = 1/$dist;
1141 if (defined $dist and length $dist) {
1142 $euclidean_distance_hash{$s_factor}->{$r_factor} = $dist;
1144 if ($dist < $min_euc_dist) {
1145 $min_euc_dist = $dist;
1147 elsif ($dist > $max_euc_dist) {
1148 $max_euc_dist = $dist;
1151 else {
1152 $c->stash->{rest} = { error => "There are not rows and columns for all of the plots! Do not try to use a Euclidean distance between plots for the permanent environment structure"};
1153 return;
1159 foreach my $r (sort { $a <=> $b } keys %euclidean_distance_hash) {
1160 foreach my $s (sort { $a <=> $b } keys %{$euclidean_distance_hash{$r}}) {
1161 my $val = $euclidean_distance_hash{$r}->{$s};
1162 if (defined $val and length $val) {
1163 my $val_scaled = ($val-$min_euc_dist)/($max_euc_dist-$min_euc_dist);
1164 $data .= "$r\t$s\t$val_scaled\n";
1169 open(my $F3, ">", $permanent_environment_structure_tempfile) || die "Can't open file ".$permanent_environment_structure_tempfile;
1170 print $F3 $data;
1171 close($F3);
1173 elsif ($permanent_environment_structure eq 'phenotype_correlation') {
1174 my $phenotypes_search_permanent_environment_structure = CXGN::Phenotypes::SearchFactory->instantiate(
1175 'MaterializedViewTable',
1177 bcs_schema=>$schema,
1178 data_level=>'plot',
1179 trial_list=>$field_trial_id_list,
1180 trait_list=>$permanent_environment_structure_phenotype_correlation_traits,
1181 include_timestamp=>0,
1182 exclude_phenotype_outlier=>0
1185 my ($data_permanent_environment_structure, $unique_traits_permanent_environment_structure) = $phenotypes_search_permanent_environment_structure->search();
1187 if (scalar(@$data_permanent_environment_structure) == 0) {
1188 $c->stash->{rest} = { error => "There are no phenotypes for the permanent environment structure traits you have selected!"};
1189 return;
1192 my %seen_plot_names_pe_rel;
1193 my %phenotype_data_pe_rel;
1194 my %seen_traits_pe_rel;
1195 foreach my $obs_unit (@$data_permanent_environment_structure){
1196 my $obsunit_stock_uniquename = $obs_unit->{observationunit_uniquename};
1197 my $germplasm_name = $obs_unit->{germplasm_uniquename};
1198 my $germplasm_stock_id = $obs_unit->{germplasm_stock_id};
1199 my $row_number = $obs_unit->{obsunit_row_number} || '';
1200 my $col_number = $obs_unit->{obsunit_col_number} || '';
1201 my $rep = $obs_unit->{obsunit_rep};
1202 my $block = $obs_unit->{obsunit_block};
1203 $seen_plot_names_pe_rel{$obsunit_stock_uniquename} = $obs_unit;
1204 my $observations = $obs_unit->{observations};
1205 foreach (@$observations){
1206 $phenotype_data_pe_rel{$obsunit_stock_uniquename}->{$_->{trait_name}} = $_->{value};
1207 $seen_traits_pe_rel{$_->{trait_name}}++;
1211 my @seen_plot_names_pe_rel_sorted = sort keys %seen_plot_names_pe_rel;
1212 my @seen_traits_pe_rel_sorted = sort keys %seen_traits_pe_rel;
1214 my @header_pe = ('plot_id');
1216 my %trait_name_encoder_pe;
1217 my %trait_name_encoder_rev_pe;
1218 my $trait_name_encoded_pe = 1;
1219 my @header_traits_pe;
1220 foreach my $trait_name (@seen_traits_pe_rel_sorted) {
1221 if (!exists($trait_name_encoder_pe{$trait_name})) {
1222 my $trait_name_e = 't'.$trait_name_encoded_pe;
1223 $trait_name_encoder_pe{$trait_name} = $trait_name_e;
1224 $trait_name_encoder_rev_pe{$trait_name_e} = $trait_name;
1225 push @header_traits_pe, $trait_name_e;
1226 $trait_name_encoded_pe++;
1230 my @pe_pheno_matrix;
1231 push @header_pe, @header_traits_pe;
1232 push @pe_pheno_matrix, \@header_pe;
1234 foreach my $p (@seen_plot_names_pe_rel_sorted) {
1235 my $obj = $seen_plot_names_pe_rel{$p};
1236 my @row = ($plot_factor_map{$obj->{observationunit_stock_id}}->{plot_id_factor});
1237 foreach my $t (@seen_traits_pe_rel_sorted) {
1238 my $val = $phenotype_data_pe_rel{$p}->{$t} + 0;
1239 push @row, $val;
1241 push @pe_pheno_matrix, \@row;
1244 open(my $pe_pheno_f, ">", $stats_out_pe_pheno_rel_tempfile) || die "Can't open file ".$stats_out_pe_pheno_rel_tempfile;
1245 foreach (@pe_pheno_matrix) {
1246 my $line = join "\t", @$_;
1247 print $pe_pheno_f $line."\n";
1249 close($pe_pheno_f);
1251 my %rel_pe_result_hash;
1252 my $pe_rel_cmd = 'R -e "library(lme4); library(data.table);
1253 mat_agg <- fread(\''.$stats_out_pe_pheno_rel_tempfile.'\', header=TRUE, sep=\'\t\');
1254 mat_pheno <- mat_agg[,2:ncol(mat_agg)];
1255 cor_mat <- cor(t(mat_pheno));
1256 rownames(cor_mat) <- mat_agg\$plot_id;
1257 colnames(cor_mat) <- mat_agg\$plot_id;
1258 range01 <- function(x){(x-min(x))/(max(x)-min(x))};
1259 cor_mat <- range01(cor_mat);
1260 write.table(cor_mat, file=\''.$stats_out_pe_pheno_rel_tempfile2.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');"';
1261 # print STDERR Dumper $pe_rel_cmd;
1262 my $status_pe_rel = system("$pe_rel_cmd > /dev/null");
1264 my $csv = Text::CSV->new({ sep_char => "\t" });
1266 open(my $pe_rel_res, '<', $stats_out_pe_pheno_rel_tempfile2)
1267 or die "Could not open file '$stats_out_pe_pheno_rel_tempfile2' $!";
1269 print STDERR "Opened $stats_out_pe_pheno_rel_tempfile2\n";
1270 my $header_row = <$pe_rel_res>;
1271 my @header;
1272 if ($csv->parse($header_row)) {
1273 @header = $csv->fields();
1276 while (my $row = <$pe_rel_res>) {
1277 my @columns;
1278 if ($csv->parse($row)) {
1279 @columns = $csv->fields();
1281 my $stock_id1 = $columns[0];
1282 my $counter = 1;
1283 foreach my $stock_id2 (@header) {
1284 my $val = $columns[$counter];
1285 $rel_pe_result_hash{$stock_id1}->{$stock_id2} = $val;
1286 $counter++;
1289 close($pe_rel_res);
1291 my $data_rel_pe = '';
1292 my %result_hash_pe;
1293 foreach my $s (sort { $a <=> $b } @stocks_ordered) {
1294 foreach my $r (sort { $a <=> $b } @stocks_ordered) {
1295 my $s_factor = $plot_factor_map{$s}->{plot_id_factor};
1296 my $r_factor = $plot_factor_map{$r}->{plot_id_factor};
1297 if (!exists($result_hash_pe{$s_factor}->{$r_factor}) && !exists($result_hash_pe{$r_factor}->{$s_factor})) {
1298 $result_hash_pe{$s_factor}->{$r_factor} = $rel_pe_result_hash{$s_factor}->{$r_factor};
1302 foreach my $r (sort { $a <=> $b } keys %result_hash_pe) {
1303 foreach my $s (sort { $a <=> $b } keys %{$result_hash_pe{$r}}) {
1304 my $val = $result_hash_pe{$r}->{$s};
1305 if (defined $val and length $val) {
1306 $data_rel_pe .= "$r\t$s\t$val\n";
1311 open(my $pe_rel_out, ">", $permanent_environment_structure_tempfile) || die "Can't open file ".$permanent_environment_structure_tempfile;
1312 print $pe_rel_out $data_rel_pe;
1313 close($pe_rel_out);
1317 if ($statistics_select eq 'sommer_grm_spatial_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups'
1318 || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups'
1319 || $statistics_select eq 'sommer_grm_genetic_blups') {
1321 my %seen_accession_stock_ids;
1322 foreach my $trial_id (@$field_trial_id_list) {
1323 my $trial = CXGN::Trial->new({ bcs_schema => $schema, trial_id => $trial_id });
1324 my $accessions = $trial->get_accessions();
1325 foreach (@$accessions) {
1326 $seen_accession_stock_ids{$_->{stock_id}}++;
1329 my @accession_ids = keys %seen_accession_stock_ids;
1331 if ($compute_relationship_matrix_from_htp_phenotypes eq 'genotypes') {
1333 if ($include_pedgiree_info_if_compute_from_parents) {
1334 my $shared_cluster_dir_config = $c->config->{cluster_shared_tempdir};
1335 my $tmp_arm_dir = $shared_cluster_dir_config."/tmp_download_arm";
1336 mkdir $tmp_arm_dir if ! -d $tmp_arm_dir;
1337 my ($arm_tempfile_fh, $arm_tempfile) = tempfile("drone_stats_download_arm_XXXXX", DIR=> $tmp_arm_dir);
1338 my ($grm1_tempfile_fh, $grm1_tempfile) = tempfile("drone_stats_download_grm1_XXXXX", DIR=> $tmp_arm_dir);
1339 my ($grm_out_temp_tempfile_fh, $grm_out_temp_tempfile) = tempfile("drone_stats_download_grm_temp_out_XXXXX", DIR=> $tmp_arm_dir);
1340 my ($grm_out_tempfile_fh, $grm_out_tempfile) = tempfile("drone_stats_download_grm_out_XXXXX", DIR=> $tmp_arm_dir);
1341 my ($grm_out_posdef_tempfile_fh, $grm_out_posdef_tempfile) = tempfile("drone_stats_download_grm_out_XXXXX", DIR=> $tmp_arm_dir);
1343 if (!$protocol_id) {
1344 $protocol_id = undef;
1347 my $pedigree_arm = CXGN::Pedigree::ARM->new({
1348 bcs_schema=>$schema,
1349 arm_temp_file=>$arm_tempfile,
1350 people_schema=>$people_schema,
1351 accession_id_list=>\@accession_ids,
1352 # plot_id_list=>\@plot_id_list,
1353 cache_root=>$c->config->{cache_file_path},
1354 download_format=>'matrix', #either 'matrix', 'three_column', or 'heatmap'
1356 my ($parent_hash, $stock_ids, $all_accession_stock_ids, $female_stock_ids, $male_stock_ids) = $pedigree_arm->get_arm(
1357 $shared_cluster_dir_config,
1358 $c->config->{backend},
1359 $c->config->{cluster_host},
1360 $c->config->{'web_cluster_queue'},
1361 $c->config->{basepath}
1363 # print STDERR Dumper $parent_hash;
1365 my $female_geno = CXGN::Genotype::GRM->new({
1366 bcs_schema=>$schema,
1367 grm_temp_file=>$grm1_tempfile,
1368 people_schema=>$people_schema,
1369 cache_root=>$c->config->{cache_file_path},
1370 accession_id_list=>$female_stock_ids,
1371 protocol_id=>$protocol_id,
1372 get_grm_for_parental_accessions=>0,
1373 download_format=>'three_column_reciprocal'
1374 # minor_allele_frequency=>$minor_allele_frequency,
1375 # marker_filter=>$marker_filter,
1376 # individuals_filter=>$individuals_filter
1378 my $female_grm_data = $female_geno->download_grm(
1379 'data',
1380 $shared_cluster_dir_config,
1381 $c->config->{backend},
1382 $c->config->{cluster_host},
1383 $c->config->{'web_cluster_queue'},
1384 $c->config->{basepath}
1386 my @fl = split '\n', $female_grm_data;
1387 my %female_parent_grm;
1388 foreach (@fl) {
1389 my @l = split '\t', $_;
1390 $female_parent_grm{$l[0]}->{$l[1]} = $l[2];
1392 # print STDERR Dumper \%female_parent_grm;
1394 my $male_geno = CXGN::Genotype::GRM->new({
1395 bcs_schema=>$schema,
1396 grm_temp_file=>$grm1_tempfile,
1397 people_schema=>$people_schema,
1398 cache_root=>$c->config->{cache_file_path},
1399 accession_id_list=>$male_stock_ids,
1400 protocol_id=>$protocol_id,
1401 get_grm_for_parental_accessions=>0,
1402 download_format=>'three_column_reciprocal'
1403 # minor_allele_frequency=>$minor_allele_frequency,
1404 # marker_filter=>$marker_filter,
1405 # individuals_filter=>$individuals_filter
1407 my $male_grm_data = $male_geno->download_grm(
1408 'data',
1409 $shared_cluster_dir_config,
1410 $c->config->{backend},
1411 $c->config->{cluster_host},
1412 $c->config->{'web_cluster_queue'},
1413 $c->config->{basepath}
1415 my @ml = split '\n', $male_grm_data;
1416 my %male_parent_grm;
1417 foreach (@ml) {
1418 my @l = split '\t', $_;
1419 $male_parent_grm{$l[0]}->{$l[1]} = $l[2];
1421 # print STDERR Dumper \%male_parent_grm;
1423 my %rel_result_hash;
1424 foreach my $a1 (@accession_ids) {
1425 foreach my $a2 (@accession_ids) {
1426 my $female_parent1 = $parent_hash->{$a1}->{female_stock_id};
1427 my $male_parent1 = $parent_hash->{$a1}->{male_stock_id};
1428 my $female_parent2 = $parent_hash->{$a2}->{female_stock_id};
1429 my $male_parent2 = $parent_hash->{$a2}->{male_stock_id};
1431 my $female_rel = 0;
1432 if ($female_parent1 && $female_parent2 && $female_parent_grm{'S'.$female_parent1}->{'S'.$female_parent2}) {
1433 $female_rel = $female_parent_grm{'S'.$female_parent1}->{'S'.$female_parent2};
1435 elsif ($female_parent1 && $female_parent2 && $female_parent1 == $female_parent2) {
1436 $female_rel = 1;
1438 elsif ($a1 == $a2) {
1439 $female_rel = 1;
1442 my $male_rel = 0;
1443 if ($male_parent1 && $male_parent2 && $male_parent_grm{'S'.$male_parent1}->{'S'.$male_parent2}) {
1444 $male_rel = $male_parent_grm{'S'.$male_parent1}->{'S'.$male_parent2};
1446 elsif ($male_parent1 && $male_parent2 && $male_parent1 == $male_parent2) {
1447 $male_rel = 1;
1449 elsif ($a1 == $a2) {
1450 $male_rel = 1;
1452 # print STDERR "$a1 $a2 $female_rel $male_rel\n";
1454 my $rel = 0.5*($female_rel + $male_rel);
1455 $rel_result_hash{$a1}->{$a2} = $rel;
1458 # print STDERR Dumper \%rel_result_hash;
1460 my $data = '';
1461 my %result_hash;
1462 foreach my $s (sort @accession_ids) {
1463 foreach my $c (sort @accession_ids) {
1464 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
1465 my $val = $rel_result_hash{$s}->{$c};
1466 if (defined $val and length $val) {
1467 $result_hash{$s}->{$c} = $val;
1468 $data .= "S$s\tS$c\t$val\n";
1474 # print STDERR Dumper $data;
1475 open(my $F2, ">", $grm_out_temp_tempfile) || die "Can't open file ".$grm_out_temp_tempfile;
1476 print $F2 $data;
1477 close($F2);
1479 my $cmd = 'R -e "library(data.table); library(scales); library(tidyr); library(reshape2);
1480 three_col <- fread(\''.$grm_out_temp_tempfile.'\', header=FALSE, sep=\'\t\');
1481 A_wide <- dcast(three_col, V1~V2, value.var=\'V3\');
1482 A_1 <- A_wide[,-1];
1483 A_1[is.na(A_1)] <- 0;
1484 A <- A_1 + t(A_1);
1485 diag(A) <- diag(as.matrix(A_1));
1486 E = eigen(A);
1487 ev = E\$values;
1488 U = E\$vectors;
1489 no = dim(A)[1];
1490 nev = which(ev < 0);
1491 wr = 0;
1492 k=length(nev);
1493 if(k > 0){
1494 p = ev[no - k];
1495 B = sum(ev[nev])*2.0;
1496 wr = (B*B*100.0)+1;
1497 val = ev[nev];
1498 ev[nev] = p*(B-val)*(B-val)/wr;
1499 A = U%*%diag(ev)%*%t(U);
1501 A <- as.data.frame(A);
1502 colnames(A) <- A_wide[,1];
1503 A\$stock_id <- A_wide[,1];
1504 A_threecol <- melt(A, id.vars = c(\'stock_id\'), measure.vars = A_wide[,1]);
1505 A_threecol\$stock_id <- substring(A_threecol\$stock_id, 2);
1506 A_threecol\$variable <- substring(A_threecol\$variable, 2);
1507 write.table(data.frame(variable = A_threecol\$variable, stock_id = A_threecol\$stock_id, value = A_threecol\$value), file=\''.$grm_out_tempfile.'\', row.names=FALSE, col.names=FALSE, sep=\'\t\');"';
1508 print STDERR $cmd."\n";
1509 my $status = system("$cmd > /dev/null");
1511 my $csv = Text::CSV->new({ sep_char => "\t" });
1513 my %rel_pos_def_result_hash;
1514 open(my $F3, '<', $grm_out_tempfile)
1515 or die "Could not open file '$grm_out_tempfile' $!";
1517 print STDERR "Opened $grm_out_tempfile\n";
1519 while (my $row = <$F3>) {
1520 my @columns;
1521 if ($csv->parse($row)) {
1522 @columns = $csv->fields();
1524 my $stock_id1 = $columns[0];
1525 my $stock_id2 = $columns[1];
1526 my $val = $columns[2];
1527 $rel_pos_def_result_hash{$stock_id1}->{$stock_id2} = $val;
1529 close($F3);
1531 my $data_pos_def = '';
1532 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
1533 my %result_hash;
1534 foreach my $s (sort @accession_ids) {
1535 foreach my $c (sort @accession_ids) {
1536 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
1537 my $val = $rel_pos_def_result_hash{$s}->{$c};
1538 if (defined $val and length $val) {
1539 $result_hash{$s}->{$c} = $val;
1540 $data_pos_def .= "$s\t$c\t$val\n";
1546 else {
1547 my %result_hash;
1548 foreach my $s (sort @accession_ids) {
1549 foreach my $c (sort @accession_ids) {
1550 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
1551 my $val = $rel_pos_def_result_hash{$s}->{$c};
1552 if (defined $val and length $val) {
1553 $result_hash{$s}->{$c} = $val;
1554 $result_hash{$c}->{$s} = $val;
1555 $data_pos_def .= "S$s\tS$c\t$val\n";
1556 if ($s != $c) {
1557 $data_pos_def .= "S$c\tS$s\t$val\n";
1565 open(my $F4, ">", $grm_out_posdef_tempfile) || die "Can't open file ".$grm_out_posdef_tempfile;
1566 print $F4 $data_pos_def;
1567 close($F4);
1569 $grm_file = $grm_out_posdef_tempfile;
1571 elsif ($use_parental_grms_if_compute_from_parents) {
1572 my $shared_cluster_dir_config = $c->config->{cluster_shared_tempdir};
1573 my $tmp_arm_dir = $shared_cluster_dir_config."/tmp_download_arm";
1574 mkdir $tmp_arm_dir if ! -d $tmp_arm_dir;
1575 my ($arm_tempfile_fh, $arm_tempfile) = tempfile("drone_stats_download_arm_XXXXX", DIR=> $tmp_arm_dir);
1576 my ($grm1_tempfile_fh, $grm1_tempfile) = tempfile("drone_stats_download_grm1_XXXXX", DIR=> $tmp_arm_dir);
1577 my ($grm_out_temp_tempfile_fh, $grm_out_temp_tempfile) = tempfile("drone_stats_download_grm_temp_out_XXXXX", DIR=> $tmp_arm_dir);
1578 my ($grm_out_tempfile_fh, $grm_out_tempfile) = tempfile("drone_stats_download_grm_out_XXXXX", DIR=> $tmp_arm_dir);
1579 my ($grm_out_posdef_tempfile_fh, $grm_out_posdef_tempfile) = tempfile("drone_stats_download_grm_out_XXXXX", DIR=> $tmp_arm_dir);
1581 if (!$protocol_id) {
1582 $protocol_id = undef;
1585 my $pedigree_arm = CXGN::Pedigree::ARM->new({
1586 bcs_schema=>$schema,
1587 arm_temp_file=>$arm_tempfile,
1588 people_schema=>$people_schema,
1589 accession_id_list=>\@accession_ids,
1590 # plot_id_list=>\@plot_id_list,
1591 cache_root=>$c->config->{cache_file_path},
1592 download_format=>'matrix', #either 'matrix', 'three_column', or 'heatmap'
1594 my ($parent_hash, $stock_ids, $all_accession_stock_ids, $female_stock_ids, $male_stock_ids) = $pedigree_arm->get_arm(
1595 $shared_cluster_dir_config,
1596 $c->config->{backend},
1597 $c->config->{cluster_host},
1598 $c->config->{'web_cluster_queue'},
1599 $c->config->{basepath}
1601 # print STDERR Dumper $parent_hash;
1603 my $female_geno = CXGN::Genotype::GRM->new({
1604 bcs_schema=>$schema,
1605 grm_temp_file=>$grm1_tempfile,
1606 people_schema=>$people_schema,
1607 cache_root=>$c->config->{cache_file_path},
1608 accession_id_list=>$female_stock_ids,
1609 protocol_id=>$protocol_id,
1610 get_grm_for_parental_accessions=>0,
1611 download_format=>'three_column_reciprocal'
1612 # minor_allele_frequency=>$minor_allele_frequency,
1613 # marker_filter=>$marker_filter,
1614 # individuals_filter=>$individuals_filter
1616 my $female_grm_data = $female_geno->download_grm(
1617 'data',
1618 $shared_cluster_dir_config,
1619 $c->config->{backend},
1620 $c->config->{cluster_host},
1621 $c->config->{'web_cluster_queue'},
1622 $c->config->{basepath}
1624 my @fl = split '\n', $female_grm_data;
1625 my %female_parent_grm;
1626 foreach (@fl) {
1627 my @l = split '\t', $_;
1628 $female_parent_grm{$l[0]}->{$l[1]} = $l[2];
1630 # print STDERR Dumper \%female_parent_grm;
1632 my $male_geno = CXGN::Genotype::GRM->new({
1633 bcs_schema=>$schema,
1634 grm_temp_file=>$grm1_tempfile,
1635 people_schema=>$people_schema,
1636 cache_root=>$c->config->{cache_file_path},
1637 accession_id_list=>$male_stock_ids,
1638 protocol_id=>$protocol_id,
1639 get_grm_for_parental_accessions=>0,
1640 download_format=>'three_column_reciprocal'
1641 # minor_allele_frequency=>$minor_allele_frequency,
1642 # marker_filter=>$marker_filter,
1643 # individuals_filter=>$individuals_filter
1645 my $male_grm_data = $male_geno->download_grm(
1646 'data',
1647 $shared_cluster_dir_config,
1648 $c->config->{backend},
1649 $c->config->{cluster_host},
1650 $c->config->{'web_cluster_queue'},
1651 $c->config->{basepath}
1653 my @ml = split '\n', $male_grm_data;
1654 my %male_parent_grm;
1655 foreach (@ml) {
1656 my @l = split '\t', $_;
1657 $male_parent_grm{$l[0]}->{$l[1]} = $l[2];
1659 # print STDERR Dumper \%male_parent_grm;
1661 my %rel_result_hash;
1662 foreach my $a1 (@accession_ids) {
1663 foreach my $a2 (@accession_ids) {
1664 my $female_parent1 = $parent_hash->{$a1}->{female_stock_id};
1665 my $male_parent1 = $parent_hash->{$a1}->{male_stock_id};
1666 my $female_parent2 = $parent_hash->{$a2}->{female_stock_id};
1667 my $male_parent2 = $parent_hash->{$a2}->{male_stock_id};
1669 my $female_rel = 0;
1670 if ($female_parent1 && $female_parent2 && $female_parent_grm{'S'.$female_parent1}->{'S'.$female_parent2}) {
1671 $female_rel = $female_parent_grm{'S'.$female_parent1}->{'S'.$female_parent2};
1673 elsif ($a1 == $a2) {
1674 $female_rel = 1;
1677 my $male_rel = 0;
1678 if ($male_parent1 && $male_parent2 && $male_parent_grm{'S'.$male_parent1}->{'S'.$male_parent2}) {
1679 $male_rel = $male_parent_grm{'S'.$male_parent1}->{'S'.$male_parent2};
1681 elsif ($a1 == $a2) {
1682 $male_rel = 1;
1684 # print STDERR "$a1 $a2 $female_rel $male_rel\n";
1686 my $rel = 0.5*($female_rel + $male_rel);
1687 $rel_result_hash{$a1}->{$a2} = $rel;
1690 # print STDERR Dumper \%rel_result_hash;
1692 my $data = '';
1693 my %result_hash;
1694 foreach my $s (sort @accession_ids) {
1695 foreach my $c (sort @accession_ids) {
1696 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
1697 my $val = $rel_result_hash{$s}->{$c};
1698 if (defined $val and length $val) {
1699 $result_hash{$s}->{$c} = $val;
1700 $data .= "S$s\tS$c\t$val\n";
1706 # print STDERR Dumper $data;
1707 open(my $F2, ">", $grm_out_temp_tempfile) || die "Can't open file ".$grm_out_temp_tempfile;
1708 print $F2 $data;
1709 close($F2);
1711 my $cmd = 'R -e "library(data.table); library(scales); library(tidyr); library(reshape2);
1712 three_col <- fread(\''.$grm_out_temp_tempfile.'\', header=FALSE, sep=\'\t\');
1713 A_wide <- dcast(three_col, V1~V2, value.var=\'V3\');
1714 A_1 <- A_wide[,-1];
1715 A_1[is.na(A_1)] <- 0;
1716 A <- A_1 + t(A_1);
1717 diag(A) <- diag(as.matrix(A_1));
1718 E = eigen(A);
1719 ev = E\$values;
1720 U = E\$vectors;
1721 no = dim(A)[1];
1722 nev = which(ev < 0);
1723 wr = 0;
1724 k=length(nev);
1725 if(k > 0){
1726 p = ev[no - k];
1727 B = sum(ev[nev])*2.0;
1728 wr = (B*B*100.0)+1;
1729 val = ev[nev];
1730 ev[nev] = p*(B-val)*(B-val)/wr;
1731 A = U%*%diag(ev)%*%t(U);
1733 A <- as.data.frame(A);
1734 colnames(A) <- A_wide[,1];
1735 A\$stock_id <- A_wide[,1];
1736 A_threecol <- melt(A, id.vars = c(\'stock_id\'), measure.vars = A_wide[,1]);
1737 A_threecol\$stock_id <- substring(A_threecol\$stock_id, 2);
1738 A_threecol\$variable <- substring(A_threecol\$variable, 2);
1739 write.table(data.frame(variable = A_threecol\$variable, stock_id = A_threecol\$stock_id, value = A_threecol\$value), file=\''.$grm_out_tempfile.'\', row.names=FALSE, col.names=FALSE, sep=\'\t\');"';
1740 print STDERR $cmd."\n";
1741 my $status = system("$cmd > /dev/null");
1743 my $csv = Text::CSV->new({ sep_char => "\t" });
1745 my %rel_pos_def_result_hash;
1746 open(my $F3, '<', $grm_out_tempfile)
1747 or die "Could not open file '$grm_out_tempfile' $!";
1749 print STDERR "Opened $grm_out_tempfile\n";
1751 while (my $row = <$F3>) {
1752 my @columns;
1753 if ($csv->parse($row)) {
1754 @columns = $csv->fields();
1756 my $stock_id1 = $columns[0];
1757 my $stock_id2 = $columns[1];
1758 my $val = $columns[2];
1759 $rel_pos_def_result_hash{$stock_id1}->{$stock_id2} = $val;
1761 close($F3);
1763 my $data_pos_def = '';
1764 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
1765 my %result_hash;
1766 foreach my $s (sort @accession_ids) {
1767 foreach my $c (sort @accession_ids) {
1768 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
1769 my $val = $rel_pos_def_result_hash{$s}->{$c};
1770 if (defined $val and length $val) {
1771 $result_hash{$s}->{$c} = $val;
1772 $data_pos_def .= "$s\t$c\t$val\n";
1778 else {
1779 my %result_hash;
1780 foreach my $s (sort @accession_ids) {
1781 foreach my $c (sort @accession_ids) {
1782 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
1783 my $val = $rel_pos_def_result_hash{$s}->{$c};
1784 if (defined $val and length $val) {
1785 $result_hash{$s}->{$c} = $val;
1786 $result_hash{$c}->{$s} = $val;
1787 $data_pos_def .= "S$s\tS$c\t$val\n";
1788 if ($s != $c) {
1789 $data_pos_def .= "S$c\tS$s\t$val\n";
1797 open(my $F4, ">", $grm_out_posdef_tempfile) || die "Can't open file ".$grm_out_posdef_tempfile;
1798 print $F4 $data_pos_def;
1799 close($F4);
1801 $grm_file = $grm_out_posdef_tempfile;
1803 else {
1804 my $shared_cluster_dir_config = $c->config->{cluster_shared_tempdir};
1805 my $tmp_grm_dir = $shared_cluster_dir_config."/tmp_genotype_download_grm";
1806 mkdir $tmp_grm_dir if ! -d $tmp_grm_dir;
1807 my ($grm_tempfile_fh, $grm_tempfile) = tempfile("drone_stats_download_grm_XXXXX", DIR=> $tmp_grm_dir);
1808 my ($grm_out_tempfile_fh, $grm_out_tempfile) = tempfile("drone_stats_download_grm_XXXXX", DIR=> $tmp_grm_dir);
1810 if (!$protocol_id) {
1811 $protocol_id = undef;
1814 my $grm_search_params = {
1815 bcs_schema=>$schema,
1816 grm_temp_file=>$grm_tempfile,
1817 people_schema=>$people_schema,
1818 cache_root=>$c->config->{cache_file_path},
1819 accession_id_list=>\@accession_ids,
1820 protocol_id=>$protocol_id,
1821 get_grm_for_parental_accessions=>$compute_from_parents,
1822 # minor_allele_frequency=>$minor_allele_frequency,
1823 # marker_filter=>$marker_filter,
1824 # individuals_filter=>$individuals_filter
1827 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
1828 $grm_search_params->{download_format} = 'three_column_stock_id_integer';
1830 else {
1831 $grm_search_params->{download_format} = 'three_column_reciprocal';
1834 my $geno = CXGN::Genotype::GRM->new($grm_search_params);
1835 my $grm_data = $geno->download_grm(
1836 'data',
1837 $shared_cluster_dir_config,
1838 $c->config->{backend},
1839 $c->config->{cluster_host},
1840 $c->config->{'web_cluster_queue'},
1841 $c->config->{basepath}
1844 open(my $F2, ">", $grm_out_tempfile) || die "Can't open file ".$grm_out_tempfile;
1845 print $F2 $grm_data;
1846 close($F2);
1847 $grm_file = $grm_out_tempfile;
1851 elsif ($compute_relationship_matrix_from_htp_phenotypes eq 'htp_phenotypes') {
1853 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
1854 'MaterializedViewTable',
1856 bcs_schema=>$schema,
1857 data_level=>'plot',
1858 trial_list=>$field_trial_id_list,
1859 include_timestamp=>0,
1860 exclude_phenotype_outlier=>0
1863 my ($data, $unique_traits) = $phenotypes_search->search();
1865 if (scalar(@$data) == 0) {
1866 $c->stash->{rest} = { error => "There are no phenotypes for the trial you have selected!"};
1867 return;
1870 my $q_time = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
1871 my $h_time = $schema->storage->dbh()->prepare($q_time);
1873 my %seen_plot_names_htp_rel;
1874 my %phenotype_data_htp_rel;
1875 my %seen_times_htp_rel;
1876 foreach my $obs_unit (@$data){
1877 my $germplasm_name = $obs_unit->{germplasm_uniquename};
1878 my $germplasm_stock_id = $obs_unit->{germplasm_stock_id};
1879 my $row_number = $obs_unit->{obsunit_row_number} || '';
1880 my $col_number = $obs_unit->{obsunit_col_number} || '';
1881 my $rep = $obs_unit->{obsunit_rep};
1882 my $block = $obs_unit->{obsunit_block};
1883 $seen_plot_names_htp_rel{$obs_unit->{observationunit_uniquename}} = $obs_unit;
1884 my $observations = $obs_unit->{observations};
1885 foreach (@$observations){
1886 if ($_->{associated_image_project_time_json}) {
1887 my $related_time_terms_json = decode_json $_->{associated_image_project_time_json};
1889 my $time_days_cvterm = $related_time_terms_json->{day};
1890 my $time_days_term_string = $time_days_cvterm;
1891 my $time_days = (split '\|', $time_days_cvterm)[0];
1892 my $time_days_value = (split ' ', $time_days)[1];
1894 my $time_gdd_value = $related_time_terms_json->{gdd_average_temp} + 0;
1895 my $gdd_term_string = "GDD $time_gdd_value";
1896 $h_time->execute($gdd_term_string, 'cxgn_time_ontology');
1897 my ($gdd_cvterm_id) = $h_time->fetchrow_array();
1898 if (!$gdd_cvterm_id) {
1899 my $new_gdd_term = $schema->resultset("Cv::Cvterm")->create_with({
1900 name => $gdd_term_string,
1901 cv => 'cxgn_time_ontology'
1903 $gdd_cvterm_id = $new_gdd_term->cvterm_id();
1905 my $time_gdd_term_string = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $gdd_cvterm_id, 'extended');
1907 $phenotype_data_htp_rel{$obs_unit->{observationunit_uniquename}}->{$_->{trait_name}} = $_->{value};
1908 $seen_times_htp_rel{$_->{trait_name}} = [$time_days_value, $time_days_term_string, $time_gdd_value, $time_gdd_term_string];
1913 my @allowed_standard_htp_values = ('Nonzero Pixel Count', 'Total Pixel Sum', 'Mean Pixel Value', 'Harmonic Mean Pixel Value', 'Median Pixel Value', 'Pixel Variance', 'Pixel Standard Deviation', 'Pixel Population Standard Deviation', 'Minimum Pixel Value', 'Maximum Pixel Value', 'Minority Pixel Value', 'Minority Pixel Count', 'Majority Pixel Value', 'Majority Pixel Count', 'Pixel Group Count');
1914 my %filtered_seen_times_htp_rel;
1915 while (my ($t, $time) = each %seen_times_htp_rel) {
1916 my $allowed = 0;
1917 foreach (@allowed_standard_htp_values) {
1918 if (index($t, $_) != -1) {
1919 $allowed = 1;
1920 last;
1923 if ($allowed) {
1924 $filtered_seen_times_htp_rel{$t} = $time;
1928 my @seen_plot_names_htp_rel_sorted = sort keys %seen_plot_names_htp_rel;
1929 my @filtered_seen_times_htp_rel_sorted = sort keys %filtered_seen_times_htp_rel;
1931 my @header_htp = ('plot_id', 'plot_name', 'accession_id', 'accession_name', 'rep', 'block');
1933 my %trait_name_encoder_htp;
1934 my %trait_name_encoder_rev_htp;
1935 my $trait_name_encoded_htp = 1;
1936 my @header_traits_htp;
1937 foreach my $trait_name (@filtered_seen_times_htp_rel_sorted) {
1938 if (!exists($trait_name_encoder_htp{$trait_name})) {
1939 my $trait_name_e = 't'.$trait_name_encoded_htp;
1940 $trait_name_encoder_htp{$trait_name} = $trait_name_e;
1941 $trait_name_encoder_rev_htp{$trait_name_e} = $trait_name;
1942 push @header_traits_htp, $trait_name_e;
1943 $trait_name_encoded_htp++;
1947 my @htp_pheno_matrix;
1948 if ($compute_relationship_matrix_from_htp_phenotypes_time_points eq 'all') {
1949 push @header_htp, @header_traits_htp;
1950 push @htp_pheno_matrix, \@header_htp;
1952 foreach my $p (@seen_plot_names_htp_rel_sorted) {
1953 my $obj = $seen_plot_names_htp_rel{$p};
1954 my @row = ($obj->{observationunit_stock_id}, $obj->{observationunit_uniquename}, $obj->{germplasm_stock_id}, $obj->{germplasm_uniquename}, $obj->{obsunit_rep}, $obj->{obsunit_block});
1955 foreach my $t (@filtered_seen_times_htp_rel_sorted) {
1956 my $val = $phenotype_data_htp_rel{$p}->{$t} + 0;
1957 push @row, $val;
1959 push @htp_pheno_matrix, \@row;
1962 elsif ($compute_relationship_matrix_from_htp_phenotypes_time_points eq 'latest_trait') {
1963 my $max_day = 0;
1964 foreach (keys %seen_days_after_plantings) {
1965 if ($_ + 0 > $max_day) {
1966 $max_day = $_;
1970 foreach my $t (@filtered_seen_times_htp_rel_sorted) {
1971 my $day = $filtered_seen_times_htp_rel{$t}->[0];
1972 if ($day <= $max_day) {
1973 push @header_htp, $t;
1976 push @htp_pheno_matrix, \@header_htp;
1978 foreach my $p (@seen_plot_names_htp_rel_sorted) {
1979 my $obj = $seen_plot_names_htp_rel{$p};
1980 my @row = ($obj->{observationunit_stock_id}, $obj->{observationunit_uniquename}, $obj->{germplasm_stock_id}, $obj->{germplasm_uniquename}, $obj->{obsunit_rep}, $obj->{obsunit_block});
1981 foreach my $t (@filtered_seen_times_htp_rel_sorted) {
1982 my $day = $filtered_seen_times_htp_rel{$t}->[0];
1983 if ($day <= $max_day) {
1984 my $val = $phenotype_data_htp_rel{$p}->{$t} + 0;
1985 push @row, $val;
1988 push @htp_pheno_matrix, \@row;
1991 elsif ($compute_relationship_matrix_from_htp_phenotypes_time_points eq 'vegetative') {
1994 elsif ($compute_relationship_matrix_from_htp_phenotypes_time_points eq 'reproductive') {
1997 elsif ($compute_relationship_matrix_from_htp_phenotypes_time_points eq 'mature') {
2000 else {
2001 $c->stash->{rest} = { error => "The value of $compute_relationship_matrix_from_htp_phenotypes_time_points htp_pheno_rel_matrix_time_points is not valid!" };
2002 return;
2005 open(my $htp_pheno_f, ">", $stats_out_htp_rel_tempfile_input) || die "Can't open file ".$stats_out_htp_rel_tempfile_input;
2006 foreach (@htp_pheno_matrix) {
2007 my $line = join "\t", @$_;
2008 print $htp_pheno_f $line."\n";
2010 close($htp_pheno_f);
2012 my %rel_htp_result_hash;
2013 if ($compute_relationship_matrix_from_htp_phenotypes_type eq 'correlations') {
2014 my $htp_cmd = 'R -e "library(lme4); library(data.table);
2015 mat <- fread(\''.$stats_out_htp_rel_tempfile_input.'\', header=TRUE, sep=\'\t\');
2016 mat_agg <- aggregate(mat[, 7:ncol(mat)], list(mat\$accession_id), mean);
2017 mat_pheno <- mat_agg[,2:ncol(mat_agg)];
2018 cor_mat <- cor(t(mat_pheno));
2019 rownames(cor_mat) <- mat_agg[,1];
2020 colnames(cor_mat) <- mat_agg[,1];
2021 range01 <- function(x){(x-min(x))/(max(x)-min(x))};
2022 cor_mat <- range01(cor_mat);
2023 write.table(cor_mat, file=\''.$stats_out_htp_rel_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');"';
2024 print STDERR Dumper $htp_cmd;
2025 my $status = system("$htp_cmd > /dev/null");
2027 elsif ($compute_relationship_matrix_from_htp_phenotypes_type eq 'blues') {
2028 my $htp_cmd = 'R -e "library(lme4); library(data.table);
2029 mat <- fread(\''.$stats_out_htp_rel_tempfile_input.'\', header=TRUE, sep=\'\t\');
2030 blues <- data.frame(id = seq(1,length(unique(mat\$accession_id))));
2031 varlist <- names(mat)[7:ncol(mat)];
2032 blues.models <- lapply(varlist, function(x) {
2033 tryCatch(
2034 lmer(substitute(i ~ 1 + (1|accession_id), list(i = as.name(x))), data = mat, REML = FALSE, control = lmerControl(optimizer =\'Nelder_Mead\', boundary.tol='.$compute_relationship_matrix_from_htp_phenotypes_blues_inversion.' ) ), error=function(e) {}
2037 counter = 1;
2038 for (m in blues.models) {
2039 if (!is.null(m)) {
2040 blues\$accession_id <- row.names(ranef(m)\$accession_id);
2041 blues[,ncol(blues) + 1] <- ranef(m)\$accession_id\$\`(Intercept)\`;
2042 colnames(blues)[ncol(blues)] <- varlist[counter];
2044 counter = counter + 1;
2046 blues_vals <- as.matrix(blues[,3:ncol(blues)]);
2047 blues_vals <- apply(blues_vals, 2, function(y) (y - mean(y)) / sd(y) ^ as.logical(sd(y)));
2048 rel <- (1/ncol(blues_vals)) * (blues_vals %*% t(blues_vals));
2049 rownames(rel) <- blues[,2];
2050 colnames(rel) <- blues[,2];
2051 write.table(rel, file=\''.$stats_out_htp_rel_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');"';
2052 print STDERR Dumper $htp_cmd;
2053 my $status = system("$htp_cmd > /dev/null");
2055 else {
2056 $c->stash->{rest} = { error => "The value of $compute_relationship_matrix_from_htp_phenotypes_type htp_pheno_rel_matrix_type is not valid!" };
2057 return;
2060 my $csv = Text::CSV->new({ sep_char => "\t" });
2062 open(my $htp_rel_res, '<', $stats_out_htp_rel_tempfile)
2063 or die "Could not open file '$stats_out_htp_rel_tempfile' $!";
2065 print STDERR "Opened $stats_out_htp_rel_tempfile\n";
2066 my $header_row = <$htp_rel_res>;
2067 my @header;
2068 if ($csv->parse($header_row)) {
2069 @header = $csv->fields();
2072 while (my $row = <$htp_rel_res>) {
2073 my @columns;
2074 if ($csv->parse($row)) {
2075 @columns = $csv->fields();
2077 my $stock_id1 = $columns[0];
2078 my $counter = 1;
2079 foreach my $stock_id2 (@header) {
2080 my $val = $columns[$counter];
2081 $rel_htp_result_hash{$stock_id1}->{$stock_id2} = $val;
2082 $counter++;
2085 close($htp_rel_res);
2087 my $data_rel_htp = '';
2088 my %result_hash;
2089 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
2090 foreach my $s (sort @accession_ids) {
2091 foreach my $c (sort @accession_ids) {
2092 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
2093 my $val = $rel_htp_result_hash{$s}->{$c};
2094 if (defined $val and length $val) {
2095 $result_hash{$s}->{$c} = $val;
2096 $data_rel_htp .= "$s\t$c\t$val\n";
2102 else {
2103 foreach my $s (sort @accession_ids) {
2104 foreach my $c (sort @accession_ids) {
2105 if (!exists($result_hash{$s}->{$c}) && !exists($result_hash{$c}->{$s})) {
2106 my $val = $rel_htp_result_hash{$s}->{$c};
2107 if (defined $val and length $val) {
2108 $result_hash{$s}->{$c} = $val;
2109 $result_hash{$c}->{$s} = $val;
2110 $data_rel_htp .= "S$s\tS$c\t$val\n";
2111 if ($s != $c) {
2112 $data_rel_htp .= "S$c\tS$s\t$val\n";
2120 open(my $htp_rel_out, ">", $stats_out_htp_rel_tempfile_out) || die "Can't open file ".$stats_out_htp_rel_tempfile_out;
2121 print $htp_rel_out $data_rel_htp;
2122 close($htp_rel_out);
2124 $grm_file = $stats_out_htp_rel_tempfile_out;
2126 else {
2127 $c->stash->{rest} = { error => "The value of $compute_relationship_matrix_from_htp_phenotypes is not valid!" };
2128 return;
2132 my $time = DateTime->now();
2133 my $timestamp = $time->ymd()."_".$time->hms();
2135 if ($statistics_select eq 'lmer_germplasmname_replicate') {
2136 $statistical_ontology_term = "Univariate linear mixed model genetic BLUPs using germplasmName computed using LMER R|SGNSTAT:0000002";
2137 $analysis_result_values_type = "analysis_result_values_match_accession_names";
2138 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_lmer_germplasmname_replicate_phenotype_file";
2140 foreach my $t (@sorted_trait_names) {
2141 my $cmd = 'R -e "library(lme4); library(data.table);
2142 mat <- fread(\''.$stats_tempfile.'\', header=TRUE, sep=\',\');
2143 mix <- lmer('.$trait_name_encoder{$t}.' ~ replicate + (1|id), data = mat, na.action = na.omit );
2144 #mix.summary <- summary(mix);
2145 #ve <- mix.summary\$varcor\$id[1,1]/(mix.summary\$varcor\$id[1,1] + (mix.summary\$sigma)^2);
2146 write.table(ranef(mix)\$id, file=\''.$stats_out_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');"';
2147 my $status = system("$cmd > /dev/null");
2149 my $csv = Text::CSV->new({ sep_char => "\t" });
2151 open(my $fh, '<', $stats_out_tempfile)
2152 or die "Could not open file '$stats_out_tempfile' $!";
2154 print STDERR "Opened $stats_out_tempfile\n";
2155 my $header = <$fh>;
2156 my @header_cols;
2157 if ($csv->parse($header)) {
2158 @header_cols = $csv->fields();
2161 while (my $row = <$fh>) {
2162 my @columns;
2163 if ($csv->parse($row)) {
2164 @columns = $csv->fields();
2166 my $stock_id = $columns[0];
2167 my $stock_name = $stock_info{$stock_id}->{uniquename};
2168 my $value = $columns[1];
2169 $result_blup_data->{$stock_name}->{$t} = [$value, $timestamp, $user_name, '', ''];
2171 close($fh);
2174 elsif ($statistics_select eq 'sommer_grm_genetic_blups') {
2175 $statistical_ontology_term = "Multivariate genetic BLUPs using genetic relationship matrix computed using Sommer R|SGNSTAT:0000024";
2177 $analysis_result_values_type = "analysis_result_values_match_accession_names";
2178 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_sommer_grm_genetic_blups_phenotype_file";
2180 @unique_plot_names = sort keys %seen_plot_names;
2182 my @encoded_traits = values %trait_name_encoder;
2183 my $encoded_trait_string = join ',', @encoded_traits;
2184 my $number_traits = scalar(@encoded_traits);
2185 my $cbind_string = $number_traits > 1 ? "cbind($encoded_trait_string)" : $encoded_trait_string;
2187 my $cmd = 'R -e "library(sommer); library(data.table); library(reshape2);
2188 mat <- data.frame(fread(\''.$stats_tempfile.'\', header=TRUE, sep=\',\'));
2189 geno_mat_3col <- data.frame(fread(\''.$grm_file.'\', header=FALSE, sep=\'\t\'));
2190 geno_mat <- acast(geno_mat_3col, V1~V2, value.var=\'V3\');
2191 geno_mat[is.na(geno_mat)] <- 0;
2192 mix <- mmer('.$cbind_string.'~1 + replicate, random=~vs(id, Gu=geno_mat, Gtc=unsm('.$number_traits.')), rcov=~vs(units, Gtc=unsm('.$number_traits.')), data=mat, tolparinv='.$tolparinv.');
2193 write.table(mix\$U\$\`u:id\`, file=\''.$stats_out_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');
2195 print STDERR Dumper $cmd;
2196 my $status = system("$cmd > /dev/null");
2198 my $csv = Text::CSV->new({ sep_char => "\t" });
2200 my %unique_accessions_seen;
2201 open(my $fh, '<', $stats_out_tempfile)
2202 or die "Could not open file '$stats_out_tempfile' $!";
2204 print STDERR "Opened $stats_out_tempfile\n";
2205 my $header = <$fh>;
2206 my @header_cols;
2207 if ($csv->parse($header)) {
2208 @header_cols = $csv->fields();
2211 while (my $row = <$fh>) {
2212 my @columns;
2213 if ($csv->parse($row)) {
2214 @columns = $csv->fields();
2216 my $col_counter = 0;
2217 foreach my $encoded_trait (@header_cols) {
2218 my $trait = $trait_name_encoder_rev{$encoded_trait};
2219 my $stock_id = $columns[0];
2221 my $stock_name = $stock_info{$stock_id}->{uniquename};
2222 my $value = $columns[$col_counter+1];
2223 $result_blup_data->{$stock_name}->{$trait} = [$value, $timestamp, $user_name, '', ''];
2224 $col_counter++;
2225 $unique_accessions_seen{$stock_name}++;
2228 close($fh);
2229 @unique_accession_names = keys %unique_accessions_seen;
2231 elsif ($statistics_select eq 'sommer_grm_spatial_genetic_blups') {
2232 $statistical_ontology_term = "Multivariate linear mixed model genetic BLUPs using genetic relationship matrix and row and column spatial effects computed using Sommer R|SGNSTAT:0000001"; #In the JS this is set to either the genetic or spatial BLUP term (Multivariate linear mixed model 2D spline spatial BLUPs using genetic relationship matrix and row and column spatial effects computed using Sommer R|SGNSTAT:0000003) when saving analysis results
2234 $analysis_result_values_type = "analysis_result_values_match_accession_names";
2235 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_sommer_grm_spatial_genetic_blups_phenotype_file";
2237 @unique_plot_names = sort keys %seen_plot_names;
2239 my @encoded_traits = values %trait_name_encoder;
2240 my $encoded_trait_string = join ',', @encoded_traits;
2241 my $number_traits = scalar(@encoded_traits);
2242 my $cbind_string = $number_traits > 1 ? "cbind($encoded_trait_string)" : $encoded_trait_string;
2244 my $cmd = 'R -e "library(sommer); library(data.table); library(reshape2);
2245 mat <- data.frame(fread(\''.$stats_tempfile.'\', header=TRUE, sep=\',\'));
2246 geno_mat_3col <- data.frame(fread(\''.$grm_file.'\', header=FALSE, sep=\'\t\'));
2247 geno_mat <- acast(geno_mat_3col, V1~V2, value.var=\'V3\');
2248 geno_mat[is.na(geno_mat)] <- 0;
2249 mat\$rowNumber <- as.numeric(mat\$rowNumber);
2250 mat\$colNumber <- as.numeric(mat\$colNumber);
2251 mat\$rowNumberFactor <- as.factor(mat\$rowNumberFactor);
2252 mat\$colNumberFactor <- as.factor(mat\$colNumberFactor);
2253 mix <- mmer('.$cbind_string.'~1 + replicate, random=~vs(id, Gu=geno_mat, Gtc=unsm('.$number_traits.')) +vs(rowNumberFactor, Gtc=diag('.$number_traits.')) +vs(colNumberFactor, Gtc=diag('.$number_traits.')) +vs(spl2D(rowNumber, colNumber), Gtc=diag('.$number_traits.')), rcov=~vs(units, Gtc=unsm('.$number_traits.')), data=mat, tolparinv='.$tolparinv.');
2254 #gen_cor <- cov2cor(mix\$sigma\$\`u:id\`);
2255 write.table(mix\$U\$\`u:id\`, file=\''.$stats_out_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');
2256 write.table(mix\$U\$\`u:rowNumberFactor\`, file=\''.$stats_out_tempfile_row.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');
2257 write.table(mix\$U\$\`u:colNumberFactor\`, file=\''.$stats_out_tempfile_col.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');
2258 X <- with(mat, spl2D(rowNumber, colNumber));
2259 spatial_blup_results <- data.frame(plot_id = mat\$plot_id);
2261 my $trait_index = 1;
2262 foreach my $enc_trait_name (@encoded_traits) {
2263 $cmd .= '
2264 blups'.$trait_index.' <- mix\$U\$\`u:rowNumber\`\$'.$enc_trait_name.';
2265 spatial_blup_results\$'.$enc_trait_name.' <- data.matrix(X) %*% data.matrix(blups'.$trait_index.');
2267 $trait_index++;
2269 $cmd .= 'write.table(spatial_blup_results, file=\''.$stats_out_tempfile_2dspl.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');
2271 print STDERR Dumper $cmd;
2272 my $status = system("$cmd > /dev/null");
2274 my $csv = Text::CSV->new({ sep_char => "\t" });
2276 my %unique_accessions_seen;
2277 open(my $fh, '<', $stats_out_tempfile)
2278 or die "Could not open file '$stats_out_tempfile' $!";
2280 print STDERR "Opened $stats_out_tempfile\n";
2281 my $header = <$fh>;
2282 my @header_cols;
2283 if ($csv->parse($header)) {
2284 @header_cols = $csv->fields();
2287 while (my $row = <$fh>) {
2288 my @columns;
2289 if ($csv->parse($row)) {
2290 @columns = $csv->fields();
2292 my $col_counter = 0;
2293 foreach my $encoded_trait (@header_cols) {
2294 my $trait = $trait_name_encoder_rev{$encoded_trait};
2295 my $stock_id = $columns[0];
2297 my $stock_name = $stock_info{$stock_id}->{uniquename};
2298 my $value = $columns[$col_counter+1];
2299 $result_blup_data->{$stock_name}->{$trait} = [$value, $timestamp, $user_name, '', ''];
2300 $col_counter++;
2301 $unique_accessions_seen{$stock_name}++;
2304 close($fh);
2305 @unique_accession_names = keys %unique_accessions_seen;
2307 my %result_blup_row_data;
2308 my @row_numbers;
2309 open(my $fh_row, '<', $stats_out_tempfile_row)
2310 or die "Could not open file '$stats_out_tempfile_row' $!";
2312 print STDERR "Opened $stats_out_tempfile_row\n";
2313 my $header_row = <$fh_row>;
2314 my @header_cols_row;
2315 if ($csv->parse($header_row)) {
2316 @header_cols_row = $csv->fields();
2319 while (my $row_row = <$fh_row>) {
2320 my @columns_row;
2321 if ($csv->parse($row_row)) {
2322 @columns_row = $csv->fields();
2324 my $col_counter_row = 0;
2325 foreach my $encoded_trait (@header_cols_row) {
2326 my $trait = $trait_name_encoder_rev{$encoded_trait};
2327 my $row_id = $columns_row[0];
2328 push @row_numbers, $row_id;
2329 my $value = $columns_row[$col_counter_row+1];
2330 $result_blup_row_data{$row_id}->{$trait} = $value;
2331 $col_counter_row++;
2334 close($fh_row);
2336 my %result_blup_col_data;
2337 my @col_numbers;
2338 open(my $fh_col, '<', $stats_out_tempfile_col)
2339 or die "Could not open file '$stats_out_tempfile_col' $!";
2341 print STDERR "Opened $stats_out_tempfile_col\n";
2342 my $header_col = <$fh_col>;
2343 my @header_cols_col;
2344 if ($csv->parse($header_col)) {
2345 @header_cols_col = $csv->fields();
2348 while (my $row_col = <$fh_col>) {
2349 my @columns_col;
2350 if ($csv->parse($row_col)) {
2351 @columns_col = $csv->fields();
2353 my $col_counter_col = 0;
2354 foreach my $encoded_trait (@header_cols_col) {
2355 my $trait = $trait_name_encoder_rev{$encoded_trait};
2356 my $col_id = $columns_col[0];
2357 push @col_numbers, $col_id;
2358 my $value = $columns_col[$col_counter_col+1];
2359 $result_blup_col_data{$col_id}->{$trait} = $value;
2360 $col_counter_col++;
2363 close($fh_col);
2365 open(my $fh_2dspl, '<', $stats_out_tempfile_2dspl)
2366 or die "Could not open file '$stats_out_tempfile_2dspl' $!";
2368 print STDERR "Opened $stats_out_tempfile_2dspl\n";
2369 my $header_2dspl = <$fh_2dspl>;
2370 my @header_cols_2dspl;
2371 if ($csv->parse($header_2dspl)) {
2372 @header_cols_2dspl = $csv->fields();
2374 shift @header_cols_2dspl;
2375 while (my $row_2dspl = <$fh_2dspl>) {
2376 my @columns;
2377 if ($csv->parse($row_2dspl)) {
2378 @columns = $csv->fields();
2380 my $col_counter = 0;
2381 foreach my $encoded_trait (@header_cols_2dspl) {
2382 my $trait = $trait_name_encoder_rev{$encoded_trait};
2383 my $plot_id = $columns[0];
2385 my $plot_name = $plot_id_map{$plot_id};
2386 my $value = $columns[$col_counter+1];
2387 $result_blup_spatial_data->{$plot_name}->{$trait} = [$value, $timestamp, $user_name, '', ''];
2388 $col_counter++;
2391 close($fh_2dspl);
2393 # foreach my $trait (@sorted_trait_names) {
2394 # foreach my $row (@row_numbers) {
2395 # foreach my $col (@col_numbers) {
2396 # my $uniquename = $obsunit_row_col{$row}->{$col}->{stock_uniquename};
2397 # my $stock_id = $obsunit_row_col{$row}->{$col}->{stock_id};
2399 # my $row_val = $result_blup_row_data{$row}->{$trait};
2400 # my $col_val = $result_blup_col_data{$col}->{$trait};
2401 # $result_blup_spatial_data->{$uniquename}->{$trait} = [$row_val*$col_val, $timestamp, $user_name, '', ''];
2406 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups') {
2407 $statistical_ontology_term = "Multivariate linear mixed model genetic BLUPs using genetic relationship matrix and temporal Legendre polynomial random regression on days after planting computed using Sommer R|SGNSTAT:0000004"; #In the JS this is set to either the genetic of permanent environment BLUP term (Multivariate linear mixed model permanent environment BLUPs using genetic relationship matrix and temporal Legendre polynomial random regression on days after planting computed using Sommer R|SGNSTAT:0000005) when saving results
2409 $analysis_result_values_type = "analysis_result_values_match_accession_names";
2411 if ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups') {
2412 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_sommer_grm_temporal_leg_random_regression_DAP_genetic_blups_phenotype_file";
2414 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups') {
2415 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_sommer_grm_temporal_leg_random_regression_GDD_genetic_blups_phenotype_file";
2418 my $cmd = 'R -e "library(sommer); library(data.table); library(reshape2); library(orthopolynom);
2419 mat <- fread(\''.$stats_tempfile.'\', header=TRUE, sep=\',\', check.names = FALSE);
2420 geno_mat_3col <- data.frame(fread(\''.$grm_file.'\', header=FALSE, sep=\'\t\'));
2421 geno_mat <- acast(geno_mat_3col, V1~V2, value.var=\'V3\');
2422 geno_mat[is.na(geno_mat)] <- 0;
2423 mat_long <- melt(mat, id.vars=c(\'replicate\', \'block\', \'id\', \'plot_id\', \'rowNumber\', \'colNumber\', \'rowNumberFactor\', \'colNumberFactor\'), variable.name=\'time\', value.name=\'value\');
2424 mat_long\$time <- as.numeric(as.character(mat_long\$time));
2425 mat_long <- mat_long[order(time),];
2426 mat\$rowNumber <- as.numeric(mat\$rowNumber);
2427 mat\$colNumber <- as.numeric(mat\$colNumber);
2428 mat\$rowNumberFactor <- as.factor(mat\$rowNumberFactor);
2429 mat\$colNumberFactor <- as.factor(mat\$colNumberFactor);
2430 mix <- mmer(
2431 value~1 + replicate,
2432 random=~vs(id, Gu=geno_mat) +vs(leg(time,'.$legendre_order_number.', intercept=TRUE), id) +vs(leg(time,'.$legendre_order_number.', intercept=TRUE), plot_id),
2433 rcov=~vs(units),
2434 data=mat_long, tolparinv='.$tolparinv.'
2436 write.table(data.frame(plot_id = mix\$data\$plot_id, time = mix\$data\$time, residuals = mix\$residuals, fitted = mix\$fitted), file=\''.$stats_out_tempfile_residual.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');
2437 write.table(mix\$U\$\`u:id\`, file=\''.$stats_out_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');
2438 genetic_coeff <- data.frame(id = names(mix\$U\$\`leg0:id\`\$value));
2439 pe_coeff <- data.frame(plot_id = names(mix\$U\$\`leg0:plot_id\`\$value));';
2440 for my $leg_num (0..$legendre_order_number) {
2441 $cmd .= 'genetic_coeff\$leg_'.$leg_num.' <- mix\$U\$\`leg'.$leg_num.':id\`\$value;';
2443 for my $leg_num (0..$legendre_order_number) {
2444 $cmd .= 'pe_coeff\$leg_'.$leg_num.' <- mix\$U\$\`leg'.$leg_num.':plot_id\`\$value;';
2446 $cmd .= 'write.table(genetic_coeff, file=\''.$stats_out_tempfile_genetic.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');
2447 write.table(pe_coeff, file=\''.$stats_out_tempfile_permanent_environment.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');"
2449 print STDERR Dumper $cmd;
2450 my $status = system("$cmd > /dev/null");
2452 my $csv = Text::CSV->new({ sep_char => "\t" });
2454 no warnings 'uninitialized';
2456 my %unique_accessions_seen;
2457 my %unique_plots_seen;
2458 my @new_sorted_trait_names;
2459 my %sommer_rr_genetic_coeff;
2460 my %sommer_rr_temporal_coeff;
2461 open(my $fh_genetic, '<', $stats_out_tempfile_genetic)
2462 or die "Could not open file '$stats_out_tempfile_genetic' $!";
2464 print STDERR "Opened $stats_out_tempfile_genetic\n";
2465 my $header = <$fh_genetic>;
2466 my @header_cols;
2467 if ($csv->parse($header)) {
2468 @header_cols = $csv->fields();
2471 while (my $row = <$fh_genetic>) {
2472 my @columns;
2473 if ($csv->parse($row)) {
2474 @columns = $csv->fields();
2477 my $accession_id = $columns[0];
2478 my $accession_name = $stock_info{$accession_id}->{uniquename};
2479 $unique_accessions_seen{$accession_name}++;
2481 my $col_counter = 1;
2482 foreach (0..$legendre_order_number) {
2483 my $value = $columns[$col_counter];
2484 push @{$sommer_rr_genetic_coeff{$accession_name}}, $value;
2485 $col_counter++;
2488 close($fh_genetic);
2490 open(my $fh, '<', $stats_out_tempfile_permanent_environment)
2491 or die "Could not open file '$stats_out_tempfile_permanent_environment' $!";
2493 print STDERR "Opened $stats_out_tempfile_permanent_environment\n";
2494 $header = <$fh>;
2495 if ($csv->parse($header)) {
2496 @header_cols = $csv->fields();
2499 my $row_counter = 0;
2500 while (my $row = <$fh>) {
2501 my @columns;
2502 if ($csv->parse($row)) {
2503 @columns = $csv->fields();
2506 my $plot_id = $columns[0];
2507 my $plot_name = $plot_id_map{$plot_id};
2508 $unique_plots_seen{$plot_name}++;
2510 my $col_counter = 1;
2511 foreach (0..$legendre_order_number) {
2512 my $value = $columns[$col_counter];
2513 push @{$sommer_rr_temporal_coeff{$plot_name}}, $value;
2514 $col_counter++;
2516 $row_counter++;
2518 close($fh);
2520 # print STDERR Dumper \%sommer_rr_genetic_coeff;
2521 # print STDERR Dumper \%sommer_rr_temporal_coeff;
2523 open(my $fh_residual, '<', $stats_out_tempfile_residual)
2524 or die "Could not open file '$stats_out_tempfile_residual' $!";
2526 print STDERR "Opened $stats_out_tempfile_residual\n";
2527 my $header_residual = <$fh_residual>;
2528 my @header_cols_residual;
2529 if ($csv->parse($header_residual)) {
2530 @header_cols_residual = $csv->fields();
2533 while (my $row = <$fh_residual>) {
2534 my @columns;
2535 if ($csv->parse($row)) {
2536 @columns = $csv->fields();
2539 my $stock_id = $columns[0];
2540 my $time = $columns[1];
2541 my $residual = $columns[2];
2542 my $fitted = $columns[3];
2543 my $stock_name = $plot_id_map{$stock_id};
2544 $result_residual_data->{$stock_name}->{$seen_times{$time}} = [$residual, $timestamp, $user_name, '', ''];
2545 $result_fitted_data->{$stock_name}->{$seen_times{$time}} = [$fitted, $timestamp, $user_name, '', ''];
2547 close($fh_residual);
2549 $time_min = 100000000;
2550 $time_max = 0;
2551 foreach (@sorted_trait_names) {
2552 if ($_ < $time_min) {
2553 $time_min = $_;
2555 if ($_ > $time_max) {
2556 $time_max = $_;
2559 print STDERR Dumper [$time_min, $time_max];
2561 my $q_time = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
2562 my $h_time = $schema->storage->dbh()->prepare($q_time);
2564 my %rr_unique_traits;
2566 open(my $Fgc, ">", $coeff_genetic_tempfile) || die "Can't open file ".$coeff_genetic_tempfile;
2568 while ( my ($accession_name, $coeffs) = each %sommer_rr_genetic_coeff) {
2569 my @line = ($accession_name, @$coeffs);
2570 my $line_string = join ',', @line;
2571 print $Fgc "$line_string\n";
2573 foreach my $t_i (0..20) {
2574 my $time = $t_i*5/100;
2575 my $time_rescaled = sprintf("%.2f", $time*($time_max - $time_min) + $time_min);
2577 my $value = 0;
2578 my $coeff_counter = 0;
2579 foreach my $b (@$coeffs) {
2580 my $eval_string = $legendre_coeff_exec[$coeff_counter];
2581 # print STDERR Dumper [$eval_string, $b, $time];
2582 $value += eval $eval_string;
2583 $coeff_counter++;
2586 my $time_term_string = '';
2587 if ($statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups') {
2588 $time_term_string = "GDD $time_rescaled";
2590 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups') {
2591 $time_term_string = "day $time_rescaled"
2593 $h_time->execute($time_term_string, 'cxgn_time_ontology');
2594 my ($time_cvterm_id) = $h_time->fetchrow_array();
2596 if (!$time_cvterm_id) {
2597 my $new_time_term = $schema->resultset("Cv::Cvterm")->create_with({
2598 name => $time_term_string,
2599 cv => 'cxgn_time_ontology'
2601 $time_cvterm_id = $new_time_term->cvterm_id();
2603 my $time_term_string_blup = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $time_cvterm_id, 'extended');
2604 $rr_unique_traits{$time_term_string_blup}++;
2606 $result_blup_data->{$accession_name}->{$time_term_string_blup} = [$value, $timestamp, $user_name, '', ''];
2609 close($Fgc);
2611 open(my $Fpc, ">", $coeff_pe_tempfile) || die "Can't open file ".$coeff_pe_tempfile;
2613 while ( my ($plot_name, $coeffs) = each %sommer_rr_temporal_coeff) {
2614 my @line = ($plot_name, @$coeffs);
2615 my $line_string = join ',', @line;
2616 print $Fpc "$line_string\n";
2618 foreach my $t_i (0..20) {
2619 my $time = $t_i*5/100;
2620 my $time_rescaled = sprintf("%.2f", $time*($time_max - $time_min) + $time_min);
2622 my $value = 0;
2623 my $coeff_counter = 0;
2624 foreach my $b (@$coeffs) {
2625 my $eval_string = $legendre_coeff_exec[$coeff_counter];
2626 # print STDERR Dumper [$eval_string, $b, $time];
2627 $value += eval $eval_string;
2628 $coeff_counter++;
2631 my $time_term_string = '';
2632 if ($statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups') {
2633 $time_term_string = "GDD $time_rescaled";
2635 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups') {
2636 $time_term_string = "day $time_rescaled"
2638 $h_time->execute($time_term_string, 'cxgn_time_ontology');
2639 my ($time_cvterm_id) = $h_time->fetchrow_array();
2641 if (!$time_cvterm_id) {
2642 my $new_time_term = $schema->resultset("Cv::Cvterm")->create_with({
2643 name => $time_term_string,
2644 cv => 'cxgn_time_ontology'
2646 $time_cvterm_id = $new_time_term->cvterm_id();
2648 my $time_term_string_pe = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $time_cvterm_id, 'extended');
2649 $rr_unique_traits{$time_term_string_pe}++;
2651 $result_blup_pe_data->{$plot_name}->{$time_term_string_pe} = [$value, $timestamp, $user_name, '', ''];
2654 close($Fpc);
2656 @sorted_trait_names = sort keys %rr_unique_traits;
2658 elsif ($statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups') {
2659 $statistical_ontology_term = "Multivariate linear mixed model genetic BLUPs using genetic relationship matrix and temporal Legendre polynomial random regression on days after planting computed using Sommer R|SGNSTAT:0000004";
2661 $analysis_result_values_type = "analysis_result_values_match_accession_names";
2663 if ($statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups') {
2664 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_sommer_grm_genetic_leg_random_regression_DAP_genetic_blups_phenotype_file";
2666 elsif ($statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups') {
2667 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_sommer_grm_genetic_leg_random_regression_GDD_genetic_blups_phenotype_file";
2670 my $cmd = 'R -e "library(sommer); library(data.table); library(reshape2); library(orthopolynom);
2671 mat <- fread(\''.$stats_tempfile.'\', header=TRUE, sep=\',\', check.names = FALSE);
2672 geno_mat_3col <- data.frame(fread(\''.$grm_file.'\', header=FALSE, sep=\'\t\'));
2673 geno_mat <- acast(geno_mat_3col, V1~V2, value.var=\'V3\');
2674 geno_mat[is.na(geno_mat)] <- 0;
2675 mat_long <- melt(mat, id.vars=c(\'replicate\', \'block\', \'id\', \'plot_id\', \'rowNumber\', \'colNumber\', \'rowNumberFactor\', \'colNumberFactor\'), variable.name=\'time\', value.name=\'value\');
2676 mat_long\$time <- as.numeric(as.character(mat_long\$time));
2677 mat_long <- mat_long[order(time),];
2678 mat\$rowNumber <- as.numeric(mat\$rowNumber);
2679 mat\$colNumber <- as.numeric(mat\$colNumber);
2680 mat\$rowNumberFactor <- as.factor(mat\$rowNumberFactor);
2681 mat\$colNumberFactor <- as.factor(mat\$colNumberFactor);
2682 mix <- mmer(
2683 value~1 + replicate,
2684 random=~vs(id, Gu=geno_mat) +vs(leg(time,'.$legendre_order_number.', intercept=TRUE), id),
2685 rcov=~vs(units),
2686 data=mat_long, tolparinv='.$tolparinv.'
2688 write.table(data.frame(plot_id = mix\$data\$plot_id, time = mix\$data\$time, residuals = mix\$residuals, fitted = mix\$fitted), file=\''.$stats_out_tempfile_residual.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');
2689 write.table(mix\$U\$\`u:id\`, file=\''.$stats_out_tempfile.'\', row.names=TRUE, col.names=TRUE, sep=\'\t\');
2690 genetic_coeff <- data.frame(id = names(mix\$U\$\`leg0:id\`\$value));';
2691 for my $leg_num (0..$legendre_order_number) {
2692 $cmd .= 'genetic_coeff\$leg_'.$leg_num.' <- mix\$U\$\`leg'.$leg_num.':id\`\$value;';
2694 $cmd .= 'write.table(genetic_coeff, file=\''.$stats_out_tempfile_genetic.'\', row.names=FALSE, col.names=TRUE, sep=\'\t\');"
2696 print STDERR Dumper $cmd;
2697 my $status = system("$cmd > /dev/null/");
2699 my $csv = Text::CSV->new({ sep_char => "\t" });
2701 no warnings 'uninitialized';
2703 my %unique_accessions_seen;
2704 my %unique_plots_seen;
2705 my @new_sorted_trait_names;
2706 my %sommer_rr_genetic_coeff;
2707 open(my $fh_genetic, '<', $stats_out_tempfile_genetic)
2708 or die "Could not open file '$stats_out_tempfile_genetic' $!";
2710 print STDERR "Opened $stats_out_tempfile_genetic\n";
2711 my $header = <$fh_genetic>;
2712 my @header_cols;
2713 if ($csv->parse($header)) {
2714 @header_cols = $csv->fields();
2717 while (my $row = <$fh_genetic>) {
2718 my @columns;
2719 if ($csv->parse($row)) {
2720 @columns = $csv->fields();
2723 my $accession_id = $columns[0];
2724 my $accession_name = $stock_info{$accession_id}->{uniquename};
2725 $unique_accessions_seen{$accession_name}++;
2727 my $col_counter = 1;
2728 foreach (0..$legendre_order_number) {
2729 my $value = $columns[$col_counter];
2730 push @{$sommer_rr_genetic_coeff{$accession_name}}, $value;
2731 $col_counter++;
2734 close($fh_genetic);
2736 # print STDERR Dumper \%sommer_rr_genetic_coeff;
2738 open(my $fh_residual, '<', $stats_out_tempfile_residual)
2739 or die "Could not open file '$stats_out_tempfile_residual' $!";
2741 print STDERR "Opened $stats_out_tempfile_residual\n";
2742 my $header_residual = <$fh_residual>;
2743 my @header_cols_residual;
2744 if ($csv->parse($header_residual)) {
2745 @header_cols_residual = $csv->fields();
2748 while (my $row = <$fh_residual>) {
2749 my @columns;
2750 if ($csv->parse($row)) {
2751 @columns = $csv->fields();
2754 my $stock_id = $columns[0];
2755 my $time = $columns[1];
2756 my $residual = $columns[2];
2757 my $fitted = $columns[3];
2758 my $stock_name = $plot_id_map{$stock_id};
2759 $result_residual_data->{$stock_name}->{$seen_times{$time}} = [$residual, $timestamp, $user_name, '', ''];
2760 $result_fitted_data->{$stock_name}->{$seen_times{$time}} = [$fitted, $timestamp, $user_name, '', ''];
2762 close($fh_residual);
2764 $time_min = 100000000;
2765 $time_max = 0;
2766 foreach (@sorted_trait_names) {
2767 if ($_ < $time_min) {
2768 $time_min = $_;
2770 if ($_ > $time_max) {
2771 $time_max = $_;
2774 print STDERR Dumper [$time_min, $time_max];
2776 my $q_time = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
2777 my $h_time = $schema->storage->dbh()->prepare($q_time);
2779 my %rr_unique_traits;
2781 open(my $Fgc, ">", $coeff_genetic_tempfile) || die "Can't open file ".$coeff_genetic_tempfile;
2783 while ( my ($accession_name, $coeffs) = each %sommer_rr_genetic_coeff) {
2784 my @line = ($accession_name, @$coeffs);
2785 my $line_string = join ',', @line;
2786 print $Fgc "$line_string\n";
2788 foreach my $t_i (0..20) {
2789 my $time = $t_i*5/100;
2790 my $time_rescaled = sprintf("%.2f", $time*($time_max - $time_min) + $time_min);
2792 my $value = 0;
2793 my $coeff_counter = 0;
2794 foreach my $b (@$coeffs) {
2795 my $eval_string = $legendre_coeff_exec[$coeff_counter];
2796 # print STDERR Dumper [$eval_string, $b, $time];
2797 $value += eval $eval_string;
2798 $coeff_counter++;
2801 my $time_term_string = '';
2802 if ($statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups') {
2803 $time_term_string = "GDD $time_rescaled";
2805 elsif ($statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups') {
2806 $time_term_string = "day $time_rescaled"
2808 $h_time->execute($time_term_string, 'cxgn_time_ontology');
2809 my ($time_cvterm_id) = $h_time->fetchrow_array();
2811 if (!$time_cvterm_id) {
2812 my $new_time_term = $schema->resultset("Cv::Cvterm")->create_with({
2813 name => $time_term_string,
2814 cv => 'cxgn_time_ontology'
2816 $time_cvterm_id = $new_time_term->cvterm_id();
2818 my $time_term_string_blup = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $time_cvterm_id, 'extended');
2819 $rr_unique_traits{$time_term_string_blup}++;
2821 $result_blup_data->{$accession_name}->{$time_term_string_blup} = [$value, $timestamp, $user_name, '', ''];
2824 close($Fgc);
2826 @sorted_trait_names = sort keys %rr_unique_traits;
2828 elsif ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
2830 $statistical_ontology_term = "Multivariate linear mixed model genetic BLUPs using genetic relationship matrix and temporal Legendre polynomial random regression on days after planting computed using Sommer R|SGNSTAT:0000004"; #In the JS this is set to either the genetic of permanent environment BLUP term (Multivariate linear mixed model permanent environment BLUPs using genetic relationship matrix and temporal Legendre polynomial random regression on days after planting computed using Sommer R|SGNSTAT:0000005) when saving results
2832 $analysis_result_values_type = "analysis_result_values_match_accession_names";
2834 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups') {
2835 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_blupf90_grm_temporal_leg_random_regression_GDD_genetic_blups_phenotype_file";
2837 elsif ($statistics_select eq 'blupf90_grm_random_regression_dap_blups') {
2838 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_blupf90_grm_temporal_leg_random_regression_DAP_genetic_blups_phenotype_file";
2840 elsif ($statistics_select eq 'airemlf90_grm_random_regression_gdd_blups') {
2841 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_airemlf90_grm_temporal_leg_random_regression_GDD_genetic_blups_phenotype_file";
2843 elsif ($statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
2844 $analysis_model_training_data_file_type = "nicksmixedmodels_v1.01_airemlf90_grm_temporal_leg_random_regression_DAP_genetic_blups_phenotype_file";
2847 my $pheno_var_pos = $legendre_order_number+1;
2848 my $cmd_r = 'R -e "
2849 pheno <- read.csv(\''.$stats_prep2_tempfile.'\', header=FALSE, sep=\',\');
2850 v <- var(pheno);
2851 v <- v[1:'.$pheno_var_pos.', 1:'.$pheno_var_pos.'];
2852 #v <- matrix(rep(0.1, '.$pheno_var_pos.'*'.$pheno_var_pos.'), nrow = '.$pheno_var_pos.');
2853 #diag(v) <- rep(1, '.$pheno_var_pos.');
2854 write.table(v, file=\''.$stats_out_param_tempfile.'\', row.names=FALSE, col.names=FALSE, sep=\'\t\');
2856 print STDERR Dumper $cmd_r;
2857 my $status_r = system("$cmd_r > /dev/null");
2859 my $csv = Text::CSV->new({ sep_char => "\t" });
2861 my @pheno_var;
2862 open(my $fh_r, '<', $stats_out_param_tempfile)
2863 or die "Could not open file '$stats_out_param_tempfile' $!";
2864 print STDERR "Opened $stats_out_param_tempfile\n";
2866 while (my $row = <$fh_r>) {
2867 my @columns;
2868 if ($csv->parse($row)) {
2869 @columns = $csv->fields();
2871 push @pheno_var, \@columns;
2873 close($fh_r);
2874 # print STDERR Dumper \@pheno_var;
2876 my @grm_old;
2877 open(my $fh_grm_old, '<', $grm_file)
2878 or die "Could not open file '$grm_file' $!";
2879 print STDERR "Opened $grm_file\n";
2881 while (my $row = <$fh_grm_old>) {
2882 my @columns;
2883 if ($csv->parse($row)) {
2884 @columns = $csv->fields();
2886 push @grm_old, \@columns;
2888 close($fh_grm_old);
2890 my %grm_hash_ordered;
2891 foreach (@grm_old) {
2892 my $l1 = $accession_id_factor_map{$_->[0]};
2893 my $l2 = $accession_id_factor_map{$_->[1]};
2894 my $val = sprintf("%.8f", $_->[2]);
2895 if ($l1 < $l2) {
2896 $grm_hash_ordered{$l1}->{$l2} = $val;
2898 else {
2899 $grm_hash_ordered{$l2}->{$l1} = $val;
2903 open(my $fh_grm_new, '>', $grm_rename_tempfile)
2904 or die "Could not open file '$grm_rename_tempfile' $!";
2905 print STDERR "Opened $grm_rename_tempfile\n";
2907 foreach my $i (sort keys %grm_hash_ordered) {
2908 my $v = $grm_hash_ordered{$i};
2909 foreach my $j (sort keys %$v) {
2910 my $val = $v->{$j};
2911 print $fh_grm_new "$i $j $val\n";
2914 close($fh_grm_new);
2916 my $stats_tempfile_2_basename = basename($stats_tempfile_2);
2917 my $grm_file_basename = basename($grm_rename_tempfile);
2918 my $permanent_environment_structure_file_basename = basename($permanent_environment_structure_tempfile);
2919 #my @phenotype_header = ("id", "plot_id", "replicate", "time", "replicate_time", "ind_replicate", @sorted_trait_names, "phenotype");
2921 my $effect_1_levels = scalar(@rep_time_factors);
2922 my $effect_grm_levels = scalar(@unique_accession_names);
2923 my $effect_pe_levels = scalar(@ind_rep_factors);
2925 my @param_file_rows = (
2926 'DATAFILE',
2927 $stats_tempfile_2_basename,
2928 'NUMBER_OF_TRAITS',
2929 '1',
2930 'NUMBER_OF_EFFECTS',
2931 ($legendre_order_number + 1)*2 + 1,
2932 'OBSERVATION(S)',
2933 $legendre_order_number + 1 + 6 + 1,
2934 'WEIGHT(S)',
2936 'EFFECTS: POSITION_IN_DATAFILE NUMBER_OF_LEVELS TYPE_OF_EFFECT',
2937 '5 '.$effect_1_levels.' cross',
2939 my $p_counter = 1;
2940 foreach (0 .. $legendre_order_number) {
2941 push @param_file_rows, 6+$p_counter.' '.$effect_grm_levels.' cov 1';
2942 $p_counter++;
2944 my $p2_counter = 1;
2945 my @hetres_group;
2946 foreach (0 .. $legendre_order_number) {
2947 push @param_file_rows, 6+$p2_counter.' '.$effect_pe_levels.' cov 6';
2948 push @hetres_group, 6+$p2_counter;
2949 $p2_counter++;
2951 my @random_group1;
2952 foreach (1..$legendre_order_number+1) {
2953 push @random_group1, 1+$_;
2955 my $random_group_string1 = join ' ', @random_group1;
2956 my @random_group2;
2957 foreach (1..$legendre_order_number+1) {
2958 push @random_group2, 1+scalar(@random_group1)+$_;
2960 my $random_group_string2 = join ' ', @random_group2;
2961 my $hetres_group_string = join ' ', @hetres_group;
2962 push @param_file_rows, (
2963 'RANDOM_RESIDUAL VALUES',
2964 '1',
2965 'RANDOM_GROUP',
2966 $random_group_string1,
2967 'RANDOM_TYPE'
2969 if (!$protocol_id) {
2970 push @param_file_rows, (
2971 'diagonal',
2972 'FILE',
2976 else {
2977 push @param_file_rows, (
2978 'user_file_inv',
2979 'FILE',
2980 $grm_file_basename
2983 push @param_file_rows, (
2984 '(CO)VARIANCES'
2986 foreach (@pheno_var) {
2987 my $s = join ' ', @$_;
2988 push @param_file_rows, $s;
2990 push @param_file_rows, (
2991 'RANDOM_GROUP',
2992 $random_group_string2,
2993 'RANDOM_TYPE'
2996 if ($permanent_environment_structure eq 'identity') {
2997 push @param_file_rows, (
2998 'diagonal',
2999 'FILE',
3003 else {
3004 push @param_file_rows, (
3005 'user_file_inv',
3006 'FILE',
3007 $permanent_environment_structure_file_basename
3011 push @param_file_rows, (
3012 '(CO)VARIANCES'
3014 foreach (@pheno_var) {
3015 my $s = join ' ', @$_;
3016 push @param_file_rows, $s;
3018 my $hetres_pol_string = join ' ', @sorted_scaled_ln_times;
3019 push @param_file_rows, (
3020 'OPTION hetres_pos '.$hetres_group_string,
3021 'OPTION hetres_pol '.$hetres_pol_string,
3022 'OPTION conv_crit '.$tolparinv,
3023 'OPTION residual',
3026 open(my $Fp, ">", $parameter_tempfile) || die "Can't open file ".$parameter_tempfile;
3027 foreach (@param_file_rows) {
3028 print $Fp "$_\n";
3030 close($Fp);
3032 my $command_name = '';
3033 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups') {
3034 $command_name = 'blupf90';
3036 elsif ($statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3037 $command_name = 'airemlf90';
3040 my $parameter_tempfile_basename = basename($parameter_tempfile);
3041 $stats_out_tempfile .= '.log';
3042 my $cmd = 'cd '.$tmp_stats_dir.'; echo '.$parameter_tempfile_basename.' | '.$command_name.' > '.$stats_out_tempfile;
3043 print STDERR Dumper $cmd;
3044 my $status = system("$cmd > /dev/null");
3046 $csv = Text::CSV->new({ sep_char => "\t" });
3048 open(my $fh_log, '<', $stats_out_tempfile)
3049 or die "Could not open file '$stats_out_tempfile' $!";
3051 print STDERR "Opened $stats_out_tempfile\n";
3052 while (my $row = <$fh_log>) {
3053 print STDERR $row;
3055 close($fh_log);
3057 my $q_time = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
3058 my $h_time = $schema->storage->dbh()->prepare($q_time);
3060 my %rr_unique_traits;
3061 my %rr_residual_unique_traits;
3063 my $sum_square_res = 0;
3064 $yhat_residual_tempfile = $tmp_stats_dir."/yhat_residual";
3065 open(my $fh_yhat_res, '<', $yhat_residual_tempfile)
3066 or die "Could not open file '$yhat_residual_tempfile' $!";
3067 print STDERR "Opened $yhat_residual_tempfile\n";
3069 my $pred_res_counter = 0;
3070 my $trait_counter = 0;
3071 while (my $row = <$fh_yhat_res>) {
3072 # print STDERR $row;
3073 my @vals = split ' ', $row;
3074 my $pred = $vals[0];
3075 my $residual = $vals[1];
3076 $sum_square_res = $sum_square_res + $residual*$residual;
3078 my $plot_name = $plot_id_count_map_reverse{$pred_res_counter};
3079 my $time = $time_count_map_reverse{$pred_res_counter};
3081 $rr_residual_unique_traits{$seen_times{$time}}++;
3083 $result_residual_data->{$plot_name}->{$seen_times{$time}} = [$residual, $timestamp, $user_name, '', ''];
3084 $result_fitted_data->{$plot_name}->{$seen_times{$time}} = [$pred, $timestamp, $user_name, '', ''];
3086 $pred_res_counter++;
3088 close($fh_yhat_res);
3089 $model_sum_square_residual = $sum_square_res;
3091 my %fixed_effects;
3092 my %rr_genetic_coefficients;
3093 my %rr_temporal_coefficients;
3094 $blupf90_solutions_tempfile = $tmp_stats_dir."/solutions";
3095 open(my $fh_sol, '<', $blupf90_solutions_tempfile)
3096 or die "Could not open file '$blupf90_solutions_tempfile' $!";
3097 print STDERR "Opened $blupf90_solutions_tempfile\n";
3099 my $head = <$fh_sol>;
3100 print STDERR $head;
3102 my $solution_file_counter = 0;
3103 my $grm_sol_counter = 0;
3104 my $grm_sol_trait_counter = 0;
3105 my $pe_sol_counter = 0;
3106 my $pe_sol_trait_counter = 0;
3107 while (my $row = <$fh_sol>) {
3108 # print STDERR $row;
3109 my @vals = split ' ', $row;
3110 my $level = $vals[2];
3111 my $value = $vals[3];
3112 if ($solution_file_counter < $effect_1_levels) {
3113 $fixed_effects{$solution_file_counter}->{$level} = $value;
3115 elsif ($solution_file_counter < $effect_1_levels + $effect_grm_levels*($legendre_order_number+1)) {
3116 my $accession_name = $accession_id_factor_map_reverse{$level};
3117 # my $trait = $seen_times{$sorted_trait_names[$grm_sol_trait_counter]};
3118 if ($grm_sol_counter < $effect_grm_levels-1) {
3119 $grm_sol_counter++;
3121 else {
3122 $grm_sol_counter = 0;
3123 $grm_sol_trait_counter++;
3125 # $result_blup_data->{$accession_name}->{$trait} = [$value, $timestamp, $user_name, '', ''];
3126 push @{$rr_genetic_coefficients{$accession_name}}, $value;
3128 else {
3129 my $plot_name = $plot_id_factor_map_reverse{$level};
3130 # my $trait = $seen_times{$sorted_trait_names[$pe_sol_trait_counter]};
3131 if ($pe_sol_counter < $effect_pe_levels-1) {
3132 $pe_sol_counter++;
3134 else {
3135 $pe_sol_counter = 0;
3136 $pe_sol_trait_counter++;
3138 # $result_blup_pe_data->{$plot_name}->{$trait} = [$value, $timestamp, $user_name, '', ''];
3139 push @{$rr_temporal_coefficients{$plot_name}}, $value;
3141 $solution_file_counter++;
3143 close($fh_sol);
3145 # print STDERR Dumper \%rr_genetic_coefficients;
3146 # print STDERR Dumper \%rr_temporal_coefficients;
3148 open(my $Fgc, ">", $coeff_genetic_tempfile) || die "Can't open file ".$coeff_genetic_tempfile;
3149 print STDERR "OPENED $coeff_genetic_tempfile\n";
3151 while ( my ($accession_name, $coeffs) = each %rr_genetic_coefficients) {
3152 my @line = ($accession_name, @$coeffs);
3153 my $line_string = join ',', @line;
3154 print $Fgc "$line_string\n";
3156 foreach my $t_i (0..20) {
3157 my $time = $t_i*5/100;
3158 my $time_rescaled = sprintf("%.2f", $time*($time_max - $time_min) + $time_min);
3160 my $value = 0;
3161 my $coeff_counter = 0;
3162 foreach my $b (@$coeffs) {
3163 my $eval_string = $legendre_coeff_exec[$coeff_counter];
3164 # print STDERR Dumper [$eval_string, $b, $time];
3165 $value += eval $eval_string;
3166 $coeff_counter++;
3169 my $time_term_string = '';
3170 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups') {
3171 $time_term_string = "GDD $time_rescaled";
3173 elsif ($statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3174 $time_term_string = "day $time_rescaled"
3176 $h_time->execute($time_term_string, 'cxgn_time_ontology');
3177 my ($time_cvterm_id) = $h_time->fetchrow_array();
3179 if (!$time_cvterm_id) {
3180 my $new_time_term = $schema->resultset("Cv::Cvterm")->create_with({
3181 name => $time_term_string,
3182 cv => 'cxgn_time_ontology'
3184 $time_cvterm_id = $new_time_term->cvterm_id();
3186 my $time_term_string_blup = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $time_cvterm_id, 'extended');
3187 $rr_unique_traits{$time_term_string_blup}++;
3189 $result_blup_data->{$accession_name}->{$time_term_string_blup} = [$value, $timestamp, $user_name, '', ''];
3192 close($Fgc);
3194 while ( my ($accession_name, $coeffs) = each %rr_genetic_coefficients) {
3195 foreach my $time_term (@sorted_trait_names) {
3196 $time = ($time_term - $time_min)/($time_max - $time_min);
3197 my $value = 0;
3198 my $coeff_counter = 0;
3199 foreach my $b (@$coeffs) {
3200 my $eval_string = $legendre_coeff_exec[$coeff_counter];
3201 # print STDERR Dumper [$eval_string, $b, $time];
3202 $value += eval $eval_string;
3203 $coeff_counter++;
3206 $result_blup_data_delta->{$accession_name}->{$time_term} = [$value, $timestamp, $user_name, '', ''];
3210 open(my $Fpc, ">", $coeff_pe_tempfile) || die "Can't open file ".$coeff_pe_tempfile;
3211 print STDERR "OPENED $coeff_pe_tempfile\n";
3213 while ( my ($plot_name, $coeffs) = each %rr_temporal_coefficients) {
3214 my @line = ($plot_name, @$coeffs);
3215 my $line_string = join ',', @line;
3216 print $Fpc "$line_string\n";
3218 foreach my $t_i (0..20) {
3219 my $time = $t_i*5/100;
3220 my $time_rescaled = sprintf("%.2f", $time*($time_max - $time_min) + $time_min);
3222 my $value = 0;
3223 my $coeff_counter = 0;
3224 foreach my $b (@$coeffs) {
3225 my $eval_string = $legendre_coeff_exec[$coeff_counter];
3226 # print STDERR Dumper [$eval_string, $b, $time];
3227 $value += eval $eval_string;
3228 $coeff_counter++;
3231 my $time_term_string = '';
3232 if ($statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups') {
3233 $time_term_string = "GDD $time_rescaled";
3235 elsif ($statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3236 $time_term_string = "day $time_rescaled"
3238 $h_time->execute($time_term_string, 'cxgn_time_ontology');
3239 my ($time_cvterm_id) = $h_time->fetchrow_array();
3241 if (!$time_cvterm_id) {
3242 my $new_time_term = $schema->resultset("Cv::Cvterm")->create_with({
3243 name => $time_term_string,
3244 cv => 'cxgn_time_ontology'
3246 $time_cvterm_id = $new_time_term->cvterm_id();
3248 my $time_term_string_pe = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $time_cvterm_id, 'extended');
3249 $rr_unique_traits{$time_term_string_pe}++;
3251 $result_blup_pe_data->{$plot_name}->{$time_term_string_pe} = [$value, $timestamp, $user_name, '', ''];
3254 close($Fpc);
3256 while ( my ($plot_name, $coeffs) = each %rr_temporal_coefficients) {
3257 foreach my $time_term (@sorted_trait_names) {
3258 my $time = ($time_term - $time_min)/($time_max - $time_min);
3259 my $value = 0;
3260 my $coeff_counter = 0;
3261 foreach my $b (@$coeffs) {
3262 my $eval_string = $legendre_coeff_exec[$coeff_counter];
3263 # print STDERR Dumper [$eval_string, $b, $time];
3264 $value += eval $eval_string;
3265 $coeff_counter++;
3268 $result_blup_pe_data_delta->{$plot_name}->{$time_term} = [$value, $timestamp, $user_name, '', ''];
3272 # print STDERR Dumper \%fixed_effects;
3273 # print STDERR Dumper $result_blup_data;
3274 # print STDERR Dumper $result_blup_pe_data;
3275 @sorted_trait_names = sort keys %rr_unique_traits;
3276 @sorted_residual_trait_names = sort keys %rr_residual_unique_traits;
3279 elsif ($statistics_select eq 'marss_germplasmname_block') {
3281 my $dbh = $c->dbc->dbh();
3282 my $bs = CXGN::BreederSearch->new( { dbh=>$dbh } );
3283 my $status = $bs->test_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass});
3284 if ($status->{'error'}) {
3285 $c->stash->{rest} = { error => $status->{'error'}};
3286 return;
3288 my $results_ref = $bs->metadata_query(['trials', 'accessions'], {'accessions' => {'trials' => $field_trial_id_list_string}}, {'accessions' => {'trials'=>1}});
3289 my %unique_accession_ids;
3290 foreach (@{$results_ref->{results}}) {
3291 $unique_accession_ids{$_->[0]}++;
3293 my @unique_accession_ids = keys %unique_accession_ids;
3294 if (scalar(@unique_accession_ids) == 0) {
3295 $c->stash->{rest} = { error => "There are no common accessions in the trials you have selected! If that is the case, please just select one at a time."};
3296 return;
3298 print STDERR scalar(@unique_accession_ids)." Common Accessions\n";
3300 my $marss_prediction_selection = $c->req->param('statistics_select_marss_options');
3302 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
3303 'MaterializedViewTable',
3305 bcs_schema=>$schema,
3306 data_level=>'plot',
3307 trait_list=>$trait_id_list,
3308 trial_list=>$field_trial_id_list,
3309 accession_list=>\@unique_accession_ids,
3310 include_timestamp=>0,
3311 exclude_phenotype_outlier=>0
3314 my ($data, $unique_traits) = $phenotypes_search->search();
3315 my @sorted_trait_names = sort keys %$unique_traits;
3317 if (scalar(@$data) == 0) {
3318 $c->stash->{rest} = { error => "There are no phenotypes for the trials and traits you have selected!"};
3319 return;
3322 my %germplasm_name_encoder;
3323 my $germplasm_name_encoded = 1;
3324 my %trait_name_encoder;
3325 my $trait_name_encoded = 1;
3326 my %phenotype_data;
3327 my %seen_gdd_times;
3328 my %seen_germplasm_names;
3329 foreach my $obs_unit (@$data){
3330 my $germplasm_name = $obs_unit->{germplasm_uniquename};
3331 my $observations = $obs_unit->{observations};
3332 if (!exists($germplasm_name_encoder{$germplasm_name})) {
3333 $germplasm_name_encoder{$germplasm_name} = $germplasm_name_encoded;
3334 $germplasm_name_encoded++;
3336 foreach (@$observations){
3337 my $related_time_terms_json = decode_json $_->{associated_image_project_time_json};
3338 my $gdd_time = $related_time_terms_json->{gdd_average_temp} + 0;
3339 $phenotype_data{$obs_unit->{observationunit_uniquename}}->{$gdd_time} = $_->{value};
3340 $seen_gdd_times{$gdd_time}++;
3342 $seen_germplasm_names{$germplasm_name} = $obs_unit->{germplasm_stock_id};
3344 my @sorted_gdd_time_points = sort {$a <=> $b} keys %seen_gdd_times;
3346 my %data_matrix;
3347 my %germplasm_pheno_hash;
3348 foreach (@$data) {
3349 my $germplasm_name = $_->{germplasm_uniquename};
3350 my $obsunit_name = $_->{observationunit_uniquename};
3351 $germplasm_pheno_hash{$germplasm_name}->{obsunit_rep} = $_->{obsunit_rep};
3352 $germplasm_pheno_hash{$germplasm_name}->{obsunit_block} = $_->{obsunit_block};
3353 $germplasm_pheno_hash{$germplasm_name}->{germplasm_encoded} = $germplasm_name_encoder{$germplasm_name};
3354 foreach my $t (@sorted_gdd_time_points) {
3355 if (defined($phenotype_data{$obsunit_name}->{$t})) {
3356 $germplasm_pheno_hash{$germplasm_name}->{$t} = $phenotype_data{$obsunit_name}->{$t} + 0;
3357 } else {
3358 print STDERR "Using NA for ".$obsunit_name." : $t : $germplasm_name : \n";
3362 foreach my $g (keys %seen_germplasm_names) {
3363 my @row = ($germplasm_pheno_hash{$g}->{obsunit_rep}, $germplasm_pheno_hash{$g}->{obsunit_block}, $germplasm_pheno_hash{$g}->{germplasm_encoded});
3364 foreach my $t (@sorted_gdd_time_points) {
3365 push @row, $germplasm_pheno_hash{$g}->{$t};
3367 push @{$data_matrix{$g}}, @row;
3370 my @phenotype_header = ("replicate", "block", "germplasmName");
3371 my $num_col_before_traits = scalar(@phenotype_header);
3372 foreach (@sorted_gdd_time_points) {
3373 push @phenotype_header, "$_";
3376 print STDERR Dumper \%data_matrix;
3377 print STDERR Dumper \@phenotype_header;
3379 foreach (keys %seen_germplasm_names) {
3380 my $germplasm_stock_id = $seen_germplasm_names{$_};
3381 my $dir = $c->tempfiles_subdir('/drone_imagery_analysis_plot');
3382 my $temp_plot = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_analysis_plot/imageXXXX');
3383 $temp_plot .= '.jpg';
3385 my $germplasm_data = $data_matrix{$_};
3386 my $num_rows = scalar(@$germplasm_data)/scalar(@phenotype_header);
3387 my $rmatrix = R::YapRI::Data::Matrix->new({
3388 name => 'matrix1',
3389 coln => scalar(@phenotype_header),
3390 rown => $num_rows,
3391 colnames => \@phenotype_header,
3392 data => $germplasm_data
3395 my $rbase = R::YapRI::Base->new();
3396 my $r_block = $rbase->create_block('r_block');
3397 $rmatrix->send_rbase($rbase, 'r_block');
3398 $r_block->add_command('library(MARSS)');
3399 $r_block->add_command('library(ggplot2)');
3400 $r_block->add_command('header <- colnames(matrix1)');
3401 $r_block->add_command('gdd_times <- header[-c(1:'.$num_col_before_traits.')]');
3402 $r_block->add_command('matrix_transposed <- t(matrix1)');
3403 $r_block->add_command('result_matrix <- matrix(NA,nrow = 3*'.$num_rows.', ncol = length(matrix_transposed[ ,1]))');
3404 $r_block->add_command('jpeg("'.$temp_plot.'")');
3406 my $row_number = 1;
3407 foreach my $t (1..$num_rows) {
3408 $r_block->add_command('row'.$t.' <- matrix_transposed[ , '.$t.']');
3409 $r_block->add_command('replicate'.$t.' <- row'.$t.'[1]');
3410 $r_block->add_command('block'.$t.' <- row'.$t.'[2]');
3411 $r_block->add_command('germplasmName'.$t.' <- row'.$t.'[3]');
3412 $r_block->add_command('time_series'.$t.' <- row'.$t.'[-c(1:'.$num_col_before_traits.')]');
3413 $r_block->add_command('for (i in range(1:length(time_series'.$t.'))) { if (time_series'.$t.'[i] == "NA") { time_series'.$t.'[i] <- NA } }');
3414 $r_block->add_command('time_series_original'.$t.' <- time_series'.$t.'');
3415 if ($marss_prediction_selection eq 'marss_predict_last_two_time_points') {
3416 $r_block->add_command('time_series'.$t.'[c(length(time_series'.$t.')-1, length(time_series'.$t.') )] <- NA');
3418 elsif ($marss_prediction_selection eq 'marss_predict_last_time_point') {
3419 $r_block->add_command('time_series'.$t.'[length(time_series'.$t.')] <- NA');
3421 else {
3422 die "MARSS predict option not selected\n";
3424 #$r_block->add_command('mars_model'.$t.' <- list(B=matrix("phi"), U=matrix(0), Q=matrix("sig.sq.w"), Z=matrix("a"), A=matrix(0), R=matrix("sig.sq.v"), x0=matrix("mu"), tinitx=0 )');
3425 $r_block->add_command('mars_model'.$t.' <- list(B="unconstrained", U="zero", Q="unconstrained", Z="identity", A="zero", R="diagonal and unequal", tinitx=1 )');
3426 $r_block->add_command('mars_fit'.$t.' <- MARSS(time_series'.$t.', model=mars_model'.$t.', method="kem")');
3427 $r_block->add_command('minimum_y_val'.$t.' <- min( c( min(as.numeric(time_series_original'.$t.'), na.rm=T), min(as.numeric(mars_fit'.$t.'$ytT)), na.rm=T) , na.rm=T)');
3428 $r_block->add_command('maximum_y_val'.$t.' <- max( c( max(as.numeric(time_series_original'.$t.'), na.rm=T), max(as.numeric(mars_fit'.$t.'$ytT)), na.rm=T) , na.rm=T)');
3429 $r_block->add_command('maximum_y_std'.$t.' <- max( mars_fit'.$t.'$ytT.se, na.rm=T)');
3430 $r_block->add_command('result_matrix['.$row_number.',] <- c(replicate'.$t.', block'.$t.', germplasmName'.$t.', time_series_original'.$t.')');
3431 $row_number++;
3432 $r_block->add_command('result_matrix['.$row_number.',] <- c(replicate'.$t.', block'.$t.', germplasmName'.$t.', mars_fit'.$t.'$ytT)');
3433 $row_number++;
3434 $r_block->add_command('result_matrix['.$row_number.',] <- c(replicate'.$t.', block'.$t.', germplasmName'.$t.', mars_fit'.$t.'$ytT.se)');
3435 $row_number++;
3437 if ($t == 1) {
3438 $r_block->add_command('plot(gdd_times, time_series_original'.$t.', type="b", col="gray", main="State Space '.$_.'", xlab="Growing Degree Days", ylab="Phenotype", ylim = c(minimum_y_val'.$t.'-maximum_y_std'.$t.'-0.05*maximum_y_val'.$t.', maximum_y_val'.$t.'+maximum_y_std'.$t.'+0.05*maximum_y_val'.$t.') )');
3440 else {
3441 $r_block->add_command('lines(gdd_times, time_series_original'.$t.', type="b", col="gray")');
3443 $r_block->add_command('points(gdd_times[which(is.na(time_series'.$t.'))], mars_fit'.$t.'$ytT[which(is.na(time_series'.$t.'))], col="blue", lty=2)');
3444 $r_block->add_command('points(gdd_times[which(is.na(time_series'.$t.'))], c(mars_fit'.$t.'$ytT + qnorm(0.975)*mars_fit'.$t.'$ytT.se)[which(is.na(time_series'.$t.'))], col="red", lty=2)');
3445 $r_block->add_command('points(gdd_times[which(is.na(time_series'.$t.'))], c(mars_fit'.$t.'$ytT - qnorm(0.975)*mars_fit'.$t.'$ytT.se)[which(is.na(time_series'.$t.'))], col="red", lty=2)');
3446 # $r_block->add_command('legend("topleft", col=c("blue", "gray", "red"), legend = c("Predicted", "Observed", "SE"), lty=1 )');
3448 $r_block->add_command('dev.off()');
3449 $r_block->run_block();
3450 my $result_matrix = R::YapRI::Data::Matrix->read_rbase($rbase,'r_block','result_matrix');
3451 #print STDERR Dumper $result_matrix;
3453 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
3454 my $md5checksum = $image->calculate_md5sum($temp_plot);
3455 my $q = "SELECT md_image.image_id
3456 FROM metadata.md_image AS md_image
3457 JOIN phenome.stock_image AS stock_image USING(image_id)
3458 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND stock_image.stock_id = ?;";
3459 my $h = $schema->storage->dbh->prepare($q);
3460 $h->execute($md5checksum, $germplasm_stock_id);
3461 my ($saved_image_id) = $h->fetchrow_array();
3463 my $plot_image_fullpath;
3464 my $plot_image_url;
3465 my $plot_image_id;
3466 if ($saved_image_id) {
3467 print STDERR Dumper "Image $temp_plot has already been added to the database and will not be added again.";
3468 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
3469 $plot_image_fullpath = $image->get_filename('original_converted', 'full');
3470 $plot_image_url = $image->get_image_url('original');
3471 $plot_image_id = $image->get_image_id();
3472 } else {
3473 $image->set_sp_person_id($user_id);
3474 my $ret = $image->process_image($temp_plot, 'stock', $germplasm_stock_id);
3475 $plot_image_fullpath = $image->get_filename('original_converted', 'full');
3476 $plot_image_url = $image->get_image_url('original');
3477 $plot_image_id = $image->get_image_id();
3480 push @results, ["TimeSeries", $result_matrix, $plot_image_url];
3483 else {
3484 $c->stash->{rest} = { error => "Not supported $statistics_select!"};
3485 return;
3488 my $genetic_effects_figure_tempfile_string;
3489 if ($statistics_select eq 'sommer_grm_genetic_blups' || $statistics_select eq 'sommer_grm_spatial_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3490 my ($effects_original_line_chart_tempfile_fh, $effects_original_line_chart_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
3491 open(my $F_pheno, ">", $effects_original_line_chart_tempfile) || die "Can't open file ".$effects_original_line_chart_tempfile;
3492 print $F_pheno "germplasmName,time,value\n";
3493 foreach my $p (@unique_accession_names) {
3494 foreach my $t (@sorted_trait_names_original) {
3495 my @row;
3496 if ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_genetic_only_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3497 my $val = $result_blup_data_delta->{$p}->{$t}->[0];
3498 @row = ($p, $t, $val);
3500 elsif ($statistics_select eq 'sommer_grm_genetic_blups' || $statistics_select eq 'sommer_grm_spatial_genetic_blups') {
3501 my $val = $result_blup_data->{$p}->{$t}->[0];
3502 @row = ($p, $trait_to_time_map{$t}, $val);
3504 my $line = join ',', @row;
3505 print $F_pheno "$line\n";
3508 close($F_pheno);
3510 my @set = ('0' ..'9', 'A' .. 'F');
3511 my @colors;
3512 for (1..scalar(@unique_accession_names)) {
3513 my $str = join '' => map $set[rand @set], 1 .. 6;
3514 push @colors, '#'.$str;
3516 my $color_string = join '\',\'', @colors;
3518 $genetic_effects_figure_tempfile_string = $c->tempfile( TEMPLATE => 'tmp_drone_statistics/figureXXXX');
3519 $genetic_effects_figure_tempfile_string .= '.png';
3520 my $genetic_effects_figure_tempfile = $c->config->{basepath}."/".$genetic_effects_figure_tempfile_string;
3522 my $cmd_gen_plot = 'R -e "library(data.table); library(ggplot2);
3523 mat <- fread(\''.$effects_original_line_chart_tempfile.'\', header=TRUE, sep=\',\');
3524 mat\$time <- as.numeric(as.character(mat\$time));
3525 options(device=\'png\');
3526 par();
3527 sp <- ggplot(mat, aes(x = time, y = value)) +
3528 geom_line(aes(color = germplasmName), size = 1) +
3529 scale_fill_manual(values = c(\''.$color_string.'\')) +
3530 theme_minimal();
3531 sp <- sp + guides(shape = guide_legend(override.aes = list(size = 0.5)));
3532 sp <- sp + guides(color = guide_legend(override.aes = list(size = 0.5)));
3533 sp <- sp + theme(legend.title = element_text(size = 3), legend.text = element_text(size = 3));';
3534 if (scalar(@unique_accession_names) > 100) {
3535 $cmd_gen_plot .= 'sp <- sp + theme(legend.position = \'none\');';
3537 $cmd_gen_plot .= 'ggsave(\''.$genetic_effects_figure_tempfile.'\', sp, device=\'png\', width=12, height=6, units=\'in\');
3538 dev.off();"';
3539 my $status_gen_plot = system("$cmd_gen_plot > /dev/null");
3542 my $env_effects_figure_tempfile_string;
3543 if ($statistics_select eq 'sommer_grm_spatial_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3544 my ($phenotypes_original_heatmap_tempfile_fh, $phenotypes_original_heatmap_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
3545 open(my $F_pheno, ">", $phenotypes_original_heatmap_tempfile) || die "Can't open file ".$phenotypes_original_heatmap_tempfile;
3546 print $F_pheno "trait_type,row,col,value\n";
3547 foreach my $p (@unique_plot_names) {
3548 foreach my $t (@sorted_trait_names_original) {
3549 if ($statistics_select eq 'sommer_grm_spatial_genetic_blups') {
3550 my @row = ("phenotype_".$trait_name_encoder{$t}, $stock_name_row_col{$p}->{row_number}, $stock_name_row_col{$p}->{col_number}, $phenotype_data{$p}->{$t});
3551 my $line = join ',', @row;
3552 print $F_pheno "$line\n";
3554 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3555 my @row = ("phenotype_dap".$t, $stock_name_row_col{$p}->{row_number}, $stock_name_row_col{$p}->{col_number}, $phenotype_data{$p}->{$t});
3556 my $line = join ',', @row;
3557 print $F_pheno "$line\n";
3561 close($F_pheno);
3563 my ($effects_heatmap_tempfile_fh, $effects_heatmap_tempfile) = tempfile("drone_stats_XXXXX", DIR=> $tmp_stats_dir);
3564 open(my $F_eff, ">", $effects_heatmap_tempfile) || die "Can't open file ".$effects_heatmap_tempfile;
3565 print $F_eff "trait_type,row,col,value\n";
3566 foreach my $p (@unique_plot_names) {
3567 foreach my $t (@sorted_trait_names_original) {
3568 if ($statistics_select eq 'sommer_grm_spatial_genetic_blups') {
3569 my @row = ("effect_".$trait_name_encoder{$t}, $stock_name_row_col{$p}->{row_number}, $stock_name_row_col{$p}->{col_number}, $result_blup_spatial_data->{$p}->{$t}->[0]);
3570 my $line = join ',', @row;
3571 print $F_eff "$line\n";
3573 elsif ($statistics_select eq 'sommer_grm_temporal_random_regression_dap_genetic_blups' || $statistics_select eq 'sommer_grm_temporal_random_regression_gdd_genetic_blups' || $statistics_select eq 'blupf90_grm_random_regression_gdd_blups' || $statistics_select eq 'blupf90_grm_random_regression_dap_blups' || $statistics_select eq 'airemlf90_grm_random_regression_gdd_blups' || $statistics_select eq 'airemlf90_grm_random_regression_dap_blups') {
3574 my @row = ("effect_".$t, $stock_name_row_col{$p}->{row_number}, $stock_name_row_col{$p}->{col_number}, $result_blup_pe_data_delta->{$p}->{$t}->[0]);
3575 my $line = join ',', @row;
3576 print $F_eff "$line\n";
3580 close($F_eff);
3582 $env_effects_figure_tempfile_string = $c->tempfile( TEMPLATE => 'tmp_drone_statistics/figureXXXX');
3583 $env_effects_figure_tempfile_string .= '.png';
3584 my $env_effects_figure_tempfile = $c->config->{basepath}."/".$env_effects_figure_tempfile_string;
3586 my $output_plot_row = 'row';
3587 my $output_plot_col = 'col';
3588 if ($max_col > $max_row) {
3589 $output_plot_row = 'col';
3590 $output_plot_col = 'row';
3593 my $cmd_spatialfirst_plot = 'R -e "library(data.table); library(ggplot2); library(dplyr); library(viridis); library(GGally); library(gridExtra);
3594 mat_pheno <- fread(\''.$phenotypes_original_heatmap_tempfile.'\', header=TRUE, sep=\',\');
3595 mat_eff <- fread(\''.$effects_heatmap_tempfile.'\', header=TRUE, sep=\',\');
3596 options(device=\'png\');
3597 par();
3598 gg <- ggplot(mat_pheno, aes('.$output_plot_col.', '.$output_plot_row.', fill=value)) +
3599 geom_tile() +
3600 scale_fill_viridis(discrete=FALSE) +
3601 coord_equal() +
3602 facet_wrap(~trait_type, ncol='.scalar(@sorted_trait_names).');
3603 gg_eff <- ggplot(mat_eff, aes('.$output_plot_col.', '.$output_plot_row.', fill=value)) +
3604 geom_tile() +
3605 scale_fill_viridis(discrete=FALSE) +
3606 coord_equal() +
3607 facet_wrap(~trait_type, ncol='.scalar(@sorted_trait_names).');
3608 ggsave(\''.$env_effects_figure_tempfile.'\', arrangeGrob(gg, gg_eff, nrow=2), device=\'png\', width=20, height=20, units=\'in\');
3610 # print STDERR Dumper $cmd;
3611 my $status_spatialfirst_plot = system("$cmd_spatialfirst_plot > /dev/null");
3614 $c->stash->{rest} = {
3615 results => \@results,
3616 result_blup_genetic_data => $result_blup_data,
3617 result_blup_spatial_data => $result_blup_spatial_data,
3618 result_blup_pe_data => $result_blup_pe_data,
3619 result_residual_data => $result_residual_data,
3620 result_fitted_data => $result_fitted_data,
3621 unique_traits => \@sorted_trait_names,
3622 unique_residual_traits => \@sorted_residual_trait_names,
3623 unique_accessions => \@unique_accession_names,
3624 unique_plots => \@unique_plot_names,
3625 statistics_select => $statistics_select,
3626 grm_file => $grm_file,
3627 stats_tempfile => $stats_tempfile,
3628 blupf90_grm_file => $grm_rename_tempfile,
3629 blupf90_param_file => $parameter_tempfile,
3630 blupf90_training_file => $stats_tempfile_2,
3631 blupf90_permanent_environment_structure_file => $permanent_environment_structure_tempfile,
3632 yhat_residual_tempfile => $yhat_residual_tempfile,
3633 rr_genetic_coefficients => $coeff_genetic_tempfile,
3634 rr_pe_coefficients => $coeff_pe_tempfile,
3635 blupf90_solutions => $blupf90_solutions_tempfile,
3636 stats_out_tempfile => $stats_out_tempfile,
3637 stats_out_tempfile_string => $stats_out_tempfile_string,
3638 stats_out_htp_rel_tempfile_out_string => $stats_out_htp_rel_tempfile_out_string,
3639 stats_out_tempfile_col => $stats_out_tempfile_col,
3640 stats_out_tempfile_row => $stats_out_tempfile_row,
3641 statistical_ontology_term => $statistical_ontology_term,
3642 analysis_result_values_type => $analysis_result_values_type,
3643 analysis_model_type => $statistics_select,
3644 analysis_model_language => $analysis_model_language,
3645 application_name => "NickMorales Mixed Models",
3646 application_version => "V1.01",
3647 analysis_model_training_data_file_type => $analysis_model_training_data_file_type,
3648 field_trial_design => $field_trial_design,
3649 sum_square_residual => $model_sum_square_residual,
3650 trait_composing_info => \%trait_composing_info,
3651 genetic_effects_line_plot => $genetic_effects_figure_tempfile_string,
3652 env_effects_heatmap_plot => $env_effects_figure_tempfile_string
3656 sub _drone_imagery_interactive_get_gps {
3657 my $c = shift;
3658 my $schema = shift;
3659 my $drone_run_project_id = shift;
3660 my $flight_pass_counter = shift;
3662 my $saved_image_stacks_rotated_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks_rotated', 'project_property')->cvterm_id();
3663 my $saved_micasense_stacks_rotated_json = $schema->resultset("Project::Projectprop")->find({
3664 project_id => $drone_run_project_id,
3665 type_id => $saved_image_stacks_rotated_type_id
3667 my $saved_micasense_stacks_rotated_full_separated;
3668 my $saved_micasense_stacks_rotated_full;
3669 my $saved_micasense_stacks_rotated;
3670 if ($saved_micasense_stacks_rotated_json) {
3671 $saved_micasense_stacks_rotated_full = decode_json $saved_micasense_stacks_rotated_json->value();
3672 $saved_micasense_stacks_rotated_full_separated = $saved_micasense_stacks_rotated_full;
3673 $saved_micasense_stacks_rotated = $saved_micasense_stacks_rotated_full->{$flight_pass_counter};
3675 # print STDERR Dumper $saved_micasense_stacks_rotated_full;
3676 # print STDERR Dumper $saved_micasense_stacks_rotated;
3678 my $saved_image_stacks_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks_separated', 'project_property')->cvterm_id();
3679 my $saved_micasense_stacks_json = $schema->resultset("Project::Projectprop")->find({
3680 project_id => $drone_run_project_id,
3681 type_id => $saved_image_stacks_type_id
3683 my $saved_micasense_stacks_full_separated;
3684 my $saved_micasense_stacks_full;
3685 my $saved_micasense_stacks;
3686 if ($saved_micasense_stacks_json) {
3687 $saved_micasense_stacks_full = decode_json $saved_micasense_stacks_json->value();
3688 $saved_micasense_stacks_full_separated = $saved_micasense_stacks_full;
3689 $saved_micasense_stacks = $saved_micasense_stacks_full->{$flight_pass_counter};
3691 # print STDERR Dumper $saved_micasense_stacks;
3693 my $is_rotated;
3694 if ($saved_micasense_stacks_rotated) {
3695 $saved_micasense_stacks_full = $saved_micasense_stacks_rotated_full;
3696 $saved_micasense_stacks = $saved_micasense_stacks_rotated;
3697 $is_rotated = 1;
3699 my @saved_micasense_stacks_values = values %$saved_micasense_stacks;
3701 my $max_flight_pass_counter = keys %$saved_micasense_stacks_full_separated;
3703 my $all_passes_rotated;
3704 my $all_passes_rotated_one_missing;
3705 for (1 .. $max_flight_pass_counter) {
3706 if (!$saved_micasense_stacks_rotated_full_separated->{$_}) {
3707 $all_passes_rotated_one_missing = 1;
3710 if (!$all_passes_rotated_one_missing) {
3711 $all_passes_rotated = 1;
3714 my $saved_gps_positions_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_gps_pixel_positions', 'project_property')->cvterm_id();
3715 my $saved_gps_positions_json = $schema->resultset("Project::Projectprop")->find({
3716 project_id => $drone_run_project_id,
3717 type_id => $saved_gps_positions_type_id
3719 my $saved_gps_positions;
3720 if ($saved_gps_positions_json) {
3721 $saved_gps_positions = decode_json $saved_gps_positions_json->value();
3722 $saved_gps_positions = $saved_gps_positions->{$flight_pass_counter};
3725 my $first_image = SGN::Image->new( $schema->storage->dbh, $saved_micasense_stacks_values[0]->[3]->{image_id}, $c );
3726 my $first_image_url = $first_image->get_image_url('original_converted');
3727 my $first_image_fullpath = $first_image->get_filename('original_converted', 'full');
3728 my @size = imgsize($first_image_fullpath);
3729 my $width = $size[0];
3730 my $length = $size[1];
3732 my %gps_images;
3733 my %gps_images_rounded;
3734 my %longitudes;
3735 my %longitudes_rounded;
3736 my %latitudes;
3737 my %latitudes_rounded;
3738 my $max_longitude = -1000000;
3739 my $min_longitude = 1000000;
3740 my $max_latitude = -1000000;
3741 my $min_latitude = 1000000;
3742 my %latitude_rounded_map;
3743 my %longitude_rounded_map;
3745 # print STDERR Dumper $saved_micasense_stacks;
3747 foreach (sort {$a <=> $b} keys %$saved_micasense_stacks) {
3748 my $image_ids_array = $saved_micasense_stacks->{$_};
3749 my $nir_image = $image_ids_array->[3];
3750 my $latitude_raw = $nir_image->{latitude};
3751 my $longitude_raw = $nir_image->{longitude};
3753 if ($latitude_raw > $max_latitude) {
3754 $max_latitude = $latitude_raw;
3756 if ($longitude_raw > $max_longitude) {
3757 $max_longitude = $longitude_raw;
3759 if ($latitude_raw < $min_latitude) {
3760 $min_latitude = $latitude_raw;
3762 if ($longitude_raw < $min_longitude) {
3763 $min_longitude = $longitude_raw;
3766 my $latitude_rounded = nearest(0.0001,$latitude_raw);
3767 my $longitude_rounded = nearest(0.0001,$longitude_raw);
3769 $longitudes{$longitude_raw}++;
3770 $longitudes_rounded{$longitude_rounded}++;
3771 $latitudes{$latitude_raw}++;
3772 $latitudes_rounded{$latitude_rounded}++;
3774 $latitude_rounded_map{$latitude_raw} = $latitude_rounded;
3775 $longitude_rounded_map{$longitude_raw} = $longitude_rounded;
3777 my @rotated_stack_image_ids;
3778 foreach (@$image_ids_array) {
3779 push @rotated_stack_image_ids, $_->{rotated_image_id};
3782 my $nir_image_id = $nir_image->{image_id};
3784 my $image = SGN::Image->new( $schema->storage->dbh, $nir_image_id, $c );
3785 my $image_url = $image->get_image_url('original_converted');
3786 my $image_fullpath = $image->get_filename('original_converted', 'full');
3788 $gps_images{$latitude_raw}->{$longitude_raw} = {
3789 nir_image_id => $nir_image_id,
3790 d3_rotate_angle => $nir_image->{d3_rotate_angle},
3791 rotated_bound => $nir_image->{rotated_bound},
3792 rotated_bound_translated => $nir_image->{rotated_bound_translated},
3793 rotated_image_ids => \@rotated_stack_image_ids,
3794 image_url => $image_url,
3795 image_size => [$width, $length],
3796 altitude => $nir_image->{altitude},
3797 x_pos => $nir_image->{x_pos},
3798 y_pos => $nir_image->{y_pos},
3799 latitude => $latitude_raw,
3800 longitude => $longitude_raw
3803 push @{$gps_images_rounded{$latitude_rounded}->{$longitude_rounded}}, {
3804 nir_image_id => $nir_image_id,
3805 d3_rotate_angle => $nir_image->{d3_rotate_angle},
3806 rotated_bound => $nir_image->{rotated_bound},
3807 rotated_bound_translated => $nir_image->{rotated_bound_translated},
3808 rotated_image_ids => \@rotated_stack_image_ids,
3809 image_url => $image_url,
3810 image_size => [$width, $length],
3811 altitude => $nir_image->{altitude},
3812 x_pos => $nir_image->{x_pos},
3813 y_pos => $nir_image->{y_pos},
3814 latitude => $latitude_raw,
3815 longitude => $longitude_raw
3818 # print STDERR Dumper \%longitudes;
3819 # print STDERR Dumper \%latitudes;
3821 my %latitude_rounded_map_ordinal;
3822 my %longitude_rounded_map_ordinal;
3823 my @latitudes_sorted = sort {$a <=> $b} keys %latitudes;
3824 my @latitudes_rounded_sorted = sort {$a <=> $b} keys %latitudes_rounded;
3825 my @longitudes_sorted = sort {$a <=> $b} keys %longitudes;
3826 my @longitudes_rounded_sorted = sort {$a <=> $b} keys %longitudes_rounded;
3828 my $lat_index = 1;
3829 foreach (@latitudes_rounded_sorted) {
3830 $latitude_rounded_map_ordinal{$_} = $lat_index;
3831 $lat_index++;
3833 my $long_index = 1;
3834 foreach (@longitudes_rounded_sorted) {
3835 $longitude_rounded_map_ordinal{$_} = $long_index;
3836 $long_index++;
3839 while (my($latitude_raw, $latitude_rounded) = each %latitude_rounded_map) {
3840 $latitude_rounded_map{$latitude_raw} = $latitude_rounded_map_ordinal{$latitude_rounded};
3842 while (my($longitude_raw, $longitude_rounded) = each %longitude_rounded_map) {
3843 $longitude_rounded_map{$longitude_raw} = $longitude_rounded_map_ordinal{$longitude_rounded};
3846 my $min_x_val = 100000000;
3847 my $min_y_val = 100000000;
3848 my $max_x_val = 0;
3849 my $max_y_val = 0;
3850 my $x_range = 0;
3851 my $y_range = 0;
3852 my $no_x_pos = 1;
3853 if ($saved_gps_positions) {
3854 while (my ($l, $lo) = each %$saved_gps_positions) {
3855 foreach my $v (values %$lo) {
3856 if ($v->{x_pos} && $v->{y_pos}) {
3857 $no_x_pos = 0;
3858 my $x_val = $v->{x_pos};
3859 my $y_val = $v->{y_pos};
3860 if ($x_val < $min_x_val) {
3861 $min_x_val = $x_val;
3863 if ($y_val < $min_y_val) {
3864 $min_y_val = $y_val;
3866 if ($x_val > $max_x_val) {
3867 $max_x_val = $x_val;
3869 if ($y_val > $max_y_val) {
3870 $max_y_val = $y_val;
3875 if ($no_x_pos == 0) {
3876 $x_range = $max_x_val - $min_x_val + $width;
3877 $y_range = $max_y_val - $min_y_val + $length;
3881 my $x_factor = 10000000;
3882 my $y_factor = 16000000;
3883 if ($x_range != 0) {
3884 $x_range = $x_range + 1.2*$width;
3885 } else {
3886 $x_range = ($max_longitude - $min_longitude)*100*$x_factor + 1.2*$width;
3888 if ($y_range != 0) {
3889 $y_range = $y_range + 1.2*$length;
3890 } else {
3891 $y_range = ($max_latitude - $min_latitude)*3*$y_factor + 1.2*$length;
3894 return {
3895 success => 1,
3896 longitudes => \@longitudes_sorted,
3897 longitudes_rounded => \@longitudes_rounded_sorted,
3898 longitude_rounded_map => \%longitude_rounded_map,
3899 latitudes => \@latitudes_sorted,
3900 latitudes_rounded => \@latitudes_rounded_sorted,
3901 latitude_rounded_map => \%latitude_rounded_map,
3902 saved_micasense_stacks => $saved_micasense_stacks,
3903 saved_micasense_stacks_full => $saved_micasense_stacks_full,
3904 saved_micasense_stacks_rotated_full_separated => $saved_micasense_stacks_rotated_full_separated,
3905 gps_images => \%gps_images,
3906 gps_images_rounded => \%gps_images_rounded,
3907 saved_gps_positions => $saved_gps_positions,
3908 image_width => $width,
3909 image_length => $length,
3910 min_latitude => $min_latitude,
3911 min_longitude => $min_longitude,
3912 max_latitude => $max_latitude,
3913 max_longitude => $max_longitude,
3914 x_range => $x_range,
3915 y_range => $y_range,
3916 x_factor => $x_factor,
3917 y_factor => $y_factor,
3918 is_rotated => $is_rotated,
3919 all_passes_rotated => $all_passes_rotated,
3920 max_flight_pass_counter => $max_flight_pass_counter
3924 sub drone_imagery_separate_gps : Path('/api/drone_imagery/separate_drone_imagery_gps') : ActionClass('REST') { }
3925 sub drone_imagery_separate_gps_GET : Args(0) {
3926 my $self = shift;
3927 my $c = shift;
3928 print STDERR Dumper $c->req->params();
3929 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
3930 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
3931 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
3932 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
3933 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
3934 my $drone_run_project_id = $c->req->param("drone_run_project_id");
3936 my $saved_image_stacks_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks', 'project_property')->cvterm_id();
3937 my $saved_image_stacks_separated_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks_separated', 'project_property')->cvterm_id();
3939 my $saved_micasense_stacks_json = $schema->resultset("Project::Projectprop")->find({
3940 project_id => $drone_run_project_id,
3941 type_id => $saved_image_stacks_type_id
3943 my $saved_micasense_stacks;
3944 if ($saved_micasense_stacks_json) {
3945 $saved_micasense_stacks = decode_json $saved_micasense_stacks_json->value();
3948 my $saved_separated_micasense_stacks_json = $schema->resultset("Project::Projectprop")->find({
3949 project_id => $drone_run_project_id,
3950 type_id => $saved_image_stacks_separated_type_id
3952 my $saved_micasense_stacks_separated;
3953 if ($saved_separated_micasense_stacks_json) {
3954 $saved_micasense_stacks_separated = decode_json $saved_separated_micasense_stacks_json->value();
3957 # print STDERR Dumper $saved_micasense_stacks;
3958 my %pass_micasense_stacks;
3959 if (!$saved_micasense_stacks_separated) {
3961 my $check_change_lat = abs($saved_micasense_stacks->{2}->[3]->{latitude} - $saved_micasense_stacks->{0}->[3]->{latitude});
3962 my $check_change_long = abs($saved_micasense_stacks->{2}->[3]->{longitude} - $saved_micasense_stacks->{0}->[3]->{longitude});
3963 my $flight_dir = "latitude";
3964 if ($check_change_long > $check_change_lat) {
3965 $flight_dir = "longitude";
3967 my $flight_dir_sign = 1;
3968 if ($saved_micasense_stacks->{0}->[3]->{$flight_dir} - $saved_micasense_stacks->{1}->[3]->{$flight_dir} < 0) {
3969 $flight_dir_sign = -1;
3972 my $flight_pass_counter = 1;
3973 foreach (sort {$a <=> $b} keys %$saved_micasense_stacks) {
3974 my $image_ids_array = $saved_micasense_stacks->{$_};
3975 my $nir_image = $image_ids_array->[3];
3976 my $latitude_raw = $nir_image->{latitude};
3977 my $longitude_raw = $nir_image->{longitude};
3979 my $flight_dir_pos1 = $saved_micasense_stacks->{$_}->[3]->{$flight_dir};
3980 my $flight_dir_pos2 = $saved_micasense_stacks->{$_+1}->[3]->{$flight_dir};
3981 if ($flight_dir_pos2) {
3982 my $flight_dir_sign_check = 1;
3983 if ($flight_dir_pos1 - $flight_dir_pos2 < 0) {
3984 $flight_dir_sign_check = -1;
3987 if ($flight_dir_sign_check != $flight_dir_sign) {
3988 $flight_pass_counter++;
3989 $flight_dir_sign = $flight_dir_sign_check;
3992 $pass_micasense_stacks{$flight_pass_counter}->{$_} = $image_ids_array;
3995 my $saved_micasense_stacks_separated_json = $schema->resultset('Project::Projectprop')->update_or_create({
3996 type_id=>$saved_image_stacks_separated_type_id,
3997 project_id=>$drone_run_project_id,
3998 rank=>0,
3999 value=>encode_json \%pass_micasense_stacks
4002 key=>'projectprop_c1'
4005 else {
4006 %pass_micasense_stacks = %$saved_micasense_stacks_separated;
4009 my @results;
4010 foreach my $flight_pass_counter (sort keys %pass_micasense_stacks) {
4011 push @results, [$flight_pass_counter, scalar(keys %{$pass_micasense_stacks{$flight_pass_counter}})];
4014 $c->stash->{rest} = { success => 1, results => \@results, pass_micasense_stacks => \%pass_micasense_stacks };
4017 sub drone_imagery_get_gps : Path('/api/drone_imagery/get_drone_imagery_gps') : ActionClass('REST') { }
4018 sub drone_imagery_get_gps_GET : Args(0) {
4019 my $self = shift;
4020 my $c = shift;
4021 print STDERR Dumper $c->req->params();
4022 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4023 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4024 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
4025 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
4026 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
4027 my $drone_run_project_id = $c->req->param("drone_run_project_id");
4028 my $flight_pass_counter = $c->req->param("flight_pass_counter");
4030 my $return = _drone_imagery_interactive_get_gps($c, $schema, $drone_run_project_id, $flight_pass_counter);
4032 $c->stash->{rest} = $return;
4035 sub drone_imagery_check_gps_images_rotation : Path('/api/drone_imagery/check_gps_images_rotation') : ActionClass('REST') { }
4036 sub drone_imagery_check_gps_images_rotation_POST : Args(0) {
4037 my $self = shift;
4038 my $c = shift;
4039 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4040 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4041 my $drone_run_project_id = $c->req->param("drone_run_project_id");
4042 my ($user_id, $user_name, $user_role) = _check_user_login($c);
4044 my $drone_run_rotate_process_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_rotation_occuring', 'project_property')->cvterm_id();
4045 my $drone_run_rotate_process = $schema->resultset('Project::Projectprop')->find({
4046 type_id=>$drone_run_rotate_process_type_id,
4047 project_id=>$drone_run_project_id,
4050 $c->stash->{rest} = {is_rotating => $drone_run_rotate_process->value};
4053 sub drone_imagery_update_gps_images_rotation : Path('/api/drone_imagery/update_gps_images_rotation') : ActionClass('REST') { }
4054 sub drone_imagery_update_gps_images_rotation_POST : Args(0) {
4055 my $self = shift;
4056 my $c = shift;
4057 print STDERR Dumper $c->req->params();
4058 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4059 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4060 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
4061 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
4062 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
4063 my $drone_run_project_id = $c->req->param("drone_run_project_id");
4064 my $rotate_angle = $c->req->param("rotate_angle");
4065 my $rotate_angle_neg = $rotate_angle*-1;
4066 my $nir_image_ids = decode_json $c->req->param("nir_image_ids");
4067 my $flight_pass_counter = $c->req->param("flight_pass_counter");
4069 my $rotate_radians = $rotate_angle * 0.0174533;
4070 my ($user_id, $user_name, $user_role) = _check_user_login($c);
4072 my $return = _drone_imagery_interactive_get_gps($c, $schema, $drone_run_project_id, $flight_pass_counter);
4073 my $is_rotated = $return->{is_rotated};
4074 my $max_flight_pass_counter = $return->{max_flight_pass_counter};
4076 my %rotated_saved_micasense_stacks_full;
4077 if ($is_rotated) {
4078 %rotated_saved_micasense_stacks_full = %{$return->{saved_micasense_stacks_full}};
4079 print STDERR "ALREADY ROTATED\n";
4080 } else {
4082 my $drone_run_rotate_process_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_rotation_occuring', 'project_property')->cvterm_id();
4083 my $drone_run_rotate_process = $schema->resultset('Project::Projectprop')->update_or_create({
4084 type_id=>$drone_run_rotate_process_type_id,
4085 project_id=>$drone_run_project_id,
4086 rank=>0,
4087 value=>1
4090 key=>'projectprop_c1'
4093 my %rotated_saved_micasense_stacks;
4094 my $saved_micasense_stacks = $return->{saved_micasense_stacks};
4095 # my $saved_micasense_stacks_full = $return->{saved_micasense_stacks_rotated_full_separated};
4097 foreach my $stack_key (sort {$a <=> $b} keys %$saved_micasense_stacks) {
4098 if (!$saved_micasense_stacks->{$stack_key}->[0]) {
4099 delete $saved_micasense_stacks->{$stack_key};
4100 print STDERR "REMOVING KEY $stack_key\n";
4104 # print STDERR Dumper $saved_micasense_stacks;
4105 my @saved_micasense_stacks_values = values %$saved_micasense_stacks;
4107 my $first_image = SGN::Image->new( $schema->storage->dbh, $saved_micasense_stacks_values[0]->[3]->{image_id}, $c );
4108 my $first_image_url = $first_image->get_image_url('original_converted');
4109 my $first_image_fullpath = $first_image->get_filename('original_converted', 'full');
4110 my @size = imgsize($first_image_fullpath);
4111 my $width = $size[0];
4112 my $length = $size[1];
4113 my $cx = $width/2;
4114 my $cy = $length/2;
4116 my $number_system_cores = `getconf _NPROCESSORS_ONLN` or die "Could not get number of system cores!\n";
4117 chomp($number_system_cores);
4118 print STDERR "NUMCORES $number_system_cores\n";
4120 my %gps_images;
4121 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
4122 my $bulk_input_temp_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/bulkinputXXXX');
4124 open(my $F, ">", $bulk_input_temp_file) || die "Can't open file ".$bulk_input_temp_file;
4126 my %input_bulk_hash;
4127 foreach my $stack_key (sort {$a <=> $b} keys %$saved_micasense_stacks) {
4128 my $image_ids_array = $saved_micasense_stacks->{$stack_key};
4130 my $index_counter = 0;
4131 foreach my $i (@$image_ids_array) {
4133 my $latitude_raw = $i->{latitude};
4134 my $longitude_raw = $i->{longitude};
4135 my $altitude_raw = $i->{altitude};
4136 my $image_id = $i->{image_id};
4138 if ($image_id) {
4139 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
4140 $archive_rotate_temp_image .= '.png';
4142 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
4143 my $image_fullpath = $image->get_filename('original_converted', 'full');
4145 print $F "$image_fullpath\t$archive_rotate_temp_image\t$rotate_angle_neg\n";
4147 $input_bulk_hash{$image_id} = {
4148 stack_key => $stack_key,
4149 latitude_raw => $latitude_raw,
4150 longitude_raw => $longitude_raw,
4151 altitude_raw => $altitude_raw,
4152 rotated_temp_image => $archive_rotate_temp_image,
4153 index_counter => $index_counter
4156 $index_counter++;
4159 close($F);
4161 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/RotateBulk.py --input_path \''.$bulk_input_temp_file.'\'';
4162 print STDERR Dumper $cmd;
4163 my $status = system("$cmd > /dev/null");
4165 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'rotated_stitched_temporary_drone_imagery', 'project_md_image')->cvterm_id();
4166 while ( my ($image_id, $i_obj) = each %input_bulk_hash) {
4167 my $stack_key = $i_obj->{stack_key};
4168 my $latitude_raw = $i_obj->{latitude_raw};
4169 my $longitude_raw = $i_obj->{longitude_raw};
4170 my $altitude_raw = $i_obj->{altitude_raw};
4171 my $index_counter = $i_obj->{index_counter};
4172 my $archive_rotate_temp_image = $i_obj->{rotated_temp_image};
4174 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
4175 my $md5checksum = $image->calculate_md5sum($archive_rotate_temp_image);
4176 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
4177 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
4178 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
4179 my $h = $schema->storage->dbh->prepare($q);
4180 $h->execute($md5checksum, $linking_table_type_id, $drone_run_project_id);
4181 my ($saved_image_id) = $h->fetchrow_array();
4183 my $rotated_image_fullpath;
4184 my $rotated_image_id;
4185 my $rotated_image_url;
4186 if ($saved_image_id) {
4187 print STDERR Dumper "Image $archive_rotate_temp_image has already been added to the database and will not be added again.";
4188 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
4189 $rotated_image_fullpath = $image->get_filename('original_converted', 'full');
4190 $rotated_image_url = $image->get_image_url('original');
4191 $rotated_image_id = $image->get_image_id();
4192 } else {
4193 $image->set_sp_person_id($user_id);
4194 my $ret = $image->process_image($archive_rotate_temp_image, 'project', $drone_run_project_id, $linking_table_type_id);
4195 $rotated_image_fullpath = $image->get_filename('original_converted', 'full');
4196 $rotated_image_url = $image->get_image_url('original');
4197 $rotated_image_id = $image->get_image_id();
4200 my $temp_x1 = 0 - $cx;
4201 my $temp_y1 = $length - $cy;
4202 my $temp_x2 = $width - $cx;
4203 my $temp_y2 = $length - $cy;
4204 my $temp_x3 = $width - $cx;
4205 my $temp_y3 = 0 - $cy;
4206 my $temp_x4 = 0 - $cx;
4207 my $temp_y4 = 0 - $cy;
4209 my $rotated_x1 = $temp_x1*cos($rotate_radians) - $temp_y1*sin($rotate_radians);
4210 my $rotated_y1 = $temp_x1*sin($rotate_radians) + $temp_y1*cos($rotate_radians);
4211 my $rotated_x2 = $temp_x2*cos($rotate_radians) - $temp_y2*sin($rotate_radians);
4212 my $rotated_y2 = $temp_x2*sin($rotate_radians) + $temp_y2*cos($rotate_radians);
4213 my $rotated_x3 = $temp_x3*cos($rotate_radians) - $temp_y3*sin($rotate_radians);
4214 my $rotated_y3 = $temp_x3*sin($rotate_radians) + $temp_y3*cos($rotate_radians);
4215 my $rotated_x4 = $temp_x4*cos($rotate_radians) - $temp_y4*sin($rotate_radians);
4216 my $rotated_y4 = $temp_x4*sin($rotate_radians) + $temp_y4*cos($rotate_radians);
4218 $rotated_x1 = $rotated_x1 + $cx;
4219 $rotated_y1 = $rotated_y1 + $cy;
4220 $rotated_x2 = $rotated_x2 + $cx;
4221 $rotated_y2 = $rotated_y2 + $cy;
4222 $rotated_x3 = $rotated_x3 + $cx;
4223 $rotated_y3 = $rotated_y3 + $cy;
4224 $rotated_x4 = $rotated_x4 + $cx;
4225 $rotated_y4 = $rotated_y4 + $cy;
4227 my $x_pos = ($longitude_raw - $return->{min_longitude})*$return->{x_factor};
4228 my $y_pos = $return->{y_range} - ($latitude_raw - $return->{min_latitude})*$return->{y_factor} - $return->{image_length};
4230 my $rotated_bound = [[$rotated_x1, $rotated_y1], [$rotated_x2, $rotated_y2], [$rotated_x3, $rotated_y3], [$rotated_x4, $rotated_y4]];
4231 my $rotated_bound_translated = [[$rotated_x1 + $x_pos, $rotated_y1 + $y_pos], [$rotated_x2 + $x_pos, $rotated_y2 + $y_pos], [$rotated_x3 + $x_pos, $rotated_y3 + $y_pos], [$rotated_x4 + $x_pos, $rotated_y4 + $y_pos]];
4233 $rotated_saved_micasense_stacks{$stack_key}->[$index_counter] = {
4234 rotated_image_id => $rotated_image_id,
4235 d3_rotate_angle => $rotate_angle,
4236 image_id => $image_id,
4237 longitude => $longitude_raw,
4238 latitude => $latitude_raw,
4239 altitude => $altitude_raw,
4240 rotated_bound => $rotated_bound,
4241 rotated_bound_translated => $rotated_bound_translated,
4242 x_pos => $x_pos,
4243 y_pos => $y_pos
4247 # print STDERR Dumper \%rotated_saved_micasense_stacks;
4249 my $saved_image_stacks_rotated_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks_rotated', 'project_property')->cvterm_id();
4250 my $saved_micasense_stacks_rotated_json = $schema->resultset("Project::Projectprop")->find({
4251 project_id => $drone_run_project_id,
4252 type_id => $saved_image_stacks_rotated_type_id
4254 my $saved_micasense_stacks_full;
4255 if ($saved_micasense_stacks_rotated_json) {
4256 $saved_micasense_stacks_full = decode_json $saved_micasense_stacks_rotated_json->value();
4259 $saved_micasense_stacks_full->{$flight_pass_counter} = \%rotated_saved_micasense_stacks;
4260 %rotated_saved_micasense_stacks_full = %$saved_micasense_stacks_full;
4262 my $drone_run_band_rotate_angle = $schema->resultset('Project::Projectprop')->update_or_create({
4263 type_id=>$saved_image_stacks_rotated_type_id,
4264 project_id=>$drone_run_project_id,
4265 rank=>0,
4266 value=>encode_json \%rotated_saved_micasense_stacks_full
4269 key=>'projectprop_c1'
4272 my $return = _perform_match_raw_images_sequential($c, $schema, $metadata_schema, $phenome_schema, $people_schema, $drone_run_project_id, $nir_image_ids, $flight_pass_counter, $user_id, $user_name, $user_role);
4273 my $saved_gps_positions_full = $return->{saved_gps_positions_full};
4274 my $message = $return->{message};
4277 # my $saved_gps_positions_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_gps_pixel_positions', 'project_property')->cvterm_id();
4278 # my $saved_gps_positions_json = $schema->resultset("Project::Projectprop")->find({
4279 # project_id => $drone_run_project_id,
4280 # type_id => $saved_gps_positions_type_id
4281 # });
4282 # if ($saved_gps_positions_json) {
4283 # $saved_gps_positions_json->delete();
4286 $c->stash->{rest} = {
4287 success => 1,
4288 gps_images => \%rotated_saved_micasense_stacks_full
4292 sub drone_imagery_match_and_align_two_images : Path('/api/drone_imagery/match_and_align_two_images') : ActionClass('REST') { }
4293 sub drone_imagery_match_and_align_two_images_POST : Args(0) {
4294 my $self = shift;
4295 my $c = shift;
4296 print STDERR Dumper $c->req->params();
4297 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4298 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4299 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
4300 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
4301 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
4302 my ($user_id, $user_name, $user_role) = _check_user_login($c);
4304 my $drone_run_project_id = $c->req->param('drone_run_project_id');
4305 my $image_id1 = $c->req->param('image_id1');
4306 my $image_id2 = $c->req->param('image_id2');
4308 my $image1 = SGN::Image->new( $schema->storage->dbh, $image_id1, $c );
4309 my $image1_url = $image1->get_image_url("original");
4310 my $image1_fullpath = $image1->get_filename('original_converted', 'full');
4311 my $image2 = SGN::Image->new( $schema->storage->dbh, $image_id2, $c );
4312 my $image2_url = $image2->get_image_url("original");
4313 my $image2_fullpath = $image2->get_filename('original_converted', 'full');
4315 my $dir = $c->tempfiles_subdir('/drone_imagery_align');
4316 my $rotated_temp_image1 = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4317 my $rotated_temp_image2 = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4318 my $match_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4319 my $align_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4320 my $align_match_temp_results = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX');
4321 my $align_match_temp_results_2 = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX');
4323 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/MatchAndAlignImages.py --image_path1 \''.$image1_fullpath.'\' --image_path2 \''.$image2_fullpath.'\' --outfile_match_path \''.$match_temp_image.'\' --outfile_path \''.$align_temp_image.'\' --results_outfile_path_src \''.$align_match_temp_results.'\' --results_outfile_path_dst \''.$align_match_temp_results_2.'\' ';
4324 print STDERR Dumper $cmd;
4325 my $status = system("$cmd > /dev/null");
4327 my @match_points_src;
4328 my $csv = Text::CSV->new({ sep_char => ',' });
4329 open(my $fh, '<', $align_match_temp_results)
4330 or die "Could not open file '$align_match_temp_results' $!";
4332 while ( my $row = <$fh> ){
4333 my @columns;
4334 if ($csv->parse($row)) {
4335 @columns = $csv->fields();
4337 push @match_points_src, \@columns;
4339 close($fh);
4341 my @match_points_dst;
4342 open(my $fh2, '<', $align_match_temp_results_2)
4343 or die "Could not open file '$align_match_temp_results_2' $!";
4345 while ( my $row = <$fh2> ){
4346 my @columns;
4347 if ($csv->parse($row)) {
4348 @columns = $csv->fields();
4350 push @match_points_dst, \@columns;
4352 close($fh2);
4354 my $match_linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'standard_process_interactive_match_temporary_drone_imagery', 'project_md_image')->cvterm_id();
4355 my $align_linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'standard_process_interactive_align_temporary_drone_imagery', 'project_md_image')->cvterm_id();
4357 my $match_image = SGN::Image->new( $schema->storage->dbh, undef, $c );
4358 $match_image->set_sp_person_id($user_id);
4359 my $ret = $match_image->process_image($match_temp_image, 'project', $drone_run_project_id, $match_linking_table_type_id);
4360 my $match_image_fullpath = $match_image->get_filename('original_converted', 'full');
4361 my $match_image_url = $match_image->get_image_url('original');
4362 my $match_image_id = $match_image->get_image_id();
4364 # my $align_image = SGN::Image->new( $schema->storage->dbh, undef, $c );
4365 # $align_image->set_sp_person_id($user_id);
4366 # my $ret_align = $align_image->process_image($align_temp_image, 'project', $drone_run_project_id, $align_linking_table_type_id);
4367 # my $align_image_fullpath = $align_image->get_filename('original_converted', 'full');
4368 # my $align_image_url = $align_image->get_image_url('original');
4369 # my $align_image_id = $align_image->get_image_id();
4371 $c->stash->{rest} = {
4372 success => 1,
4373 match_image_url => $match_image_url,
4374 # align_image_url => $align_image_url,
4375 # align_image_id => $align_image_id,
4376 match_points_src => \@match_points_src,
4377 match_points_dst => \@match_points_dst,
4378 image_id_src => $image_id1,
4379 image_id_dst => $image_id2,
4383 sub _drone_imagery_match_and_align_images {
4384 my $c = shift;
4385 my $schema = shift;
4386 my $image_id1 = shift;
4387 my $image_id2 = shift;
4388 my $gps_obj_src = shift;
4389 my $gps_obj_dst = shift;
4390 my $max_features = shift;
4391 my $rotate_radians = shift;
4392 my $total_image_count = shift;
4393 my $image_counter = shift;
4394 my $skipped_counter = shift;
4396 my $image1 = SGN::Image->new( $schema->storage->dbh, $image_id1, $c );
4397 my $image1_url = $image1->get_image_url("original");
4398 my $image1_fullpath = $image1->get_filename('original_converted', 'full');
4399 my $image2 = SGN::Image->new( $schema->storage->dbh, $image_id2, $c );
4400 my $image2_url = $image2->get_image_url("original");
4401 my $image2_fullpath = $image2->get_filename('original_converted', 'full');
4403 my $rotated_temp_image1 = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4404 my $rotated_temp_image2 = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4405 my $match_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4406 my $align_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX').'.png';
4407 my $align_match_temp_results = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX');
4408 my $align_match_temp_results_2 = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_align/imageXXXX');
4410 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/MatchAndAlignImages.py --image_path1 \''.$image1_fullpath.'\' --image_path2 \''.$image2_fullpath.'\' --outfile_match_path \''.$match_temp_image.'\' --outfile_path \''.$align_temp_image.'\' --results_outfile_path_src \''.$align_match_temp_results.'\' --results_outfile_path_dst \''.$align_match_temp_results_2.'\' --max_features \''.$max_features.'\'';
4411 # print STDERR Dumper $cmd;
4412 my $status = system("$cmd > /dev/null");
4414 my @match_points_src;
4415 my $csv = Text::CSV->new({ sep_char => ',' });
4416 open(my $fh, '<', $align_match_temp_results)
4417 or die "Could not open file '$align_match_temp_results' $!";
4419 while ( my $row = <$fh> ){
4420 my @columns;
4421 if ($csv->parse($row)) {
4422 @columns = $csv->fields();
4424 push @match_points_src, \@columns;
4426 close($fh);
4428 my @match_points_dst;
4429 open(my $fh2, '<', $align_match_temp_results_2)
4430 or die "Could not open file '$align_match_temp_results_2' $!";
4432 while ( my $row = <$fh2> ){
4433 my @columns;
4434 if ($csv->parse($row)) {
4435 @columns = $csv->fields();
4437 push @match_points_dst, \@columns;
4439 close($fh2);
4441 # my $match_image = SGN::Image->new( $schema->storage->dbh, undef, $c );
4442 # $match_image->set_sp_person_id($user_id);
4443 # my $ret = $match_image->process_image($match_temp_image, 'project', $drone_run_project_id, $match_linking_table_type_id);
4444 # my $match_image_fullpath = $match_image->get_filename('original_converted', 'full');
4445 # my $match_image_url = $match_image->get_image_url('original');
4446 # my $match_image_id = $match_image->get_image_id();
4447 # $nir_image_hash{$image_id1}->{match_image_url} = $match_image_url;
4449 my $x_pos_src = $gps_obj_src->{x_pos};
4450 my $y_pos_src = $gps_obj_src->{y_pos};
4451 my $x_pos_dst = $gps_obj_dst->{x_pos};
4452 my $y_pos_dst = $gps_obj_dst->{y_pos};
4454 my $src_match = $match_points_src[0];
4455 my $src_match_x = $src_match->[0];
4456 my $src_match_y = $src_match->[1];
4457 my $src_match_x_rotated = $src_match_x*cos($rotate_radians) - $src_match_y*sin($rotate_radians);
4458 my $src_match_y_rotated = $src_match_x*sin($rotate_radians) + $src_match_y*cos($rotate_radians);
4459 my $x_pos_match_src = $x_pos_src + $src_match_x_rotated;
4460 my $y_pos_match_src = $y_pos_src + $src_match_y_rotated;
4462 my $src_match2 = $match_points_src[1];
4463 my $src_match2_x = $src_match2->[0];
4464 my $src_match2_y = $src_match2->[1];
4465 my $src_match2_x_rotated = $src_match2_x*cos($rotate_radians) - $src_match2_y*sin($rotate_radians);
4466 my $src_match2_y_rotated = $src_match2_x*sin($rotate_radians) + $src_match2_y*cos($rotate_radians);
4467 my $x_pos_match2_src = $x_pos_src + $src_match2_x_rotated;
4468 my $y_pos_match2_src = $y_pos_src + $src_match2_y_rotated;
4470 my $src_match3 = $match_points_src[2];
4471 my $src_match3_x = $src_match3->[0];
4472 my $src_match3_y = $src_match3->[1];
4473 my $src_match3_x_rotated = $src_match3_x*cos($rotate_radians) - $src_match3_y*sin($rotate_radians);
4474 my $src_match3_y_rotated = $src_match3_x*sin($rotate_radians) + $src_match3_y*cos($rotate_radians);
4475 my $x_pos_match3_src = $x_pos_src + $src_match3_x_rotated;
4476 my $y_pos_match3_src = $y_pos_src + $src_match3_y_rotated;
4478 my $dst_match = $match_points_dst[0];
4479 my $dst_match_x = $dst_match->[0];
4480 my $dst_match_y = $dst_match->[1];
4481 my $dst_match_x_rotated = $dst_match_x*cos($rotate_radians) - $dst_match_y*sin($rotate_radians);
4482 my $dst_match_y_rotated = $dst_match_x*sin($rotate_radians) + $dst_match_y*cos($rotate_radians);
4483 my $x_pos_match_dst = $x_pos_match_src - $dst_match_x_rotated;
4484 my $y_pos_match_dst = $y_pos_match_src - $dst_match_y_rotated;
4486 my $dst_match2 = $match_points_dst[1];
4487 my $dst_match2_x = $dst_match2->[0];
4488 my $dst_match2_y = $dst_match2->[1];
4489 my $dst_match2_x_rotated = $dst_match2_x*cos($rotate_radians) - $dst_match2_y*sin($rotate_radians);
4490 my $dst_match2_y_rotated = $dst_match2_x*sin($rotate_radians) + $dst_match2_y*cos($rotate_radians);
4491 my $x_pos_match2_dst = $x_pos_match2_src - $dst_match2_x_rotated;
4492 my $y_pos_match2_dst = $y_pos_match2_src - $dst_match2_y_rotated;
4494 my $dst_match3 = $match_points_dst[2];
4495 my $dst_match3_x = $dst_match3->[0];
4496 my $dst_match3_y = $dst_match3->[1];
4497 my $dst_match3_x_rotated = $dst_match3_x*cos($rotate_radians) - $dst_match3_y*sin($rotate_radians);
4498 my $dst_match3_y_rotated = $dst_match3_x*sin($rotate_radians) + $dst_match3_y*cos($rotate_radians);
4499 my $x_pos_match3_dst = $x_pos_match3_src - $dst_match3_x_rotated;
4500 my $y_pos_match3_dst = $y_pos_match3_src - $dst_match3_y_rotated;
4502 my $x_pos_translation = $x_pos_dst - $x_pos_match_dst;
4503 my $y_pos_translation = $y_pos_dst - $y_pos_match_dst;
4505 my $x_pos_translation2 = $x_pos_dst - $x_pos_match2_dst;
4506 my $y_pos_translation2 = $y_pos_dst - $y_pos_match2_dst;
4508 my $x_pos_translation3 = $x_pos_dst - $x_pos_match3_dst;
4509 my $y_pos_translation3 = $y_pos_dst - $y_pos_match3_dst;
4511 my $diffx1 = $x_pos_translation - $x_pos_translation2;
4512 my $diffy1 = $y_pos_translation - $y_pos_translation2;
4514 my $diffx2 = $x_pos_translation - $x_pos_translation3;
4515 my $diffy2 = $y_pos_translation - $y_pos_translation3;
4517 my $diffx3 = $x_pos_translation3 - $x_pos_translation2;
4518 my $diffy3 = $y_pos_translation3 - $y_pos_translation2;
4520 my $p1_diff_sum = abs($diffx1) + abs($diffy1) + abs($diffx2) + abs($diffy2);
4521 my $p2_diff_sum = abs($diffx1) + abs($diffy1) + abs($diffx3) + abs($diffy3);
4522 my $p3_diff_sum = abs($diffx2) + abs($diffy2) + abs($diffx3) + abs($diffy3);
4523 print STDERR "P1: ".$p1_diff_sum." P2: ".$p2_diff_sum." P3: ".$p3_diff_sum."\n";
4524 my $total_image_count_adjusted = $total_image_count-2;
4525 print STDERR "Progress: $image_id1 $image_id2 : $image_counter / $total_image_count_adjusted (".$image_counter/$total_image_count_adjusted.") : $skipped_counter\n";
4527 my $smallest_diff;
4528 if ($p1_diff_sum <= $p2_diff_sum && $p1_diff_sum <= $p3_diff_sum) {
4529 $smallest_diff = $p1_diff_sum;
4530 $x_pos_match_dst = $x_pos_match_dst;
4531 $y_pos_match_dst = $y_pos_match_dst;
4532 $x_pos_match_src = $x_pos_match_src;
4533 $y_pos_match_src = $y_pos_match_src;
4534 $x_pos_translation = $x_pos_translation;
4535 $y_pos_translation = $y_pos_translation;
4537 elsif ($p2_diff_sum <= $p1_diff_sum && $p2_diff_sum <= $p3_diff_sum) {
4538 $smallest_diff = $p2_diff_sum;
4539 $x_pos_match_dst = $x_pos_match2_dst;
4540 $y_pos_match_dst = $y_pos_match2_dst;
4541 $x_pos_match_src = $x_pos_match2_src;
4542 $y_pos_match_src = $y_pos_match2_src;
4543 $x_pos_translation = $x_pos_translation2;
4544 $y_pos_translation = $y_pos_translation2;
4546 elsif ($p3_diff_sum <= $p1_diff_sum && $p3_diff_sum <= $p2_diff_sum) {
4547 $smallest_diff = $p3_diff_sum;
4548 $x_pos_match_dst = $x_pos_match3_dst;
4549 $y_pos_match_dst = $y_pos_match3_dst;
4550 $x_pos_match_src = $x_pos_match3_src;
4551 $y_pos_match_src = $y_pos_match3_src;
4552 $x_pos_translation = $x_pos_translation3;
4553 $y_pos_translation = $y_pos_translation3;
4555 return {
4556 smallest_diff => $smallest_diff,
4557 x_pos_match_dst => $x_pos_match_dst,
4558 y_pos_match_dst => $y_pos_match_dst,
4559 x_pos_match_src => $x_pos_match_src,
4560 y_pos_match_src => $y_pos_match_src,
4561 x_pos_translation => $x_pos_translation,
4562 y_pos_translation => $y_pos_translation,
4563 match_temp_image => $match_temp_image,
4564 align_temp_image => $align_temp_image
4568 sub _perform_match_raw_images_sequential {
4569 my $c = shift;
4570 my $schema = shift;
4571 my $metadata_schema = shift;
4572 my $phenome_schema = shift;
4573 my $people_schema = shift;
4574 my $drone_run_project_id = shift;
4575 my $nir_image_ids = shift;
4576 my $flight_pass_counter = shift;
4577 my $user_id = shift;
4578 my $user_name = shift;
4579 my $user_role = shift;
4581 my $dir = $c->tempfiles_subdir('/drone_imagery_align');
4583 my $match_linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'standard_process_interactive_match_temporary_drone_imagery', 'project_md_image')->cvterm_id();
4584 my $align_linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'standard_process_interactive_align_temporary_drone_imagery', 'project_md_image')->cvterm_id();
4586 my $return = _drone_imagery_interactive_get_gps($c, $schema, $drone_run_project_id, $flight_pass_counter);
4587 my $gps_images = $return->{gps_images};
4588 my $gps_images_rounded = $return->{gps_images_rounded};
4589 my $saved_gps_positions = $return->{saved_gps_positions};
4590 my $longitudes = $return->{longitudes};
4591 my $latitudes = $return->{latitudes};
4592 my $width = $return->{image_width};
4593 my $length = $return->{image_length};
4594 my $max_flight_pass_counter = $return->{max_flight_pass_counter};
4596 my $longitudes_rounded = $return->{longitudes_rounded};
4597 my $longitude_rounded_map = $return->{longitude_rounded_map};
4598 my $latitudes_rounded = $return->{latitudes_rounded};
4599 my $latitude_rounded_map = $return->{latitude_rounded_map};
4601 # if ($saved_gps_positions && scalar (keys %$saved_gps_positions) > 0) {
4602 # $gps_images = $saved_gps_positions;
4605 my %nir_image_hash;
4606 foreach my $lat (@$latitudes) {
4607 foreach my $long (@$longitudes) {
4608 if ($lat && $long) {
4609 my $i = $gps_images->{$lat}->{$long};
4610 my $nir_image_id = $i->{nir_image_id};
4611 if ($nir_image_id) {
4612 $nir_image_hash{$nir_image_id} = $i;
4618 my $image_counter = 0;
4620 my $image_id1 = $nir_image_ids->[$image_counter];
4621 my $image_id2 = $nir_image_ids->[$image_counter+1];
4623 my $total_image_count = scalar(@$nir_image_ids);
4624 my $skipped_counter = 0;
4625 my $max_features = 1000;
4627 my $message = "Completed matching";
4629 while ($image_id1 && $image_id2) {
4631 my $gps_obj_src = $nir_image_hash{$image_id1};
4632 my $gps_obj_dst = $nir_image_hash{$image_id2};
4634 if ($gps_obj_src->{match_src_to} || $gps_obj_dst->{match_dst_to} || $gps_obj_dst->{match_problem} || $gps_obj_dst->{manual_match}) {
4635 $image_counter++;
4636 $image_id1 = $nir_image_ids->[$image_counter];
4637 $image_id2 = $nir_image_ids->[$image_counter+1];
4638 next;
4641 my $latitude_src = $gps_obj_src->{latitude};
4642 my $longitude_src = $gps_obj_src->{longitude};
4643 my $latitude_dst = $gps_obj_dst->{latitude};
4644 my $longitude_dst = $gps_obj_dst->{longitude};
4646 my $rotate_radians = $nir_image_hash{$image_id2}->{d3_rotate_angle} * 0.0174533;
4648 my $latitude_ordinal_src = $latitude_rounded_map->{$latitude_src};
4649 my $longitude_ordinal_src = $longitude_rounded_map->{$longitude_src};
4650 my $latitude_rounded_src = $latitudes_rounded->[$latitude_ordinal_src-1];
4651 my $longitude_rounded_src = $longitudes_rounded->[$longitude_ordinal_src-1];
4653 my $latitude_ordinal_dst = $latitude_rounded_map->{$latitude_dst};
4654 my $longitude_ordinal_dst = $longitude_rounded_map->{$longitude_dst};
4655 my $latitude_rounded_dst = $latitudes_rounded->[$latitude_ordinal_dst-1];
4656 my $longitude_rounded_dst = $longitudes_rounded->[$longitude_ordinal_dst-1];
4658 my $gps_obj_src_lat_up_objects;
4659 if ($latitudes_rounded->[$latitude_ordinal_src-1+1]) {
4660 $gps_obj_src_lat_up_objects = $gps_images_rounded->{$latitudes_rounded->[$latitude_ordinal_src-1+1]}->{$longitude_rounded_src};
4662 my $gps_obj_src_lat_down_objects;
4663 if ($latitudes_rounded->[$latitude_ordinal_src-1-1]) {
4664 $gps_obj_src_lat_down_objects = $gps_images_rounded->{$latitudes_rounded->[$latitude_ordinal_src-1-1]}->{$longitude_rounded_src};
4666 my $gps_obj_src_long_up_objects;
4667 if ($longitudes_rounded->[$longitude_ordinal_src-1+1]) {
4668 $gps_obj_src_long_up_objects = $gps_images_rounded->{$latitude_rounded_src}->{$longitudes_rounded->[$longitude_ordinal_src-1+1]};
4670 my $gps_obj_src_long_down_objects;
4671 if ($longitudes_rounded->[$longitude_ordinal_src-1-1]) {
4672 $gps_obj_src_long_down_objects = $gps_images_rounded->{$latitude_rounded_src}->{$longitudes_rounded->[$longitude_ordinal_src-1-1]};
4675 my $match = _drone_imagery_match_and_align_images($c, $schema, $image_id1, $image_id2, $gps_obj_src, $gps_obj_dst, $max_features, $rotate_radians, $total_image_count, $image_counter, $skipped_counter);
4676 my $smallest_diff = $match->{smallest_diff};
4677 my $x_pos_match_dst = $match->{x_pos_match_dst};
4678 my $y_pos_match_dst = $match->{y_pos_match_dst};
4679 my $x_pos_match_src = $match->{x_pos_match_src};
4680 my $y_pos_match_src = $match->{y_pos_match_src};
4681 my $x_pos_translation = $match->{x_pos_translation};
4682 my $y_pos_translation = $match->{y_pos_translation};
4683 my $align_temp_image = $match->{align_temp_image};
4685 # if ($gps_obj_src_lat_up_objects) {
4686 # print STDERR "LAT UP OBJS: ".scalar(@$gps_obj_src_lat_up_objects)."\n";
4687 # foreach (@$gps_obj_src_lat_up_objects) {
4688 # my $gps_obj_src_lat_up_image_id = $_->{nir_image_id};
4690 # if ($gps_obj_src_lat_up_image_id && $nir_image_hash{$gps_obj_src_lat_up_image_id} && $nir_image_hash{$gps_obj_src_lat_up_image_id}->{match_src_to}) {
4691 # my $match2 = _drone_imagery_match_and_align_images($c, $schema, $gps_obj_src_lat_up_image_id, $image_id2, $nir_image_hash{$gps_obj_src_lat_up_image_id}, $gps_obj_dst, $max_features, $rotate_radians, $total_image_count, $image_counter, $skipped_counter);
4692 # my $smallest_diff2 = $match2->{smallest_diff};
4693 # my $x_pos_match_dst2 = $match2->{x_pos_match_dst};
4694 # my $y_pos_match_dst2 = $match2->{y_pos_match_dst};
4695 # my $x_pos_match_src2 = $match2->{x_pos_match_src};
4696 # my $y_pos_match_src2 = $match2->{y_pos_match_src};
4697 # my $x_pos_translation2 = $match2->{x_pos_translation};
4698 # my $y_pos_translation2 = $match2->{y_pos_translation};
4699 # my $align_temp_image2 = $match2->{align_temp_image};
4701 # if ($smallest_diff2 <= 50) {
4702 # $smallest_diff = ($smallest_diff + $smallest_diff2) / 2;
4703 # $x_pos_match_dst = ($x_pos_match_dst + $x_pos_match_dst2) / 2;
4704 # $y_pos_match_dst = ($y_pos_match_dst + $y_pos_match_dst2) / 2;
4705 # $x_pos_match_src = ($x_pos_match_src + $x_pos_match_src2) / 2;
4706 # $y_pos_match_src = ($y_pos_match_src + $y_pos_match_src2) / 2;
4707 # $x_pos_translation = ($x_pos_translation + $x_pos_translation2) / 2;
4708 # $y_pos_translation = ($y_pos_translation + $y_pos_translation2) / 2;
4714 if ($smallest_diff > 35 && $skipped_counter < 2) {
4715 $max_features = 50000 * ($skipped_counter + 1);
4716 $skipped_counter++;
4718 # elsif ($skipped_counter >= 2) {
4719 # $nir_image_hash{$image_id2}->{match_problem} = 1;
4720 # $image_id1 = undef;
4721 # $image_id2 = undef;
4722 # $message = "There was a problem matching up images. Please manually position the image outlined in red";
4724 else {
4725 $nir_image_hash{$image_id1}->{match_problem} = 0;
4726 $nir_image_hash{$image_id2}->{match_problem} = 0;
4728 if ($skipped_counter >= 2) {
4729 $x_pos_match_dst = $x_pos_match_dst + $width + $length;
4730 $y_pos_match_dst = $y_pos_match_dst + $width + $length;
4731 $nir_image_hash{$image_id2}->{match_problem} = 1;
4733 $max_features = 1000;
4734 $skipped_counter = 0;
4736 # my $match_image = SGN::Image->new( $schema->storage->dbh, undef, $c );
4737 # $match_image->set_sp_person_id($user_id);
4738 # my $ret = $match_image->process_image($align_temp_image, 'project', $drone_run_project_id, $align_linking_table_type_id);
4739 # my $match_image_fullpath = $match_image->get_filename('original_converted', 'full');
4740 # my $match_image_url = $match_image->get_image_url('original');
4741 # my $match_image_id = $match_image->get_image_id();
4742 # $nir_image_hash{$image_id2}->{image_url} = $match_image_url;
4743 # $nir_image_hash{$image_id2}->{nir_image_id} = $match_image_id;
4745 $nir_image_hash{$image_id2}->{x_pos} = $x_pos_match_dst;
4746 $nir_image_hash{$image_id2}->{y_pos} = $y_pos_match_dst;
4748 $nir_image_hash{$image_id1}->{match_src_to} = $image_id2;
4749 $nir_image_hash{$image_id2}->{match_dst_to} = $image_id1;
4751 my $cx = $width/2;
4752 my $cy = $length/2;
4753 my $temp_x1 = 0 - $cx;
4754 my $temp_y1 = $length - $cy;
4755 my $temp_x2 = $width - $cx;
4756 my $temp_y2 = $length - $cy;
4757 my $temp_x3 = $width - $cx;
4758 my $temp_y3 = 0 - $cy;
4759 my $temp_x4 = 0 - $cx;
4760 my $temp_y4 = 0 - $cy;
4762 my $rotated_x1 = $temp_x1*cos($rotate_radians) - $temp_y1*sin($rotate_radians);
4763 my $rotated_y1 = $temp_x1*sin($rotate_radians) + $temp_y1*cos($rotate_radians);
4764 my $rotated_x2 = $temp_x2*cos($rotate_radians) - $temp_y2*sin($rotate_radians);
4765 my $rotated_y2 = $temp_x2*sin($rotate_radians) + $temp_y2*cos($rotate_radians);
4766 my $rotated_x3 = $temp_x3*cos($rotate_radians) - $temp_y3*sin($rotate_radians);
4767 my $rotated_y3 = $temp_x3*sin($rotate_radians) + $temp_y3*cos($rotate_radians);
4768 my $rotated_x4 = $temp_x4*cos($rotate_radians) - $temp_y4*sin($rotate_radians);
4769 my $rotated_y4 = $temp_x4*sin($rotate_radians) + $temp_y4*cos($rotate_radians);
4771 $rotated_x1 = $rotated_x1 + $cx;
4772 $rotated_y1 = $rotated_y1 + $cy;
4773 $rotated_x2 = $rotated_x2 + $cx;
4774 $rotated_y2 = $rotated_y2 + $cy;
4775 $rotated_x3 = $rotated_x3 + $cx;
4776 $rotated_y3 = $rotated_y3 + $cy;
4777 $rotated_x4 = $rotated_x4 + $cx;
4778 $rotated_y4 = $rotated_y4 + $cy;
4780 my $rotated_bound_dst = [[$rotated_x1, $rotated_y1], [$rotated_x2, $rotated_y2], [$rotated_x3, $rotated_y3], [$rotated_x4, $rotated_y4]];
4781 my $rotated_bound_translated_dst = [[$rotated_x1 + $x_pos_match_dst, $rotated_y1 + $y_pos_match_dst], [$rotated_x2 + $x_pos_match_dst, $rotated_y2 + $y_pos_match_dst], [$rotated_x3 + $x_pos_match_dst, $rotated_y3 + $y_pos_match_dst], [$rotated_x4 + $x_pos_match_dst, $rotated_y4 + $y_pos_match_dst]];
4782 my $rotated_bound_src = [[$rotated_x1, $rotated_y1], [$rotated_x2, $rotated_y2], [$rotated_x3, $rotated_y3], [$rotated_x4, $rotated_y4]];
4783 my $rotated_bound_translated_src = [[$rotated_x1 + $x_pos_match_src, $rotated_y1 + $y_pos_match_src], [$rotated_x2 + $x_pos_match_src, $rotated_y2 + $y_pos_match_src], [$rotated_x3 + $x_pos_match_src, $rotated_y3 + $y_pos_match_src], [$rotated_x4 + $x_pos_match_src, $rotated_y4 + $y_pos_match_src]];
4785 $nir_image_hash{$image_id1}->{rotated_bound} = $rotated_bound_src;
4786 $nir_image_hash{$image_id1}->{rotated_bound_translated} = $rotated_bound_translated_src;
4787 $nir_image_hash{$image_id2}->{rotated_bound} = $rotated_bound_dst;
4788 $nir_image_hash{$image_id2}->{rotated_bound_translated} = $rotated_bound_translated_dst;
4790 $image_counter++;
4791 $image_id1 = $nir_image_ids->[$image_counter];
4792 $image_id2 = $nir_image_ids->[$image_counter+1];
4796 my %gps_images_matched;
4797 foreach (values %nir_image_hash) {
4798 if ($_->{latitude} && $_->{longitude}) {
4799 $gps_images_matched{$_->{latitude}}->{$_->{longitude}} = $_;
4803 my $minimum_x_val = 10000000000;
4804 my $minimum_y_val = 10000000000;
4805 while (my ($latitude, $lo) = each %gps_images_matched) {
4806 while (my ($longitude, $i) = each %$lo) {
4807 my $x_pos = $i->{x_pos} + 0;
4808 my $y_pos = $i->{y_pos} + 0;
4809 if ($x_pos < $minimum_x_val) {
4810 $minimum_x_val = $x_pos;
4812 if ($y_pos < $minimum_y_val) {
4813 $minimum_y_val = $y_pos;
4818 while (my ($latitude, $lo) = each %gps_images_matched) {
4819 while (my ($longitude, $i) = each %$lo) {
4820 my $x_pos = $i->{x_pos};
4821 my $y_pos = $i->{y_pos};
4822 $gps_images_matched{$latitude}->{$longitude}->{x_pos} = $return->{image_width}/2 + $x_pos - $minimum_x_val;
4823 $gps_images_matched{$latitude}->{$longitude}->{y_pos} = $return->{image_length}/2 + $y_pos - $minimum_y_val;
4825 foreach (@{$i->{rotated_bound_translated}}) {
4826 $_->[0] = $return->{image_width}/2 + $_->[0] - $minimum_x_val;
4827 $_->[1] = $return->{image_length}/2 + $_->[1] - $minimum_y_val;
4832 my $saved_gps_positions_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_gps_pixel_positions', 'project_property')->cvterm_id();
4833 my $saved_gps_positions_json = $schema->resultset("Project::Projectprop")->find({
4834 project_id => $drone_run_project_id,
4835 type_id => $saved_gps_positions_type_id
4837 my $saved_gps_positions_full;
4838 if ($saved_gps_positions_json) {
4839 $saved_gps_positions_full = decode_json $saved_gps_positions_json->value();
4842 $saved_gps_positions_full->{$flight_pass_counter} = \%gps_images_matched;
4844 my $drone_run_band_rotate_angle = $schema->resultset('Project::Projectprop')->update_or_create({
4845 type_id=>$saved_gps_positions_type_id,
4846 project_id=>$drone_run_project_id,
4847 rank=>0,
4848 value=>encode_json $saved_gps_positions_full
4851 key=>'projectprop_c1'
4854 if ($flight_pass_counter == $max_flight_pass_counter) {
4855 my $drone_run_rotate_process_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_rotation_occuring', 'project_property')->cvterm_id();
4856 my $drone_run_rotate_process = $schema->resultset('Project::Projectprop')->update_or_create({
4857 type_id=>$drone_run_rotate_process_type_id,
4858 project_id=>$drone_run_project_id,
4859 rank=>0,
4860 value=>0
4863 key=>'projectprop_c1'
4867 return {
4868 saved_gps_positions_full => $saved_gps_positions_full,
4869 message => $message
4873 sub drone_imagery_match_and_align_images_sequential : Path('/api/drone_imagery/match_and_align_images_sequential') : ActionClass('REST') { }
4874 sub drone_imagery_match_and_align_images_sequential_POST : Args(0) {
4875 my $self = shift;
4876 my $c = shift;
4877 print STDERR Dumper $c->req->params();
4878 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4879 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4880 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
4881 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
4882 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
4883 my ($user_id, $user_name, $user_role) = _check_user_login($c);
4885 my $drone_run_project_id = $c->req->param('drone_run_project_id');
4886 my $nir_image_ids = decode_json $c->req->param('nir_image_ids');
4887 my $flight_pass_counter = $c->req->param("flight_pass_counter");
4889 my $return = _perform_match_raw_images_sequential($c, $schema, $metadata_schema, $phenome_schema, $people_schema, $drone_run_project_id, $nir_image_ids, $flight_pass_counter, $user_id, $user_name, $user_role);
4890 my $saved_gps_positions_full = $return->{saved_gps_positions_full};
4891 my $message = $return->{message};
4893 $c->stash->{rest} = {
4894 success => 1,
4895 gps_images_matched => $saved_gps_positions_full,
4896 message => $message
4900 sub drone_imagery_delete_gps_images : Path('/api/drone_imagery/delete_gps_images') : ActionClass('REST') { }
4901 sub drone_imagery_delete_gps_images_POST : Args(0) {
4902 my $self = shift;
4903 my $c = shift;
4904 print STDERR Dumper $c->req->params();
4905 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4906 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4907 my ($user_id, $user_name, $user_role) = _check_user_login($c);
4909 my $drone_run_project_id = $c->req->param("drone_run_project_id");
4911 my $saved_gps_positions_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_gps_pixel_positions', 'project_property')->cvterm_id();
4912 my $saved_gps_positions_json = $schema->resultset("Project::Projectprop")->find({
4913 project_id => $drone_run_project_id,
4914 type_id => $saved_gps_positions_type_id
4916 if ($saved_gps_positions_json) {
4917 $saved_gps_positions_json->delete();
4920 #Separated RESTART
4921 my $saved_image_stacks_separated_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks_separated', 'project_property')->cvterm_id();
4922 my $saved_micasense_stacks_separated_json = $schema->resultset("Project::Projectprop")->find({
4923 project_id => $drone_run_project_id,
4924 type_id => $saved_image_stacks_separated_type_id
4926 if ($saved_micasense_stacks_separated_json) {
4927 $saved_micasense_stacks_separated_json->delete();
4930 #ROTATED RESTART
4931 my $saved_image_stacks_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_micasense_stacks_rotated', 'project_property')->cvterm_id();
4932 my $saved_micasense_stacks_json = $schema->resultset("Project::Projectprop")->find({
4933 project_id => $drone_run_project_id,
4934 type_id => $saved_image_stacks_type_id
4936 if ($saved_micasense_stacks_json) {
4937 $saved_micasense_stacks_json->delete();
4940 $c->stash->{rest} = {
4941 success => 1
4945 sub drone_imagery_save_gps_images : Path('/api/drone_imagery/save_gps_images') : ActionClass('REST') { }
4946 sub drone_imagery_save_gps_images_POST : Args(0) {
4947 my $self = shift;
4948 my $c = shift;
4949 # print STDERR Dumper $c->req->params();
4950 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4951 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4952 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
4953 my $drone_run_project_id = $c->req->param('drone_run_project_id');
4954 my $flight_pass_counter = $c->req->param('flight_pass_counter');
4955 my $gps_images = decode_json $c->req->param('gps_images');
4957 my $saved_gps_positions_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_gps_pixel_positions', 'project_property')->cvterm_id();
4958 my $saved_gps_positions_json = $schema->resultset("Project::Projectprop")->find({
4959 project_id => $drone_run_project_id,
4960 type_id => $saved_gps_positions_type_id
4962 my $saved_gps_positions_full;
4963 if ($saved_gps_positions_json) {
4964 $saved_gps_positions_full = decode_json $saved_gps_positions_json->value();
4967 $saved_gps_positions_full->{$flight_pass_counter} = $gps_images;
4969 my $drone_run_band_rotate_angle = $schema->resultset('Project::Projectprop')->update_or_create({
4970 type_id=>$saved_gps_positions_type_id,
4971 project_id=>$drone_run_project_id,
4972 rank=>0,
4973 value => encode_json $saved_gps_positions_full
4976 key=>'projectprop_c1'
4979 $c->stash->{rest} = {
4980 success => 1,
4981 gps_images => $gps_images
4985 sub drone_imagery_calculate_statistics_store_analysis : Path('/api/drone_imagery/calculate_statistics_store_analysis') : ActionClass('REST') { }
4986 sub drone_imagery_calculate_statistics_store_analysis_POST : Args(0) {
4987 my $self = shift;
4988 my $c = shift;
4989 print STDERR Dumper $c->req->params();
4990 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
4991 my $bcs_schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
4992 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
4993 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
4994 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
4995 my $analysis_name = $c->req->param('analysis_name');
4996 my $analysis_description = $c->req->param('analysis_description');
4997 my $analysis_model_type = $c->req->param('statistics_select');
4998 my $accession_names = $c->req->param('accession_names');
4999 my $trait_names = $c->req->param('trait_names');
5000 my $training_data_file = $c->req->param('training_data_file');
5001 my $phenotype_data_hash = $c->req->param('phenotype_data_hash');
5002 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5004 my $a = CXGN::Analysis->new({
5005 bcs_schema => $bcs_schema,
5006 people_schema => $people_schema,
5007 metadata_schema => $metadata_schema,
5008 phenome_schema => $phenome_schema,
5009 name => $analysis_name,
5012 $a->description($analysis_description);
5013 $a->user_id($user_id);
5015 my $model_string = '';
5017 #print STDERR Dumper("STOCKS HERE: ".$stocks);
5018 $a->accession_names($accession_names);
5019 $a->metadata()->traits($trait_names);
5020 #$a->metadata()->analysis_protocol($params->{analysis_protocol});
5021 $a->metadata()->model($model_string);
5023 my ($verified_warning, $verified_error);
5025 print STDERR "Storing the analysis...\n";
5026 eval {
5027 ($verified_warning, $verified_error) = $a->create_and_store_analysis_design();
5030 my @errors;
5031 my @warnings;
5033 if ($@) {
5034 push @errors, $@;
5036 elsif ($verified_warning) {
5037 push @warnings, $verified_warning;
5039 elsif ($verified_error) {
5040 push @errors, $verified_error;
5043 if (@errors) {
5044 print STDERR "SORRY! Errors: ".join("\n", @errors);
5045 $c->stash->{rest} = { error => join "; ", @errors };
5046 return;
5049 print STDERR "Store analysis values...\n";
5050 #print STDERR "value hash: ".Dumper($values);
5051 print STDERR "traits: ".join(",",@$trait_names);
5053 my $plots;
5054 my $values;
5056 eval {
5057 $a->store_analysis_values(
5058 $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id),
5059 $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id),
5060 $values, # value_hash
5061 $plots,
5062 $trait_names,
5063 $user_name,
5064 $c->config->{basepath},
5065 $c->config->{dbhost},
5066 $c->config->{dbname},
5067 $c->config->{dbuser},
5068 $c->config->{dbpass}
5072 if ($@) {
5073 print STDERR "An error occurred storing analysis values ($@).\n";
5074 $c->stash->{rest} = {
5075 error => "An error occurred storing the values ($@).\n"
5077 return;
5080 $c->stash->{rest} = { success => 1 };
5083 sub drone_imagery_rotate_image : Path('/api/drone_imagery/rotate_image') : ActionClass('REST') { }
5084 sub drone_imagery_rotate_image_GET : Args(0) {
5085 my $self = shift;
5086 my $c = shift;
5087 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5088 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5089 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5090 my $image_id = $c->req->param('image_id');
5091 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5092 my $angle_rotation = $c->req->param('angle');
5093 my $view_only = $c->req->param('view_only');
5094 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5096 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
5097 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
5098 $archive_rotate_temp_image .= '.png';
5100 my $return = _perform_image_rotate($c, $schema, $metadata_schema, $drone_run_band_project_id, $image_id, $angle_rotation, $view_only, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, 1, 0);
5102 $c->stash->{rest} = $return;
5105 sub _perform_image_rotate {
5106 my $c = shift;
5107 my $schema = shift;
5108 my $metadata_schema = shift;
5109 my $drone_run_band_project_id = shift;
5110 my $image_id = shift;
5111 my $angle_rotation = shift || 0;
5112 my $view_only = shift;
5113 my $user_id = shift;
5114 my $user_name = shift;
5115 my $user_role = shift;
5116 my $archive_rotate_temp_image = shift;
5117 my $centered = shift;
5118 my $dont_check_for_previous = shift;
5119 my $check_resize = shift;
5120 my $keep_original_size_rotate = shift;
5122 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
5123 my $image_url = $image->get_image_url("original");
5124 my $image_fullpath = $image->get_filename('original_converted', 'full');
5126 my $center = '';
5127 if ($centered) {
5128 $center = ' --centered 1';
5130 my $original_size = '';
5131 if ($keep_original_size_rotate) {
5132 $original_size = ' --original_size 1';
5134 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/Rotate.py --image_path \''.$image_fullpath.'\' --outfile_path \''.$archive_rotate_temp_image.'\' --angle '.$angle_rotation.$center.$original_size;
5135 print STDERR Dumper $cmd;
5136 my $status = system("$cmd > /dev/null");
5138 if ($check_resize) {
5139 my ($check_image_width, $check_image_height) = imgsize($archive_rotate_temp_image);
5140 if ($check_image_width > 16384) {
5141 my $cmd_resize = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/Resize.py --image_path \''.$archive_rotate_temp_image.'\' --outfile_path \''.$archive_rotate_temp_image.'\' --width 16384';
5142 print STDERR Dumper $cmd_resize;
5143 my $status_resize = system("$cmd_resize > /dev/null");
5145 elsif ($check_image_height > 16384) {
5146 my $cmd_resize = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/Resize.py --image_path \''.$archive_rotate_temp_image.'\' --outfile_path \''.$archive_rotate_temp_image.'\' --height 16384';
5147 print STDERR Dumper $cmd_resize;
5148 my $status_resize = system("$cmd_resize > /dev/null");
5152 my $linking_table_type_id;
5153 if ($view_only) {
5154 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'rotated_stitched_temporary_drone_imagery', 'project_md_image')->cvterm_id();
5155 } else {
5156 my $rotated_stitched_temporary_drone_images_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'rotated_stitched_temporary_drone_imagery', 'project_md_image')->cvterm_id();
5157 my $rotated_stitched_temporary_images_search = CXGN::DroneImagery::ImagesSearch->new({
5158 bcs_schema=>$schema,
5159 project_image_type_id=>$rotated_stitched_temporary_drone_images_cvterm_id,
5160 drone_run_band_project_id_list=>[$drone_run_band_project_id]
5162 my ($rotated_stitched_temporary_result, $rotated_stitched_temporary_total_count) = $rotated_stitched_temporary_images_search->search();
5163 foreach (@$rotated_stitched_temporary_result){
5164 my $temp_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
5165 $temp_image->delete(); #Sets to obsolete
5167 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'rotated_stitched_drone_imagery', 'project_md_image')->cvterm_id();
5169 my $rotated_stitched_images_search = CXGN::DroneImagery::ImagesSearch->new({
5170 bcs_schema=>$schema,
5171 project_image_type_id=>$linking_table_type_id,
5172 drone_run_band_project_id_list=>[$drone_run_band_project_id]
5174 my ($rotated_stitched_result, $rotated_stitched_total_count) = $rotated_stitched_images_search->search();
5175 foreach (@$rotated_stitched_result){
5176 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
5177 $previous_image->delete(); #Sets to obsolete
5180 my $drone_run_band_rotate_angle_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_rotate_angle', 'project_property')->cvterm_id();
5181 my $drone_run_band_rotate_angle = $schema->resultset('Project::Projectprop')->update_or_create({
5182 type_id=>$drone_run_band_rotate_angle_type_id,
5183 project_id=>$drone_run_band_project_id,
5184 rank=>0,
5185 value=>$angle_rotation
5188 key=>'projectprop_c1'
5192 my $rotated_image_fullpath;
5193 my $rotated_image_url;
5194 my $rotated_image_id;
5195 if ($dont_check_for_previous) {
5196 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
5197 $image->set_sp_person_id($user_id);
5198 my $ret = $image->process_image($archive_rotate_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
5199 $rotated_image_fullpath = $image->get_filename('original_converted', 'full');
5200 $rotated_image_url = $image->get_image_url('original');
5201 $rotated_image_id = $image->get_image_id();
5203 else {
5204 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
5205 my $md5checksum = $image->calculate_md5sum($archive_rotate_temp_image);
5206 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
5207 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
5208 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
5209 my $h = $schema->storage->dbh->prepare($q);
5210 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id);
5211 my ($saved_image_id) = $h->fetchrow_array();
5213 if ($saved_image_id) {
5214 print STDERR Dumper "Image $archive_rotate_temp_image has already been added to the database and will not be added again.";
5215 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
5216 $rotated_image_fullpath = $image->get_filename('original_converted', 'full');
5217 $rotated_image_url = $image->get_image_url('original');
5218 $rotated_image_id = $image->get_image_id();
5219 } else {
5220 $image->set_sp_person_id($user_id);
5221 my $ret = $image->process_image($archive_rotate_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
5222 $rotated_image_fullpath = $image->get_filename('original_converted', 'full');
5223 $rotated_image_url = $image->get_image_url('original');
5224 $rotated_image_id = $image->get_image_id();
5228 unlink($archive_rotate_temp_image);
5229 return {
5230 rotated_image_id => $rotated_image_id, image_url => $image_url, image_fullpath => $image_fullpath, rotated_image_url => $rotated_image_url, rotated_image_fullpath => $rotated_image_fullpath
5234 sub drone_imagery_get_contours : Path('/api/drone_imagery/get_contours') : ActionClass('REST') { }
5235 sub drone_imagery_get_contours_GET : Args(0) {
5236 my $self = shift;
5237 my $c = shift;
5238 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5239 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5240 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5241 my $image_id = $c->req->param('image_id');
5242 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5243 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5245 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'contours_stitched_drone_imagery', 'project_md_image')->cvterm_id();
5246 my $main_production_site = $c->config->{main_production_site_url};
5248 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
5249 my $image_url = $image->get_image_url("original");
5250 my $image_fullpath = $image->get_filename('original_converted', 'full');
5252 my $dir = $c->tempfiles_subdir('/drone_imagery_contours');
5253 my $archive_contours_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_contours/imageXXXX');
5254 $archive_contours_temp_image .= '.png';
5256 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageContours/GetContours.py --image_path \''.$image_fullpath.'\' --outfile_path \''.$archive_contours_temp_image.'\'';
5257 print STDERR Dumper $cmd;
5258 my $status = system("$cmd > /dev/null");
5260 my @size = imgsize($archive_contours_temp_image);
5262 my $contours_image_fullpath;
5263 my $contours_image_url;
5264 my $contours_image_id;
5266 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
5267 my $md5checksum = $image->calculate_md5sum($archive_contours_temp_image);
5268 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
5269 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
5270 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
5271 my $h = $schema->storage->dbh->prepare($q);
5272 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id);
5273 my ($saved_image_id) = $h->fetchrow_array();
5275 if ($saved_image_id) {
5276 print STDERR Dumper "Image $archive_contours_temp_image has already been added to the database and will not be added again.";
5277 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
5278 $contours_image_fullpath = $image->get_filename('original_converted', 'full');
5279 $contours_image_url = $image->get_image_url('original');
5280 $contours_image_id = $image->get_image_id();
5281 } else {
5282 my $previous_contour_images_search = CXGN::DroneImagery::ImagesSearch->new({
5283 bcs_schema=>$schema,
5284 project_image_type_id=>$linking_table_type_id,
5285 drone_run_band_project_id_list=>[$drone_run_band_project_id]
5287 my ($previous_contour_result, $previous_contour_total_count) = $previous_contour_images_search->search();
5288 foreach (@$previous_contour_result){
5289 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
5290 $previous_image->delete(); #Sets to obsolete
5293 $image->set_sp_person_id($user_id);
5294 my $ret = $image->process_image($archive_contours_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
5295 $contours_image_fullpath = $image->get_filename('original_converted', 'full');
5296 $contours_image_url = $image->get_image_url('original');
5297 $contours_image_id = $image->get_image_id();
5300 unlink($archive_contours_temp_image);
5301 $c->stash->{rest} = { image_url => $image_url, image_fullpath => $image_fullpath, contours_image_id => $contours_image_id, contours_image_url => $contours_image_url, contours_image_fullpath => $contours_image_fullpath, image_width => $size[0], image_height => $size[1] };
5304 sub drone_imagery_retrieve_parameter_template : Path('/api/drone_imagery/retrieve_parameter_template') : ActionClass('REST') { }
5305 sub drone_imagery_retrieve_parameter_template_GET : Args(0) {
5306 my $self = shift;
5307 my $c = shift;
5308 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5309 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5310 my $template_projectprop_id = $c->req->param('plot_polygons_template_projectprop_id');
5312 my $rs = $schema->resultset("Project::Projectprop")->find({projectprop_id => $template_projectprop_id});
5313 my $plot_polygons = decode_json $rs->value;
5315 $c->stash->{rest} = {
5316 success => 1,
5317 parameter => $plot_polygons
5321 sub drone_imagery_assign_plot_polygons : Path('/api/drone_imagery/assign_plot_polygons') : ActionClass('REST') { }
5322 sub drone_imagery_assign_plot_polygons_POST : Args(0) {
5323 my $self = shift;
5324 my $c = shift;
5325 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5326 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5327 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5328 my $image_id = $c->req->param('image_id');
5329 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5330 my $stock_polygons = $c->req->param('stock_polygons');
5331 my $assign_plot_polygons_type = $c->req->param('assign_plot_polygons_type');
5333 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5335 my $return = _perform_plot_polygon_assign($c, $schema, $metadata_schema, $image_id, $drone_run_band_project_id, $stock_polygons, $assign_plot_polygons_type, $user_id, $user_name, $user_role, 1, 0, 1, 1, 'rectangular_square');
5337 $c->stash->{rest} = $return;
5340 sub _perform_plot_polygon_assign {
5341 my $c = shift;
5342 my $schema = shift;
5343 my $metadata_schema = shift;
5344 my $image_id = shift;
5345 my $drone_run_band_project_id = shift;
5346 my $stock_polygons = shift;
5347 my $assign_plot_polygons_type = shift;
5348 my $user_id = shift;
5349 my $user_name = shift;
5350 my $user_role = shift;
5351 my $from_web_interface = shift;
5352 my $ignore_previous_image_check = shift;
5353 my $width_ratio = shift;
5354 my $height_ratio = shift;
5355 my $cropping_type = shift || 'rectangular_square';
5357 print STDERR "Plot Polygon Assign Type: $assign_plot_polygons_type \n";
5359 my $number_system_cores = `getconf _NPROCESSORS_ONLN` or die "Could not get number of system cores!\n";
5360 chomp($number_system_cores);
5361 print STDERR "NUMCORES $number_system_cores\n";
5363 my $polygon_objs = decode_json $stock_polygons;
5364 my %stock_ids;
5366 # print STDERR Dumper $polygon_objs;
5368 foreach my $stock_name (keys %$polygon_objs) {
5369 my $polygon = $polygon_objs->{$stock_name};
5371 my @p_rescaled;
5372 foreach my $point (@$polygon) {
5373 my $x = $point->{x};
5374 my $y = $point->{y};
5375 push @p_rescaled, {x=>round($x/$width_ratio), y=>round($y/$height_ratio)};
5377 $polygon = \@p_rescaled;
5379 if ($from_web_interface) {
5380 my $last_point = pop @$polygon;
5382 if (scalar(@$polygon) != 4){
5383 # print STDERR Dumper $polygon;
5384 $c->stash->{rest} = {error=>'Error: Polygon for '.$stock_name.' should be 4 long!'};
5385 $c->detach();
5387 $polygon_objs->{$stock_name} = $polygon;
5389 my $stock = $schema->resultset("Stock::Stock")->find({uniquename => $stock_name});
5390 if (!$stock) {
5391 $c->stash->{rest} = {error=>'Error: Stock name '.$stock_name.' does not exist in the database!'};
5392 $c->detach();
5394 $stock_ids{$stock_name} = $stock->stock_id;
5397 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
5398 my $image_url = $image->get_image_url("original");
5399 my $image_fullpath = $image->get_filename('original_converted', 'full');
5401 my $drone_run_band_plot_polygons_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
5402 my $previous_plot_polygons_rs = $schema->resultset('Project::Projectprop')->search({type_id=>$drone_run_band_plot_polygons_type_id, project_id=>$drone_run_band_project_id});
5403 if ($previous_plot_polygons_rs->count > 1) {
5404 die "There should not be more than one saved entry for plot polygons for a drone run band";
5407 my $save_stock_polygons;
5408 if ($previous_plot_polygons_rs->count > 0) {
5409 $save_stock_polygons = decode_json $previous_plot_polygons_rs->first->value;
5411 foreach my $stock_name (keys %$polygon_objs) {
5412 $save_stock_polygons->{$stock_name} = $polygon_objs->{$stock_name};
5415 my $drone_run_band_plot_polygons = $schema->resultset('Project::Projectprop')->update_or_create({
5416 type_id=>$drone_run_band_plot_polygons_type_id,
5417 project_id=>$drone_run_band_project_id,
5418 rank=>0,
5419 value=> encode_json($save_stock_polygons)
5422 key=>'projectprop_c1'
5425 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $assign_plot_polygons_type, 'project_md_image')->cvterm_id();
5427 my @found_stock_ids = values %stock_ids;
5428 if (!$ignore_previous_image_check) {
5429 my $previous_images_search = CXGN::DroneImagery::ImagesSearch->new({
5430 bcs_schema=>$schema,
5431 drone_run_band_project_id_list=>[$drone_run_band_project_id],
5432 project_image_type_id=>$linking_table_type_id,
5433 stock_id_list=>\@found_stock_ids
5435 my ($previous_result, $previous_total_count) = $previous_images_search->search();
5437 if (scalar(@$previous_result) == scalar(@found_stock_ids)) {
5438 print STDERR "Plot polygon assignment for $assign_plot_polygons_type on project $drone_run_band_project_id has already occured. Skipping \n";
5439 return {warning => "Plot polygon assignment already occured for $assign_plot_polygons_type on project $drone_run_band_project_id."};
5443 my $image_tag_id = CXGN::Tag::exists_tag_named($schema->storage->dbh, $assign_plot_polygons_type);
5444 if (!$image_tag_id) {
5445 my $image_tag = CXGN::Tag->new($schema->storage->dbh);
5446 $image_tag->set_name($assign_plot_polygons_type);
5447 $image_tag->set_description('Drone run band project type for plot polygon assignment: '.$assign_plot_polygons_type);
5448 $image_tag->set_sp_person_id($user_id);
5449 $image_tag_id = $image_tag->store();
5451 my $image_tag = CXGN::Tag->new($schema->storage->dbh, $image_tag_id);
5453 my $corresponding_channel = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema)->{$linking_table_type_id}->{corresponding_channel} || '';
5455 my @plot_polygon_image_fullpaths;
5456 my @plot_polygon_image_urls;
5458 my $dir = $c->tempfiles_subdir('/drone_imagery_plot_polygons');
5459 my $bulk_input_temp_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_plot_polygons/bulkinputXXXX');
5461 open(my $F, ">", $bulk_input_temp_file) || die "Can't open file ".$bulk_input_temp_file;
5463 my @plot_polygons;
5464 foreach my $stock_name (keys %$polygon_objs) {
5465 #my $pid = $pm->start and next;
5467 my $polygon = $polygon_objs->{$stock_name};
5468 my $polygons = encode_json [$polygon];
5470 my $stock_id = $stock_ids{$stock_name};
5472 my $archive_plot_polygons_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_plot_polygons/imageXXXX');
5473 $archive_plot_polygons_temp_image .= '.png';
5475 print $F "$image_fullpath\t$archive_plot_polygons_temp_image\t$polygons\t$cropping_type\t$corresponding_channel\n";
5477 push @plot_polygons, {
5478 temp_plot_image => $archive_plot_polygons_temp_image,
5479 stock_id => $stock_id
5483 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/ImageCropping/CropToPolygonBulk.py --inputfile_path '$bulk_input_temp_file'";
5484 print STDERR Dumper $cmd;
5485 my $status = system("$cmd > /dev/null");
5487 my $pm = Parallel::ForkManager->new(ceil($number_system_cores/4));
5488 $pm->run_on_finish( sub {
5489 my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
5490 push @plot_polygon_image_urls, $data_structure_reference->{plot_polygon_image_url};
5491 push @plot_polygon_image_fullpaths, $data_structure_reference->{plot_polygon_image_fullpath};
5494 foreach my $obj (@plot_polygons) {
5495 my $archive_plot_polygons_temp_image = $obj->{temp_plot_image};
5496 my $stock_id = $obj->{stock_id};
5498 my $plot_polygon_image_fullpath;
5499 my $plot_polygon_image_url;
5500 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
5501 my $md5checksum = $image->calculate_md5sum($archive_plot_polygons_temp_image);
5502 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
5503 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
5504 JOIN phenome.stock_image AS stock_image ON (stock_image.image_id = md_image.image_id)
5505 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ? AND stock_image.stock_id = ?;";
5506 my $h = $schema->storage->dbh->prepare($q);
5507 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id, $stock_id);
5508 my ($image_id) = $h->fetchrow_array();
5510 if ($image_id) {
5511 print STDERR Dumper "Image $archive_plot_polygons_temp_image has already been added to the database and will not be added again.";
5512 $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
5513 $plot_polygon_image_fullpath = $image->get_filename('original_converted', 'full');
5514 $plot_polygon_image_url = $image->get_image_url('original');
5515 } else {
5516 $image->set_sp_person_id($user_id);
5517 my $ret = $image->process_image($archive_plot_polygons_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
5518 my $stock_associate = $image->associate_stock($stock_id, $user_name);
5519 $plot_polygon_image_fullpath = $image->get_filename('original_converted', 'full');
5520 $plot_polygon_image_url = $image->get_image_url('original');
5521 my $added_image_tag_id = $image->add_tag($image_tag);
5523 unlink($archive_plot_polygons_temp_image);
5525 $pm->finish(0, { plot_polygon_image_url => $plot_polygon_image_url, plot_polygon_image_fullpath => $plot_polygon_image_fullpath });
5527 $pm->wait_all_children;
5529 return {
5530 image_url => $image_url, image_fullpath => $image_fullpath, success => 1, drone_run_band_template_id => $drone_run_band_plot_polygons->projectprop_id
5534 sub drone_imagery_manual_assign_plot_polygon_save_partial_template : Path('/api/drone_imagery/manual_assign_plot_polygon_save_partial_template') : ActionClass('REST') { }
5535 sub drone_imagery_manual_assign_plot_polygon_save_partial_template_POST : Args(0) {
5536 my $self = shift;
5537 my $c = shift;
5538 print STDERR Dumper $c->req->params();
5539 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5540 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5541 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5542 my @image_ids = $c->req->param('image_ids[]');
5543 my $polygon_json = $c->req->param('polygon');
5544 my $polygon_plot_numbers_json = $c->req->param('polygon_plot_numbers');
5545 my $field_trial_id = $c->req->param('field_trial_id');
5546 my $drone_run_project_id = $c->req->param('drone_run_project_id');
5547 my $angle_rotated = $c->req->param('angle_rotated');
5548 my $partial_template_name = $c->req->param('partial_template_name');
5550 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5552 my $polygon_hash = decode_json $polygon_json;
5553 my $polygon_plot_numbers_hash = decode_json $polygon_plot_numbers_json;
5555 my $plot_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot number', 'stock_property')->cvterm_id();
5556 my $field_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'field_layout', 'experiment_type')->cvterm_id();
5558 my $q = "SELECT stock.uniquename FROM stock
5559 JOIN stockprop USING(stock_id)
5560 JOIN nd_experiment_stock USING(stock_id)
5561 JOIN nd_experiment USING(nd_experiment_id)
5562 JOIN nd_experiment_project USING(nd_experiment_id)
5563 WHERE project_id = $field_trial_id
5564 AND nd_experiment.type_id = $field_experiment_cvterm_id
5565 AND stockprop.type_id = $plot_number_cvterm_id
5566 AND stockprop.value = ?;";
5567 my $h = $schema->storage->dbh->prepare($q);
5569 my %stock_polygon;
5570 while (my ($generated_index, $plot_number) = each %$polygon_plot_numbers_hash) {
5571 $h->execute($plot_number);
5572 my ($uniquename) = $h->fetchrow_array();
5573 my $plot_polygon = $polygon_hash->{$generated_index};
5574 my $last_point = pop @$plot_polygon;
5575 if (scalar(@$plot_polygon) != 4){
5576 $c->stash->{rest} = {error=>'Error: Polygon for '.$uniquename.' should be 4 long!'};
5577 $c->detach();
5579 $stock_polygon{$uniquename} = $plot_polygon;
5582 my $manual_plot_polygon_template_partial = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons_partial', 'project_property')->cvterm_id();
5584 my $previous_plot_polygons_rs = $schema->resultset('Project::Projectprop')->search({type_id=>$manual_plot_polygon_template_partial, project_id=>$drone_run_project_id});
5585 if ($previous_plot_polygons_rs->count > 1) {
5586 die "There should not be more than one saved entry for partial plot polygon template for a drone run";
5589 my @save_stock_polygons;
5590 if ($previous_plot_polygons_rs->count > 0) {
5591 @save_stock_polygons = @{decode_json $previous_plot_polygons_rs->first->value};
5593 push @save_stock_polygons, {
5594 template_name => $partial_template_name,
5595 image_id => $image_ids[3], #NIR image id
5596 polygon => $polygon_hash,
5597 stock_polygon => \%stock_polygon
5600 my $drone_run_band_plot_polygons = $schema->resultset('Project::Projectprop')->update_or_create({
5601 type_id=>$manual_plot_polygon_template_partial,
5602 project_id=>$drone_run_project_id,
5603 rank=>0,
5604 value=> encode_json(\@save_stock_polygons)
5607 key=>'projectprop_c1'
5610 $c->stash->{rest} = {success => 1};
5613 sub drone_imagery_manual_assign_plot_polygon : Path('/api/drone_imagery/manual_assign_plot_polygon') : ActionClass('REST') { }
5614 sub drone_imagery_manual_assign_plot_polygon_POST : Args(0) {
5615 my $self = shift;
5616 my $c = shift;
5617 print STDERR Dumper $c->req->params();
5618 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5619 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5620 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5621 my @image_ids = $c->req->param('image_ids[]');
5622 my $polygon_json = $c->req->param('polygon');
5623 my $polygon_plot_numbers_json = $c->req->param('polygon_plot_numbers');
5624 my $field_trial_id = $c->req->param('field_trial_id');
5625 my $drone_run_project_id = $c->req->param('drone_run_project_id');
5626 my $angle_rotated = $c->req->param('angle_rotated');
5627 my $partial_template_name = $c->req->param('partial_template_name');
5629 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5631 my $polygon_hash = decode_json $polygon_json;
5632 my $polygon_plot_numbers_hash = decode_json $polygon_plot_numbers_json;
5634 my $plot_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot number', 'stock_property')->cvterm_id();
5635 my $field_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'field_layout', 'experiment_type')->cvterm_id();
5637 my $q = "SELECT stock.uniquename FROM stock
5638 JOIN stockprop USING(stock_id)
5639 JOIN nd_experiment_stock USING(stock_id)
5640 JOIN nd_experiment USING(nd_experiment_id)
5641 JOIN nd_experiment_project USING(nd_experiment_id)
5642 WHERE project_id = $field_trial_id
5643 AND nd_experiment.type_id = $field_experiment_cvterm_id
5644 AND stockprop.type_id = $plot_number_cvterm_id
5645 AND stockprop.value = ?;";
5646 my $h = $schema->storage->dbh->prepare($q);
5648 my %stock_polygon;
5649 while (my ($generated_index, $plot_number) = each %$polygon_plot_numbers_hash) {
5650 $h->execute($plot_number);
5651 my ($uniquename) = $h->fetchrow_array();
5652 my $plot_polygon = $polygon_hash->{$generated_index};
5653 my $last_point = pop @$plot_polygon;
5654 if (scalar(@$plot_polygon) != 4){
5655 $c->stash->{rest} = {error=>'Error: Polygon for '.$uniquename.' should be 4 long!'};
5656 $c->detach();
5658 $stock_polygon{$uniquename} = $plot_polygon;
5661 my $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
5662 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
5664 my $q_drone_run_bands = "SELECT drone_run_band.project_id, drone_run_band_project_type.value
5665 FROM project AS drone_run
5666 JOIN project_relationship ON (drone_run.project_id = project_relationship.object_project_id AND project_relationship.type_id=$project_relationship_type_id)
5667 JOIN project as drone_run_band ON (drone_run_band.project_id=project_relationship.subject_project_id)
5668 JOIN projectprop AS drone_run_band_project_type ON (drone_run_band_project_type.project_id=drone_run_band.project_id AND drone_run_band_project_type.type_id=$drone_run_band_project_type_cvterm_id)
5669 WHERE drone_run.project_id=?;";
5670 my $h_drone_run_bands = $schema->storage->dbh->prepare($q_drone_run_bands);
5671 $h_drone_run_bands->execute($drone_run_project_id);
5672 my %drone_run_bands_all;
5673 while (my ($drone_run_band_id, $drone_run_band_type) = $h_drone_run_bands->fetchrow_array()) {
5674 $drone_run_bands_all{$drone_run_band_type} = $drone_run_band_id;
5676 print STDERR Dumper \%drone_run_bands_all;
5678 my $drone_image_types = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
5679 my @plot_polygon_type_ids = (
5680 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_blue_imagery', 'project_md_image')->cvterm_id(),
5681 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_green_imagery', 'project_md_image')->cvterm_id(),
5682 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_red_imagery', 'project_md_image')->cvterm_id(),
5683 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_nir_imagery', 'project_md_image')->cvterm_id(),
5684 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_red_edge_imagery', 'project_md_image')->cvterm_id()
5686 my @plot_polygon_type_objects;
5687 foreach (@plot_polygon_type_ids) {
5688 push @plot_polygon_type_objects, $drone_image_types->{$_};
5691 my $stock_polygons = encode_json \%stock_polygon;
5692 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
5694 foreach my $index (0..scalar(@image_ids)-1) {
5695 my $drone_run_band_project_type = $plot_polygon_type_objects[$index]->{drone_run_project_types}->[0];
5696 my $plot_polygon_type = $plot_polygon_type_objects[$index]->{name};
5697 my $image_id = $image_ids[$index];
5698 my $drone_run_band_project_id = $drone_run_bands_all{$drone_run_band_project_type};
5700 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
5701 $archive_rotate_temp_image .= '.png';
5703 my $rotate_return = _perform_image_rotate($c, $schema, $metadata_schema, $drone_run_band_project_id, $image_id, $angle_rotated, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, 1, 0);
5704 my $rotated_image_id = $rotate_return->{rotated_image_id};
5706 my $return = _perform_plot_polygon_assign($c, $schema, $metadata_schema, $rotated_image_id, $drone_run_band_project_id, $stock_polygons, $plot_polygon_type, $user_id, $user_name, $user_role, 0, 1, 1, 1, 'rectangular_square');
5709 $c->stash->{rest} = {success => 1};
5712 sub drone_imagery_save_plot_polygons_template : Path('/api/drone_imagery/save_plot_polygons_template') : ActionClass('REST') { }
5713 sub drone_imagery_save_plot_polygons_template_POST : Args(0) {
5714 my $self = shift;
5715 my $c = shift;
5716 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5717 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5718 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5719 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5720 my $stock_polygons = $c->req->param('stock_polygons');
5722 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5724 my $polygon_objs = decode_json $stock_polygons;
5725 my %stock_ids;
5727 foreach my $stock_name (keys %$polygon_objs) {
5728 my $polygon = $polygon_objs->{$stock_name};
5729 my $last_point = pop @$polygon;
5730 if (scalar(@$polygon) != 4){
5731 $c->stash->{rest} = {error=>'Error: Polygon for '.$stock_name.' should be 4 long!'};
5732 $c->detach();
5734 $polygon_objs->{$stock_name} = $polygon;
5736 my $stock = $schema->resultset("Stock::Stock")->find({uniquename => $stock_name});
5737 if (!$stock) {
5738 $c->stash->{rest} = {error=>'Error: Stock name '.$stock_name.' does not exist in the database!'};
5739 $c->detach();
5741 $stock_ids{$stock_name} = $stock->stock_id;
5744 my $drone_run_band_plot_polygons_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
5745 my $previous_plot_polygons_rs = $schema->resultset('Project::Projectprop')->search({type_id=>$drone_run_band_plot_polygons_type_id, project_id=>$drone_run_band_project_id});
5746 if ($previous_plot_polygons_rs->count > 1) {
5747 die "There should not be more than one saved entry for plot polygons for a drone run band";
5750 my $save_stock_polygons;
5751 if ($previous_plot_polygons_rs->count > 0) {
5752 $save_stock_polygons = decode_json $previous_plot_polygons_rs->first->value;
5754 foreach my $stock_name (keys %$polygon_objs) {
5755 $save_stock_polygons->{$stock_name} = $polygon_objs->{$stock_name};
5758 my $drone_run_band_plot_polygons = $schema->resultset('Project::Projectprop')->update_or_create({
5759 type_id=>$drone_run_band_plot_polygons_type_id,
5760 project_id=>$drone_run_band_project_id,
5761 rank=>0,
5762 value=> encode_json($save_stock_polygons)
5765 key=>'projectprop_c1'
5768 $c->stash->{rest} = {success => 1, drone_run_band_template_id => $drone_run_band_plot_polygons->projectprop_id};
5771 sub drone_imagery_save_plot_polygons_template_separated : Path('/api/drone_imagery/save_plot_polygons_template_separated') : ActionClass('REST') { }
5772 sub drone_imagery_save_plot_polygons_template_separated_POST : Args(0) {
5773 my $self = shift;
5774 my $c = shift;
5775 print STDERR Dumper $c->req->params();
5776 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5777 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5778 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5779 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5780 my $stock_polygons = $c->req->param('stock_polygons');
5781 my $flight_pass_counter = $c->req->param('flight_pass_counter');
5783 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5785 my $polygon_objs = decode_json $stock_polygons;
5786 my %stock_ids;
5788 foreach my $stock_name (keys %$polygon_objs) {
5789 my $polygon = $polygon_objs->{$stock_name};
5790 my $last_point = pop @$polygon;
5791 if (scalar(@$polygon) != 4){
5792 $c->stash->{rest} = {error=>'Error: Polygon for '.$stock_name.' should be 4 long!'};
5793 $c->detach();
5795 $polygon_objs->{$stock_name} = $polygon;
5797 my $stock = $schema->resultset("Stock::Stock")->find({uniquename => $stock_name});
5798 if (!$stock) {
5799 $c->stash->{rest} = {error=>'Error: Stock name '.$stock_name.' does not exist in the database!'};
5800 $c->detach();
5802 $stock_ids{$stock_name} = $stock->stock_id;
5805 my $drone_run_band_plot_polygons_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons_separated', 'project_property')->cvterm_id();
5806 my $previous_plot_polygons_rs = $schema->resultset('Project::Projectprop')->search({type_id=>$drone_run_band_plot_polygons_type_id, project_id=>$drone_run_band_project_id});
5807 if ($previous_plot_polygons_rs->count > 1) {
5808 die "There should not be more than one saved entry for plot polygons for a drone run band";
5811 my $save_stock_polygons;
5812 if ($previous_plot_polygons_rs->count > 0) {
5813 $save_stock_polygons = decode_json $previous_plot_polygons_rs->first->value;
5815 foreach my $stock_name (keys %$polygon_objs) {
5816 $save_stock_polygons->{$flight_pass_counter}->{$stock_name} = $polygon_objs->{$stock_name};
5818 # print STDERR Dumper $save_stock_polygons;
5820 my $drone_run_band_plot_polygons = $schema->resultset('Project::Projectprop')->update_or_create({
5821 type_id=>$drone_run_band_plot_polygons_type_id,
5822 project_id=>$drone_run_band_project_id,
5823 rank=>0,
5824 value=> encode_json($save_stock_polygons)
5827 key=>'projectprop_c1'
5830 $c->stash->{rest} = {success => 1, drone_run_band_template_id => $drone_run_band_plot_polygons->projectprop_id};
5833 sub drone_imagery_denoise : Path('/api/drone_imagery/denoise') : ActionClass('REST') { }
5834 sub drone_imagery_denoise_GET : Args(0) {
5835 my $self = shift;
5836 my $c = shift;
5837 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5838 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5839 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
5840 my $image_id = $c->req->param('image_id');
5841 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5842 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5844 my $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
5845 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
5846 $archive_denoise_temp_image .= '.png';
5848 my $return = _perform_image_denoise($c, $schema, $metadata_schema, $image_id, $drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
5850 $c->stash->{rest} = $return;
5853 sub _perform_image_denoise {
5854 my $c = shift;
5855 my $schema = shift;
5856 my $metadata_schema = shift;
5857 my $image_id = shift;
5858 my $drone_run_band_project_id = shift;
5859 my $user_id = shift;
5860 my $user_name = shift;
5861 my $user_role = shift;
5862 my $archive_denoise_temp_image = shift;
5864 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
5865 my $image_url = $image->get_image_url("original");
5866 my $image_fullpath = $image->get_filename('original_converted', 'full');
5868 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/Denoise.py --image_path \''.$image_fullpath.'\' --outfile_path \''.$archive_denoise_temp_image.'\'';
5869 print STDERR Dumper $cmd;
5870 my $status = system("$cmd > /dev/null");
5872 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
5874 my $previous_denoised_images_search = CXGN::DroneImagery::ImagesSearch->new({
5875 bcs_schema=>$schema,
5876 project_image_type_id=>$linking_table_type_id,
5877 drone_run_band_project_id_list=>[$drone_run_band_project_id]
5879 my ($previous_denoised_result, $previous_denoised_total_count) = $previous_denoised_images_search->search();
5880 foreach (@$previous_denoised_result){
5881 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
5882 $previous_image->delete(); #Sets to obsolete
5885 my $denoised_image_fullpath;
5886 my $denoised_image_url;
5887 my $denoised_image_id;
5888 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
5889 my $md5checksum = $image->calculate_md5sum($archive_denoise_temp_image);
5890 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
5891 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
5892 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
5893 my $h = $schema->storage->dbh->prepare($q);
5894 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id);
5895 my ($saved_image_id) = $h->fetchrow_array();
5897 if ($saved_image_id) {
5898 print STDERR Dumper "Image $archive_denoise_temp_image has already been added to the database and will not be added again.";
5899 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
5900 $denoised_image_fullpath = $image->get_filename('original_converted', 'full');
5901 $denoised_image_url = $image->get_image_url('original');
5902 $denoised_image_id = $image->get_image_id();
5903 } else {
5904 $image->set_sp_person_id($user_id);
5905 my $ret = $image->process_image($archive_denoise_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
5906 $denoised_image_fullpath = $image->get_filename('original_converted', 'full');
5907 $denoised_image_url = $image->get_image_url('original');
5908 $denoised_image_id = $image->get_image_id();
5911 unlink($archive_denoise_temp_image);
5912 return {
5913 image_url => $image_url, image_fullpath => $image_fullpath, denoised_image_id => $denoised_image_id, denoised_image_url => $denoised_image_url, denoised_image_fullpath => $denoised_image_fullpath
5917 sub drone_imagery_remove_background_display : Path('/api/drone_imagery/remove_background_display') : ActionClass('REST') { }
5918 sub drone_imagery_remove_background_display_POST : Args(0) {
5919 my $self = shift;
5920 my $c = shift;
5921 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5922 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5923 my $image_id = $c->req->param('image_id');
5924 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5925 my $lower_threshold = $c->req->param('lower_threshold');
5926 my $upper_threshold = $c->req->param('upper_threshold');
5927 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5929 if (!$lower_threshold && !defined($lower_threshold)) {
5930 $c->stash->{rest} = {error => 'Please give a lower threshold'};
5931 $c->detach();
5933 if (!$upper_threshold && !defined($upper_threshold)) {
5934 $c->stash->{rest} = {error => 'Please give an upper threshold'};
5935 $c->detach();
5938 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
5939 my $image_url = $image->get_image_url("original");
5940 my $image_fullpath = $image->get_filename('original_converted', 'full');
5942 my $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
5943 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
5944 $archive_remove_background_temp_image .= '.png';
5946 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/RemoveBackground.py --image_path \''.$image_fullpath.'\' --outfile_path \''.$archive_remove_background_temp_image.'\' --lower_threshold '.$lower_threshold.' --upper_threshold '.$upper_threshold;
5947 print STDERR Dumper $cmd;
5948 my $status = system("$cmd > /dev/null");
5950 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
5951 $image->set_sp_person_id($user_id);
5952 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'background_removed_temporary_stitched_drone_imagery', 'project_md_image')->cvterm_id();
5954 my $previous_background_removed_temp_images_search = CXGN::DroneImagery::ImagesSearch->new({
5955 bcs_schema=>$schema,
5956 project_image_type_id=>$linking_table_type_id,
5957 drone_run_band_project_id_list=>[$drone_run_band_project_id]
5959 my ($previous_result, $previous_total_count) = $previous_background_removed_temp_images_search->search();
5960 foreach (@$previous_result){
5961 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
5962 $previous_image->delete(); #Sets to obsolete
5965 my $ret = $image->process_image($archive_remove_background_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
5966 my $removed_background_image_fullpath = $image->get_filename('original_converted', 'full');
5967 my $removed_background_image_url = $image->get_image_url('original');
5969 unlink($archive_remove_background_temp_image);
5970 $c->stash->{rest} = { image_url => $image_url, image_fullpath => $image_fullpath, removed_background_image_url => $removed_background_image_url, removed_background_image_fullpath => $removed_background_image_fullpath };
5973 sub drone_imagery_remove_background_save : Path('/api/drone_imagery/remove_background_save') : ActionClass('REST') { }
5974 sub drone_imagery_remove_background_save_POST : Args(0) {
5975 my $self = shift;
5976 my $c = shift;
5977 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
5978 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
5979 my $image_id = $c->req->param('image_id');
5980 my $image_type = $c->req->param('image_type');
5981 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
5982 my $lower_threshold = $c->req->param('lower_threshold');
5983 my $upper_threshold = $c->req->param('upper_threshold') || '255';
5984 my ($user_id, $user_name, $user_role) = _check_user_login($c);
5986 if (!$lower_threshold && !defined($lower_threshold)) {
5987 $c->stash->{rest} = {error => 'Please give a lower threshold'};
5988 $c->detach();
5990 if (!$upper_threshold && !defined($upper_threshold)) {
5991 $c->stash->{rest} = {error => 'Please give an upper threshold'};
5992 $c->detach();
5995 my $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
5996 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
5997 $archive_remove_background_temp_image .= '.png';
5999 my $return = _perform_image_background_remove_threshold($c, $schema, $image_id, $drone_run_band_project_id, $image_type, $lower_threshold, $upper_threshold, $user_id, $user_name, $user_role, $archive_remove_background_temp_image);
6001 $c->stash->{rest} = $return;
6004 sub _perform_image_background_remove_threshold {
6005 my $c = shift;
6006 my $schema = shift;
6007 my $image_id = shift;
6008 my $drone_run_band_project_id = shift;
6009 my $image_type = shift;
6010 my $lower_threshold = shift;
6011 my $upper_threshold = shift;
6012 my $user_id = shift;
6013 my $user_name = shift;
6014 my $user_role = shift;
6015 my $archive_remove_background_temp_image = shift;
6016 print STDERR "Background Remove Threshold Image Type: $image_type\n";
6018 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $image_type, 'project_md_image')->cvterm_id();
6019 my $drone_run_band_remove_background_threshold_type_id;
6020 my $imagery_attribute_map = CXGN::DroneImagery::ImageTypes::get_imagery_attribute_map();
6022 if ($imagery_attribute_map->{$image_type}->{name} eq 'threshold') {
6023 $drone_run_band_remove_background_threshold_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $imagery_attribute_map->{$image_type}->{key}, 'project_property')->cvterm_id();
6025 if (!$drone_run_band_remove_background_threshold_type_id) {
6026 die "Remove background threshold not found: $image_type\n";
6029 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
6030 my $image_url = $image->get_image_url("original");
6031 my $image_fullpath = $image->get_filename('original_converted', 'full');
6033 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/RemoveBackground.py --image_path \''.$image_fullpath.'\' --outfile_path \''.$archive_remove_background_temp_image.'\' --lower_threshold '.$lower_threshold.' --upper_threshold '.$upper_threshold;
6034 print STDERR Dumper $cmd;
6035 my $status = system("$cmd > /dev/null");
6037 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
6038 $image->set_sp_person_id($user_id);
6040 my $previous_background_removed_images_search = CXGN::DroneImagery::ImagesSearch->new({
6041 bcs_schema=>$schema,
6042 project_image_type_id=>$linking_table_type_id,
6043 drone_run_band_project_id_list=>[$drone_run_band_project_id]
6045 my ($previous_result, $previous_total_count) = $previous_background_removed_images_search->search();
6046 foreach (@$previous_result){
6047 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
6048 $previous_image->delete(); #Sets to obsolete
6051 my $ret = $image->process_image($archive_remove_background_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
6052 my $removed_background_image_fullpath = $image->get_filename('original_converted', 'full');
6053 my $removed_background_image_url = $image->get_image_url('original');
6054 my $removed_background_image_id = $image->get_image_id();
6056 my $drone_run_band_remove_background_threshold = $schema->resultset('Project::Projectprop')->update_or_create({
6057 type_id=>$drone_run_band_remove_background_threshold_type_id,
6058 project_id=>$drone_run_band_project_id,
6059 rank=>0,
6060 value=>"Lower Threshold:$lower_threshold. Upper Threshold:$upper_threshold"
6063 key=>'projectprop_c1'
6066 unlink($archive_remove_background_temp_image);
6067 return {
6068 image_url => $image_url, image_fullpath => $image_fullpath, removed_background_image_id => $removed_background_image_id, removed_background_image_url => $removed_background_image_url, removed_background_image_fullpath => $removed_background_image_fullpath
6072 sub drone_imagery_remove_background_percentage_save : Path('/api/drone_imagery/remove_background_percentage_save') : ActionClass('REST') { }
6073 sub drone_imagery_remove_background_percentage_save_POST : Args(0) {
6074 my $self = shift;
6075 my $c = shift;
6076 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6077 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
6078 my $image_id = $c->req->param('image_id');
6079 my $image_type_list = $c->req->param('image_type_list');
6080 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
6081 my $lower_threshold_percentage = $c->req->param('lower_threshold_percentage');
6082 my $upper_threshold_percentage = $c->req->param('upper_threshold_percentage');
6083 my ($user_id, $user_name, $user_role) = _check_user_login($c);
6085 if (!$lower_threshold_percentage && !defined($lower_threshold_percentage)) {
6086 $c->stash->{rest} = {error => 'Please give a lower threshold percentage'};
6087 $c->detach();
6089 if (!$upper_threshold_percentage && !defined($upper_threshold_percentage)) {
6090 $c->stash->{rest} = {error => 'Please give an upper threshold percentage'};
6091 $c->detach();
6094 my @image_types = split ',', $image_type_list;
6095 my @returns;
6096 foreach my $image_type (@image_types) {
6097 my $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
6098 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
6099 $archive_remove_background_temp_image .= '.png';
6101 my $return = _perform_image_background_remove_threshold_percentage($c, $schema, $image_id, $drone_run_band_project_id, $image_type, $lower_threshold_percentage, $upper_threshold_percentage, $user_id, $user_name, $user_role, $archive_remove_background_temp_image);
6102 push @returns, $return;
6105 $c->stash->{rest} = \@returns;
6108 sub _perform_image_background_remove_threshold_percentage {
6109 my $c = shift;
6110 my $schema = shift;
6111 my $image_id = shift;
6112 my $drone_run_band_project_id = shift;
6113 my $image_type = shift;
6114 my $lower_threshold_percentage = shift;
6115 my $upper_threshold_percentage = shift;
6116 my $user_id = shift;
6117 my $user_name = shift;
6118 my $user_role = shift;
6119 my $archive_remove_background_temp_image = shift;
6120 print STDERR "Remove background threshold percentage $image_type\n";
6122 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
6123 my $image_url = $image->get_image_url("original");
6124 my $image_fullpath = $image->get_filename('original_converted', 'full');
6126 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $image_type, 'project_md_image')->cvterm_id();
6127 my $drone_run_band_remove_background_threshold_type_id;
6128 my $imagery_attribute_map = CXGN::DroneImagery::ImageTypes::get_imagery_attribute_map();
6130 if ($imagery_attribute_map->{$image_type}->{name} eq 'threshold') {
6131 $drone_run_band_remove_background_threshold_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $imagery_attribute_map->{$image_type}->{key}, 'project_property')->cvterm_id();
6133 if (!$drone_run_band_remove_background_threshold_type_id) {
6134 die "Remove background threshold not found: $image_type\n";
6137 my $corresponding_channel = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_types_whole_images($schema)->{$linking_table_type_id}->{corresponding_channel};
6138 my $image_band_index_string = '';
6139 if (defined($corresponding_channel)) {
6140 $image_band_index_string = "--image_band_index $corresponding_channel";
6143 my $previous_background_removed_images_search = CXGN::DroneImagery::ImagesSearch->new({
6144 bcs_schema=>$schema,
6145 project_image_type_id=>$linking_table_type_id,
6146 drone_run_band_project_id_list=>[$drone_run_band_project_id]
6148 my ($previous_result, $previous_total_count) = $previous_background_removed_images_search->search();
6149 foreach (@$previous_result){
6150 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
6151 $previous_image->delete(); #Sets to obsolete
6154 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/RemoveBackgroundPercentage.py --image_path \''.$image_fullpath.'\' --outfile_path \''.$archive_remove_background_temp_image.'\' --lower_percentage \''.$lower_threshold_percentage.'\' --upper_percentage \''.$upper_threshold_percentage.'\' '.$image_band_index_string;
6155 print STDERR Dumper $cmd;
6156 my $status = system("$cmd > /dev/null");
6158 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
6159 $image->set_sp_person_id($user_id);
6160 my $ret = $image->process_image($archive_remove_background_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
6161 my $removed_background_image_fullpath = $image->get_filename('original_converted', 'full');
6162 my $removed_background_image_url = $image->get_image_url('original');
6163 my $removed_background_image_id = $image->get_image_id();
6165 my $drone_run_band_remove_background_threshold = $schema->resultset('Project::Projectprop')->update_or_create({
6166 type_id=>$drone_run_band_remove_background_threshold_type_id,
6167 project_id=>$drone_run_band_project_id,
6168 rank=>0,
6169 value=>"Lower Threshold Percentage:$lower_threshold_percentage. Upper Threshold Percentage:$upper_threshold_percentage"
6172 key=>'projectprop_c1'
6175 unlink($archive_remove_background_temp_image);
6176 return {
6177 image_url => $image_url, image_fullpath => $image_fullpath, removed_background_image_id => $removed_background_image_id, removed_background_image_url => $removed_background_image_url, removed_background_image_fullpath => $removed_background_image_fullpath
6181 sub get_drone_run_projects : Path('/api/drone_imagery/drone_runs') : ActionClass('REST') { }
6182 sub get_drone_run_projects_GET : Args(0) {
6183 my $self = shift;
6184 my $c = shift;
6185 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6186 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6187 my $checkbox_select_name = $c->req->param('select_checkbox_name');
6188 my $checkbox_select_all = $c->req->param('checkbox_select_all');
6189 my $field_trial_ids = $c->req->param('field_trial_ids');
6190 my $disable = $c->req->param('disable');
6192 my $project_start_date_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'project_start_date', 'project_property')->cvterm_id();
6193 my $design_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'design', 'project_property')->cvterm_id();
6194 my $drone_run_camera_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_camera_type', 'project_property')->cvterm_id();
6195 my $drone_run_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_project_type', 'project_property')->cvterm_id();
6196 my $drone_run_gdd_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_averaged_temperature_growing_degree_days', 'project_property')->cvterm_id();
6197 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6199 my $where_clause = '';
6200 if ($field_trial_ids) {
6201 $where_clause = ' WHERE field_trial.project_id IN ('.$field_trial_ids.') ';
6204 my $q = "SELECT project.project_id, project.name, project.description, drone_run_type.value, project_start_date.value, field_trial.project_id, field_trial.name, field_trial.description, drone_run_camera_type.value, drone_run_gdd.value FROM project
6205 JOIN projectprop AS project_start_date ON (project.project_id=project_start_date.project_id AND project_start_date.type_id=$project_start_date_type_id)
6206 LEFT JOIN projectprop AS drone_run_type ON (project.project_id=drone_run_type.project_id AND drone_run_type.type_id=$drone_run_project_type_cvterm_id)
6207 LEFT JOIN projectprop AS drone_run_camera_type ON (project.project_id=drone_run_camera_type.project_id AND drone_run_camera_type.type_id=$drone_run_camera_cvterm_id)
6208 LEFT JOIN projectprop AS drone_run_gdd ON (project.project_id=drone_run_gdd.project_id AND drone_run_gdd.type_id=$drone_run_gdd_cvterm_id)
6209 JOIN project_relationship ON (project.project_id = project_relationship.subject_project_id AND project_relationship.type_id=$project_relationship_type_id)
6210 JOIN project AS field_trial ON (field_trial.project_id=project_relationship.object_project_id)
6211 $where_clause
6212 ORDER BY project.project_id;";
6214 my $calendar_funcs = CXGN::Calendar->new({});
6216 my $h = $bcs_schema->storage->dbh()->prepare($q);
6217 $h->execute();
6218 my @result;
6219 while (my ($drone_run_project_id, $drone_run_project_name, $drone_run_project_description, $drone_run_type, $drone_run_date, $field_trial_project_id, $field_trial_project_name, $field_trial_project_description, $drone_run_camera_type, $drone_run_gdd) = $h->fetchrow_array()) {
6220 my @res;
6221 if ($checkbox_select_name){
6222 my $checkbox = "<input type='checkbox' name='$checkbox_select_name' value='$drone_run_project_id' ";
6223 if ($checkbox_select_all) {
6224 $checkbox .= "checked";
6226 if ($disable) {
6227 $checkbox .= "disabled";
6229 $checkbox .= ">";
6230 push @res, $checkbox;
6232 my $drone_run_date_display = $drone_run_date ? $calendar_funcs->display_start_date($drone_run_date) : '';
6233 push @res, (
6234 "<a href=\"/breeders_toolbox/trial/$drone_run_project_id\">$drone_run_project_name</a>",
6235 $drone_run_type,
6236 $drone_run_project_description,
6237 $drone_run_date_display,
6238 $drone_run_gdd,
6239 $drone_run_camera_type,
6240 "<a href=\"/breeders_toolbox/trial/$field_trial_project_id\">$field_trial_project_name</a>",
6241 $field_trial_project_description
6243 push @result, \@res;
6246 $c->stash->{rest} = { data => \@result };
6249 sub get_drone_run_projects_kv : Path('/api/drone_imagery/drone_runs_json') : ActionClass('REST') { }
6250 sub get_drone_run_projects_kv_GET : Args(0) {
6251 my $self = shift;
6252 my $c = shift;
6253 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6254 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6255 my $checkbox_select_all = $c->req->param('checkbox_select_all');
6256 my $field_trial_ids = $c->req->param('field_trial_ids');
6258 my $project_start_date_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'project_start_date', 'project_property')->cvterm_id();
6259 my $design_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'design', 'project_property')->cvterm_id();
6260 my $drone_run_camera_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_camera_type', 'project_property')->cvterm_id();
6261 my $drone_run_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_project_type', 'project_property')->cvterm_id();
6262 my $drone_run_gdd_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_averaged_temperature_growing_degree_days', 'project_property')->cvterm_id();
6263 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6265 my $where_clause = '';
6266 if ($field_trial_ids) {
6267 $where_clause = ' WHERE field_trial.project_id IN ('.$field_trial_ids.') ';
6270 my $q = "SELECT project.project_id, project.name, project.description, drone_run_type.value, project_start_date.value, field_trial.project_id, field_trial.name, field_trial.description, drone_run_camera_type.value, drone_run_gdd.value FROM project
6271 JOIN projectprop AS project_start_date ON (project.project_id=project_start_date.project_id AND project_start_date.type_id=$project_start_date_type_id)
6272 LEFT JOIN projectprop AS drone_run_type ON (project.project_id=drone_run_type.project_id AND drone_run_type.type_id=$drone_run_project_type_cvterm_id)
6273 LEFT JOIN projectprop AS drone_run_camera_type ON (project.project_id=drone_run_camera_type.project_id AND drone_run_camera_type.type_id=$drone_run_camera_cvterm_id)
6274 LEFT JOIN projectprop AS drone_run_gdd ON (project.project_id=drone_run_gdd.project_id AND drone_run_gdd.type_id=$drone_run_gdd_cvterm_id)
6275 JOIN project_relationship ON (project.project_id = project_relationship.subject_project_id AND project_relationship.type_id=$project_relationship_type_id)
6276 JOIN project AS field_trial ON (field_trial.project_id=project_relationship.object_project_id)
6277 $where_clause
6278 ORDER BY project.project_id;";
6280 my $calendar_funcs = CXGN::Calendar->new({});
6282 my $h = $bcs_schema->storage->dbh()->prepare($q);
6283 $h->execute();
6284 my @result;
6285 while (my ($drone_run_project_id, $drone_run_project_name, $drone_run_project_description, $drone_run_type, $drone_run_date, $field_trial_project_id, $field_trial_project_name, $field_trial_project_description, $drone_run_camera_type, $drone_run_gdd) = $h->fetchrow_array()) {
6286 my @res;
6287 my $drone_run_date_display = $drone_run_date ? $calendar_funcs->display_start_date($drone_run_date) : '';
6288 my %data = (
6289 "Drone Run Name" => $drone_run_project_name,
6290 "Drone Run Type" => $drone_run_type,
6291 "Drone Run Description" => $drone_run_project_description,
6292 "Imaging Date" => $drone_run_date_display,
6293 "Drone Run GDD" => $drone_run_gdd,
6294 "Camera Type" => $drone_run_camera_type,
6295 "Field Trial Name" => $field_trial_project_name,
6296 "Field Trial Description" => $field_trial_project_description
6298 push @result,\%data;
6301 $c->stash->{rest} = { data => \@result };
6305 sub get_plot_polygon_types_images : Path('/api/drone_imagery/plot_polygon_types_images') : ActionClass('REST') { }
6306 sub get_plot_polygon_types_images_GET : Args(0) {
6307 my $self = shift;
6308 my $c = shift;
6309 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6310 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6311 my $checkbox_select_name = $c->req->param('select_checkbox_name');
6312 my $checkbox_select_all = $c->req->param('checkbox_select_all');
6313 my $field_trial_ids = $c->req->param('field_trial_ids');
6314 my $stock_ids = $c->req->param('stock_ids');
6315 my $field_trial_images_only = $c->req->param('field_trial_images_only');
6316 my $drone_run_ids = $c->req->param('drone_run_ids') ? decode_json $c->req->param('drone_run_ids') : [];
6317 my $drone_run_band_ids = $c->req->param('drone_run_band_ids') ? decode_json $c->req->param('drone_run_band_ids') : [];
6319 my $drone_run_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_project_type', 'project_property')->cvterm_id();
6320 my $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
6321 my $drone_run_field_trial_project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6322 my $drone_run_band_drone_run_project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
6323 my $project_image_type_id_list;
6324 if (!$field_trial_images_only) {
6325 $project_image_type_id_list = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($bcs_schema);
6327 else {
6328 $project_image_type_id_list = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_types_whole_images($bcs_schema);
6330 my $project_image_type_id_list_sql = join ",", (keys %$project_image_type_id_list);
6332 my @where_clause;
6333 push @where_clause, "project_md_image.type_id in ($project_image_type_id_list_sql)";
6335 if ($field_trial_ids) {
6336 push @where_clause, "field_trial.project_id IN ($field_trial_ids)";
6338 if ($drone_run_ids && scalar(@$drone_run_ids)>0) {
6339 my $sql = join ("," , @$drone_run_ids);
6340 push @where_clause, "drone_run.project_id IN ($sql)";
6342 if ($drone_run_band_ids && scalar(@$drone_run_band_ids)>0) {
6343 my $sql = join ("," , @$drone_run_band_ids);
6344 push @where_clause, "drone_run_band.project_id IN ($sql)";
6346 my $stock_image_join = '';
6347 if ($stock_ids) {
6348 my @stock_ids_array = split ',', $stock_ids;
6349 my $stock_id_sql = join (",", @stock_ids_array);
6350 $stock_image_join = 'JOIN metadata.md_image AS md_image ON (md_image.image_id=project_md_image.image_id) JOIN phenome.stock_image AS stock_image ON (md_image.image_id=stock_image.image_id)';
6351 push @where_clause, "stock_image.stock_id IN ($stock_id_sql)";
6353 my $where_clause = scalar(@where_clause)>0 ? " WHERE " . (join (" AND " , @where_clause)) : '';
6355 my $q = "SELECT drone_run_band.project_id, drone_run_band.name, drone_run_band.description, drone_run_band_type.value, drone_run.project_id, drone_run.name, drone_run.description, drone_run_type.value, field_trial.project_id, field_trial.name, field_trial.description, project_md_image.type_id, project_md_image_type.name, project_md_image.image_id
6356 FROM project AS drone_run_band
6357 LEFT JOIN projectprop AS drone_run_band_type ON (drone_run_band.project_id=drone_run_band_type.project_id AND drone_run_band_type.type_id=$drone_run_band_project_type_cvterm_id)
6358 JOIN project_relationship AS drone_run_band_rel ON (drone_run_band.project_id = drone_run_band_rel.subject_project_id AND drone_run_band_rel.type_id=$drone_run_band_drone_run_project_relationship_type_id)
6359 JOIN project AS drone_run ON (drone_run.project_id=drone_run_band_rel.object_project_id)
6360 LEFT JOIN projectprop AS drone_run_type ON (drone_run.project_id=drone_run_type.project_id AND drone_run_type.type_id=$drone_run_project_type_cvterm_id)
6361 JOIN project_relationship AS field_trial_rel ON (drone_run.project_id = field_trial_rel.subject_project_id AND field_trial_rel.type_id=$drone_run_field_trial_project_relationship_type_id)
6362 JOIN project AS field_trial ON (field_trial.project_id=field_trial_rel.object_project_id)
6363 JOIN phenome.project_md_image AS project_md_image ON (drone_run_band.project_id = project_md_image.project_id)
6364 JOIN cvterm AS project_md_image_type ON (project_md_image_type.cvterm_id = project_md_image.type_id)
6365 $stock_image_join
6366 $where_clause
6367 GROUP BY drone_run_band.project_id, drone_run_band.name, drone_run_band.description, drone_run_band_type.value, drone_run.project_id, drone_run.name, drone_run.description, drone_run_type.value, field_trial.project_id, field_trial.name, field_trial.description, project_md_image.type_id, project_md_image_type.name, project_md_image.image_id
6368 ORDER BY drone_run_band.project_id;";
6370 my $h = $bcs_schema->storage->dbh()->prepare($q);
6371 $h->execute();
6372 my @result;
6373 while (my ($drone_run_band_project_id, $drone_run_band_project_name, $drone_run_band_project_description, $drone_run_band_type, $drone_run_project_id, $drone_run_project_name, $drone_run_project_description, $drone_run_type, $field_trial_project_id, $field_trial_project_name, $field_trial_project_description, $project_md_image_type_id, $project_md_image_type_name, $image_id) = $h->fetchrow_array()) {
6374 my @res;
6375 if ($checkbox_select_name){
6376 my $input = "<input type='checkbox' name='$checkbox_select_name' value='$image_id' ";
6377 if ($checkbox_select_all) {
6378 $input .= "checked";
6380 $input .= ">";
6381 push @res, $input;
6383 my $image = SGN::Image->new($bcs_schema->storage->dbh, $image_id, $c);
6384 my $image_id = $image->get_image_id;
6385 my $image_name = $image->get_name() || '';
6386 my $image_description = $image->get_description() || '';
6387 my $image_img = $image->get_image_url("medium");
6388 my $original_img = $image->get_image_url("large");
6389 my $small_image = $image->get_image_url("tiny");
6390 my $image_page = "/image/view/$image_id";
6391 my $colorbox = qq|<a href="$image_img" title="<a href=$image_page>Go to image page ($image_name)</a>" class="image_search_group" rel="gallery-figures"><img src="$small_image" width="40" height="30" border="0" alt="$image_description" /></a>|;
6393 push @res, (
6394 $colorbox,
6395 "<a href=\"/breeders_toolbox/trial/$field_trial_project_id\">$field_trial_project_name</a>",
6396 $drone_run_project_name,
6397 $drone_run_band_project_name,
6398 $drone_run_band_type,
6399 $project_md_image_type_name
6401 push @result, \@res;
6404 $c->stash->{rest} = { data => \@result };
6407 sub _get_standard_4_polygon_types {
6408 return (
6409 'observation_unit_polygon_rgb_imagery' => 1, #77976, 77689
6410 'observation_unit_polygon_nrn_imagery' => 1, #77980, 77693
6411 'observation_unit_polygon_nren_imagery' => 1, #77981, 77694
6412 # 'observation_unit_polygon_green_background_removed_threshold_imagery' => 1, #77995, 77708
6413 # 'observation_unit_polygon_red_background_removed_threshold_imagery' => 1, #77996, 77709
6414 # 'observation_unit_polygon_red_edge_background_removed_threshold_imagery' => 1, #77997, 77710
6415 # 'observation_unit_polygon_green_imagery' => 1, #77983, 77696
6416 # 'observation_unit_polygon_red_imagery' => 1, #77984, 77697
6417 # 'observation_unit_polygon_red_edge_imagery' => 1, #77985, 77698
6418 # 'observation_unit_polygon_nir_imagery' => 1, #77986, 77699
6419 'observation_unit_polygon_nir_background_removed_threshold_imagery' => 1, #77998, 77711
6420 #'observation_unit_polygon_vari_imagery' => 1, #78003, 77716
6421 #'observation_unit_polygon_ndvi_imagery' => 1, #78004, 77717
6422 # 'observation_unit_polygon_ndre_imagery' => 1, #78005, 77718
6423 #'observation_unit_polygon_background_removed_ndre_imagery' => 1, #78009, 77722
6427 sub _get_standard_9_polygon_types {
6428 return (
6429 'observation_unit_polygon_rgb_imagery' => 1, #77976, 77689
6430 'observation_unit_polygon_nrn_imagery' => 1, #77980, 77693
6431 'observation_unit_polygon_nren_imagery' => 1, #77981, 77694
6432 # 'observation_unit_polygon_green_background_removed_threshold_imagery' => 1, #77995, 77708
6433 # 'observation_unit_polygon_red_background_removed_threshold_imagery' => 1, #77996, 77709
6434 'observation_unit_polygon_red_edge_background_removed_threshold_imagery' => 1, #77997, 77710
6435 # 'observation_unit_polygon_green_imagery' => 1, #77983, 77696
6436 # 'observation_unit_polygon_red_imagery' => 1, #77984, 77697
6437 # 'observation_unit_polygon_red_edge_imagery' => 1, #77985, 77698
6438 # 'observation_unit_polygon_nir_imagery' => 1, #77986, 77699
6439 'observation_unit_polygon_nir_background_removed_threshold_imagery' => 1, #77998, 77711
6440 'observation_unit_polygon_vari_imagery' => 1, #78003, 77716
6441 'observation_unit_polygon_ndvi_imagery' => 1, #78004, 77717
6442 'observation_unit_polygon_ndre_imagery' => 1, #78005, 77718
6443 'observation_unit_polygon_tgi_imagery' => 1, #78005, 77718
6444 #'observation_unit_polygon_background_removed_ndre_imagery' => 1, #78009, 77722
6448 sub _get_standard_ndvi_ndre_polygon_types {
6449 return (
6450 'observation_unit_polygon_red_imagery' => 1, #77984, 77697
6451 'observation_unit_polygon_red_edge_imagery' => 1, #77985, 77698
6452 'observation_unit_polygon_nir_imagery' => 1, #77986, 77699
6456 sub get_plot_polygon_types : Path('/api/drone_imagery/plot_polygon_types') : ActionClass('REST') { }
6457 sub get_plot_polygon_types_GET : Args(0) {
6458 my $self = shift;
6459 my $c = shift;
6460 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6461 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6462 my $checkbox_select_name = $c->req->param('select_checkbox_name');
6463 my $checkbox_select_all = $c->req->param('checkbox_select_all');
6464 my $checkbox_select_standard_ndvi_ndre = $c->req->param('checkbox_select_standard_ndvi_ndre');
6465 my $checkbox_select_standard_4 = $c->req->param('checkbox_select_standard_4');
6466 my $checkbox_select_standard_9 = $c->req->param('checkbox_select_standard_9');
6467 my $field_trial_ids = $c->req->param('field_trial_ids');
6468 my $stock_ids = $c->req->param('stock_ids');
6469 my $field_trial_images_only = $c->req->param('field_trial_images_only');
6470 my $field_trial_images_only_2d = $c->req->param('field_trial_images_only_2d');
6471 my $drone_run_ids = $c->req->param('drone_run_ids') ? decode_json $c->req->param('drone_run_ids') : [];
6472 my $drone_run_band_ids = $c->req->param('drone_run_band_ids') ? decode_json $c->req->param('drone_run_band_ids') : [];
6474 my $drone_run_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_project_type', 'project_property')->cvterm_id();
6475 my $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
6476 my $drone_run_field_trial_project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6477 my $drone_run_band_drone_run_project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
6478 my $project_image_type_id_list_sql;
6479 if ($field_trial_images_only_2d) {
6480 my $project_image_type_id_list = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($bcs_schema);
6481 my @image_type_ids;
6482 while (my ($key, $val) = each %$project_image_type_id_list) {
6483 if (scalar(@{$val->{channels}}) == 1) {
6484 push @image_type_ids, $key;
6487 $project_image_type_id_list_sql = join ",", @image_type_ids;
6489 elsif (!$field_trial_images_only) {
6490 my $project_image_type_id_list = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($bcs_schema);
6491 $project_image_type_id_list_sql = join ",", (keys %$project_image_type_id_list);
6493 else {
6494 my $project_image_type_id_list = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_types_whole_images($bcs_schema);
6495 $project_image_type_id_list_sql = join ",", (keys %$project_image_type_id_list);
6498 my %standard_ndvi_ndre = _get_standard_ndvi_ndre_polygon_types();
6499 my %standard_4 = _get_standard_4_polygon_types();
6500 my %standard_9 = _get_standard_9_polygon_types();
6502 my @where_clause;
6503 push @where_clause, "project_md_image.type_id in ($project_image_type_id_list_sql)";
6505 if ($field_trial_ids) {
6506 push @where_clause, "field_trial.project_id IN ($field_trial_ids)";
6508 if ($drone_run_ids && scalar(@$drone_run_ids)>0) {
6509 my $sql = join ("," , @$drone_run_ids);
6510 push @where_clause, "drone_run.project_id IN ($sql)";
6512 if ($drone_run_band_ids && scalar(@$drone_run_band_ids)>0) {
6513 my $sql = join ("," , @$drone_run_band_ids);
6514 push @where_clause, "drone_run_band.project_id IN ($sql)";
6516 my $stock_image_join = '';
6517 if ($stock_ids) {
6518 my @stock_ids_array = split ',', $stock_ids;
6519 my $stock_id_sql = join (",", @stock_ids_array);
6520 $stock_image_join = 'JOIN metadata.md_image AS md_image ON (md_image.image_id=project_md_image.image_id) JOIN phenome.stock_image AS stock_image ON (md_image.image_id=stock_image.image_id)';
6521 push @where_clause, "stock_image.stock_id IN ($stock_id_sql)";
6523 my $where_clause = scalar(@where_clause)>0 ? " WHERE " . (join (" AND " , @where_clause)) : '';
6525 my $q = "SELECT drone_run_band.project_id, drone_run_band.name, drone_run_band.description, drone_run_band_type.value, drone_run.project_id, drone_run.name, drone_run.description, drone_run_type.value, field_trial.project_id, field_trial.name, field_trial.description, project_md_image.type_id, project_md_image_type.name, count(project_md_image.image_id)
6526 FROM project AS drone_run_band
6527 LEFT JOIN projectprop AS drone_run_band_type ON (drone_run_band.project_id=drone_run_band_type.project_id AND drone_run_band_type.type_id=$drone_run_band_project_type_cvterm_id)
6528 JOIN project_relationship AS drone_run_band_rel ON (drone_run_band.project_id = drone_run_band_rel.subject_project_id AND drone_run_band_rel.type_id=$drone_run_band_drone_run_project_relationship_type_id)
6529 JOIN project AS drone_run ON (drone_run.project_id=drone_run_band_rel.object_project_id)
6530 LEFT JOIN projectprop AS drone_run_type ON (drone_run.project_id=drone_run_type.project_id AND drone_run_type.type_id=$drone_run_project_type_cvterm_id)
6531 JOIN project_relationship AS field_trial_rel ON (drone_run.project_id = field_trial_rel.subject_project_id AND field_trial_rel.type_id=$drone_run_field_trial_project_relationship_type_id)
6532 JOIN project AS field_trial ON (field_trial.project_id=field_trial_rel.object_project_id)
6533 JOIN phenome.project_md_image AS project_md_image ON (drone_run_band.project_id = project_md_image.project_id)
6534 JOIN cvterm AS project_md_image_type ON (project_md_image_type.cvterm_id = project_md_image.type_id)
6535 $stock_image_join
6536 $where_clause
6537 GROUP BY drone_run_band.project_id, drone_run_band.name, drone_run_band.description, drone_run_band_type.value, drone_run.project_id, drone_run.name, drone_run.description, drone_run_type.value, field_trial.project_id, field_trial.name, field_trial.description, project_md_image.type_id, project_md_image_type.name
6538 ORDER BY drone_run_band.project_id;";
6540 my $h = $bcs_schema->storage->dbh()->prepare($q);
6541 $h->execute();
6542 my @result;
6543 while (my ($drone_run_band_project_id, $drone_run_band_project_name, $drone_run_band_project_description, $drone_run_band_type, $drone_run_project_id, $drone_run_project_name, $drone_run_project_description, $drone_run_type, $field_trial_project_id, $field_trial_project_name, $field_trial_project_description, $project_md_image_type_id, $project_md_image_type_name, $plot_polygon_count) = $h->fetchrow_array()) {
6544 my @res;
6545 if ($checkbox_select_name){
6546 my $input = "<input type='checkbox' name='$checkbox_select_name' value='$project_md_image_type_id' ";
6547 if ($checkbox_select_all) {
6548 $input .= "checked";
6550 elsif ($checkbox_select_standard_4) {
6551 if (exists($standard_4{$project_md_image_type_name})) {
6552 $input .= "checked disabled";
6554 else {
6555 $input .= "disabled";
6558 elsif ($checkbox_select_standard_9) {
6559 if (exists($standard_9{$project_md_image_type_name})) {
6560 $input .= "checked disabled";
6562 else {
6563 $input .= "disabled";
6566 elsif ($checkbox_select_standard_ndvi_ndre) {
6567 if (exists($standard_ndvi_ndre{$project_md_image_type_name})) {
6568 $input .= "checked disabled";
6570 else {
6571 $input .= "disabled";
6574 $input .= ">";
6575 push @res, $input;
6577 push @res, (
6578 "<a href=\"/breeders_toolbox/trial/$field_trial_project_id\">$field_trial_project_name</a>",
6579 $drone_run_project_name,
6580 $drone_run_band_project_name,
6581 $drone_run_band_type,
6582 $project_md_image_type_name,
6583 $plot_polygon_count
6585 push @result, \@res;
6588 $c->stash->{rest} = { data => \@result };
6592 # jQuery('#drone_image_upload_drone_bands_table').DataTable({
6593 # destroy : true,
6594 # ajax : '/api/drone_imagery/drone_run_bands?select_checkbox_name=upload_drone_imagery_drone_run_band_select&drone_run_project_id='+drone_run_project_id
6595 # });
6596 sub get_drone_run_band_projects : Path('/api/drone_imagery/drone_run_bands') : ActionClass('REST') { }
6597 sub get_drone_run_band_projects_GET : Args(0) {
6598 my $self = shift;
6599 my $c = shift;
6600 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6601 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6602 my $checkbox_select_name = $c->req->param('select_checkbox_name');
6603 my $field_trial_id = $c->req->param('field_trial_id');
6604 my $drone_run_project_id = $c->req->param('drone_run_project_id');
6605 my $drone_run_project_ids = $c->req->param('drone_run_project_ids') ? decode_json $c->req->param('drone_run_project_ids') : [];
6606 my $exclude_drone_run_band_project_id = $c->req->param('exclude_drone_run_band_project_id') || 0;
6607 my $select_all = $c->req->param('select_all') || 0;
6608 my $disable = $c->req->param('disable') || 0;
6609 # print STDERR Dumper $c->req->params();
6611 my $project_start_date_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'project_start_date', 'project_property')->cvterm_id();
6612 my $design_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'design', 'project_property')->cvterm_id();
6613 my $drone_run_band_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
6614 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6615 my $drone_run_band_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
6617 my $where_clause = '';
6618 if ($drone_run_project_id) {
6619 $where_clause = ' WHERE project.project_id = '.$drone_run_project_id.' ';
6621 if ($drone_run_project_ids && scalar(@$drone_run_project_ids)>0) {
6622 my $sql = join ",", @$drone_run_project_ids;
6623 $where_clause = ' WHERE project.project_id IN ('.$sql.') ';
6626 my $q = "SELECT drone_run_band.project_id, drone_run_band.name, drone_run_band.description, drone_run_band_type.value, project.project_id, project.name, project.description, project_start_date.value, field_trial.project_id, field_trial.name, field_trial.description
6627 FROM project AS drone_run_band
6628 JOIN projectprop AS drone_run_band_type ON(drone_run_band.project_id=drone_run_band_type.project_id AND drone_run_band_type.type_id=$drone_run_band_type_cvterm_id)
6629 JOIN project_relationship AS drone_run_band_rel ON(drone_run_band.project_id=drone_run_band_rel.subject_project_id AND drone_run_band_rel.type_id=$drone_run_band_relationship_type_id)
6630 JOIN project ON (drone_run_band_rel.object_project_id = project.project_id)
6631 JOIN projectprop AS project_start_date ON (project.project_id=project_start_date.project_id AND project_start_date.type_id=$project_start_date_type_id)
6632 JOIN project_relationship ON (project.project_id = project_relationship.subject_project_id AND project_relationship.type_id=$project_relationship_type_id)
6633 JOIN project AS field_trial ON (field_trial.project_id=project_relationship.object_project_id)
6634 $where_clause
6635 ORDER BY project.project_id;";
6637 my $calendar_funcs = CXGN::Calendar->new({});
6639 my $h = $bcs_schema->storage->dbh()->prepare($q);
6640 $h->execute();
6641 my @result;
6642 while (my ($drone_run_band_project_id, $drone_run_band_name, $drone_run_band_description, $drone_run_band_type, $drone_run_project_id, $drone_run_project_name, $drone_run_project_description, $drone_run_date, $field_trial_project_id, $field_trial_project_name, $field_trial_project_description) = $h->fetchrow_array()) {
6643 my @res;
6644 if ($drone_run_band_project_id != $exclude_drone_run_band_project_id) {
6645 my $background_removed_threshold_type;
6646 if ($drone_run_band_type eq 'Blue (450-520nm)') {
6647 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_blue';
6649 elsif ($drone_run_band_type eq 'Green (515-600nm)') {
6650 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_green';
6652 elsif ($drone_run_band_type eq 'Red (600-690nm)') {
6653 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_red';
6655 elsif ($drone_run_band_type eq 'Red Edge (690-750nm)') {
6656 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_red_edge';
6658 elsif ($drone_run_band_type eq 'NIR (780-3000nm)') {
6659 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_nir';
6661 elsif ($drone_run_band_type eq 'MIR (3000-50000nm)') {
6662 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_mir';
6664 elsif ($drone_run_band_type eq 'FIR (50000-1000000nm)') {
6665 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_fir';
6667 elsif ($drone_run_band_type eq 'Thermal IR (9000-14000nm)') {
6668 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_tir';
6670 elsif ($drone_run_band_type eq 'Black and White Image') {
6671 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_bw';
6673 elsif ($drone_run_band_type eq 'RGB Color Image') {
6674 $background_removed_threshold_type = 'threshold_background_removed_stitched_drone_imagery_rgb_channel_1,threshold_background_removed_stitched_drone_imagery_rgb_channel_2,threshold_background_removed_stitched_drone_imagery_rgb_channel_3';
6676 if ($checkbox_select_name){
6677 my $checked = $select_all ? 'checked' : '';
6678 my $disabled = $disable ? 'disabled' : '';
6679 my $extra_data = $background_removed_threshold_type ? "data-background_removed_threshold_type='$background_removed_threshold_type'" : '';
6680 push @res, "<input type='checkbox' name='$checkbox_select_name' value='$drone_run_band_project_id' $extra_data $checked $disabled>";
6682 my $drone_run_date_display = $drone_run_date ? $calendar_funcs->display_start_date($drone_run_date) : '';
6683 push @res, (
6684 $drone_run_band_name,
6685 $drone_run_band_description,
6686 $drone_run_band_type,
6687 $drone_run_project_name,
6688 $drone_run_project_description,
6689 $drone_run_date_display,
6690 "<a href=\"/breeders_toolbox/trial/$field_trial_project_id\">$field_trial_project_name</a>",
6691 $field_trial_project_description
6693 push @result, \@res;
6697 $c->stash->{rest} = { data => \@result };
6700 sub get_week_after_planting_date : Path('/api/drone_imagery/get_weeks_after_planting_date') : ActionClass('REST') { }
6701 sub get_week_after_planting_date_GET : Args(0) {
6702 my $self = shift;
6703 my $c = shift;
6704 $c->response->headers->header( "Access-Control-Allow-Origin" => '*' );
6705 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6706 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6707 my $drone_run_project_id = $c->req->param('drone_run_project_id');
6709 $c->stash->{rest} = _perform_get_weeks_drone_run_after_planting($schema, $drone_run_project_id);
6712 sub _perform_get_weeks_drone_run_after_planting {
6713 my $schema = shift;
6714 my $drone_run_project_id = shift;
6716 my $project_start_date_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'project_start_date', 'project_property')->cvterm_id();
6717 my $drone_run_base_date_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_base_date', 'project_property')->cvterm_id();
6718 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6719 my $calendar_funcs = CXGN::Calendar->new({});
6721 my $drone_run_date_rs = $schema->resultset('Project::Projectprop')->search({project_id=>$drone_run_project_id, type_id=>$project_start_date_type_id});
6722 if ($drone_run_date_rs->count != 1) {
6723 return { error => 'There is no drone run date saved! This should not be possible, please contact us'};
6725 my $drone_run_date = $drone_run_date_rs->first->value;
6726 my $drone_date = $calendar_funcs->display_start_date($drone_run_date);
6728 my $drone_run_base_date_rs = $schema->resultset('Project::Projectprop')->search({project_id=>$drone_run_project_id, type_id=>$drone_run_base_date_type_id});
6729 my $drone_run_base_date;
6730 if ($drone_run_base_date_rs->count == 1) {
6731 $drone_run_base_date = $calendar_funcs->display_start_date($drone_run_base_date_rs->first->value);
6734 my $field_trial_rs = $schema->resultset("Project::ProjectRelationship")->search({subject_project_id=>$drone_run_project_id, type_id=>$project_relationship_type_id});
6735 if ($field_trial_rs->count != 1) {
6736 return { drone_run_date => $drone_date, error => 'There is no field trial saved to the drone run! This should not be possible, please contact us'};
6738 my $trial_id = $field_trial_rs->first->object_project_id;
6739 my $trial = CXGN::Trial->new( { bcs_schema => $schema, trial_id => $trial_id });
6740 my $planting_date = $trial->get_planting_date();
6742 print STDERR $drone_date."\n";
6743 my $drone_date_time_object = Time::Piece->strptime($drone_date, "%Y-%B-%d %H:%M:%S");
6744 my $drone_date_full_calendar_datetime = $drone_date_time_object->strftime("%Y/%m/%d %H:%M:%S");
6746 if (!$planting_date) {
6747 return { drone_run_date => $drone_date, drone_run_date_calendar => $drone_date_full_calendar_datetime, error => 'The planting date is not set on the field trial, so we could not get the time of this flight automaticaly'};
6750 print STDERR "$planting_date\n";
6751 print STDERR "$drone_run_base_date\n";
6752 my $planting_date_time_object = Time::Piece->strptime($planting_date, "%Y-%B-%d");
6753 my $planting_date_full_calendar_datetime = $planting_date_time_object->strftime("%Y/%m/%d %H:%M:%S");
6754 my $time_diff;
6755 if ($drone_run_base_date) {
6756 my $imaging_event_base_date_time_object = Time::Piece->strptime($drone_run_base_date, "%Y-%B-%d %H:%M:%S");
6757 $time_diff = $drone_date_time_object - $imaging_event_base_date_time_object;
6759 else {
6760 $time_diff = $drone_date_time_object - $planting_date_time_object;
6762 my $time_diff_weeks = $time_diff->weeks;
6763 my $time_diff_days = $time_diff->days;
6764 my $time_diff_hours = $time_diff->hours;
6765 my $rounded_time_diff_weeks = round($time_diff_weeks);
6766 if ($rounded_time_diff_weeks == 0) {
6767 $rounded_time_diff_weeks = 1;
6770 my $week_term_string = "week $rounded_time_diff_weeks";
6771 my $q = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
6772 my $h = $schema->storage->dbh()->prepare($q);
6773 $h->execute($week_term_string, 'cxgn_time_ontology');
6774 my ($week_cvterm_id) = $h->fetchrow_array();
6776 if (!$week_cvterm_id) {
6777 my $new_week_term = $schema->resultset("Cv::Cvterm")->create_with({
6778 name => $week_term_string,
6779 cv => 'cxgn_time_ontology'
6781 $week_cvterm_id = $new_week_term->cvterm_id();
6784 my $day_term_string = "day $time_diff_days";
6785 $h->execute($day_term_string, 'cxgn_time_ontology');
6786 my ($day_cvterm_id) = $h->fetchrow_array();
6788 if (!$day_cvterm_id) {
6789 my $new_day_term = $schema->resultset("Cv::Cvterm")->create_with({
6790 name => $day_term_string,
6791 cv => 'cxgn_time_ontology'
6793 $day_cvterm_id = $new_day_term->cvterm_id();
6796 if (!$week_cvterm_id) {
6797 return { planting_date => $planting_date, planting_date_calendar => $planting_date_full_calendar_datetime, drone_run_date => $drone_date, drone_run_date_calendar => $drone_date_full_calendar_datetime, time_difference_weeks => $time_diff_weeks, time_difference_days => $time_diff_days, rounded_time_difference_weeks => $rounded_time_diff_weeks, error => 'The time ontology term was not found automatically! Maybe the field trial planting date or the drone run date are not correct in the database? This should not be possible, please contact us.'};
6800 my $week_term = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $week_cvterm_id, 'extended');
6801 my $day_term = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $day_cvterm_id, 'extended');
6803 return { planting_date => $planting_date, planting_date_calendar => $planting_date_full_calendar_datetime, drone_run_date => $drone_date, drone_run_date_calendar => $drone_date_full_calendar_datetime, time_difference_weeks => $time_diff_weeks, time_difference_days => $time_diff_days, rounded_time_difference_weeks => $rounded_time_diff_weeks, time_ontology_week_cvterm_id => $week_cvterm_id, time_ontology_week_term => $week_term, time_ontology_day_cvterm_id => $day_cvterm_id, time_ontology_day_term => $day_term};
6806 sub standard_process_apply : Path('/api/drone_imagery/standard_process_apply') : ActionClass('REST') { }
6807 sub standard_process_apply_POST : Args(0) {
6808 my $self = shift;
6809 my $c = shift;
6810 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
6811 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
6812 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
6813 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema', undef, $sp_person_id);
6814 my $apply_drone_run_band_project_ids_input = decode_json $c->req->param('apply_drone_run_band_project_ids');
6815 my $field_trial_id = $c->req->param('field_trial_id');
6816 my $drone_run_band_project_id_input = $c->req->param('drone_run_band_project_id');
6817 my $drone_run_project_id_input = $c->req->param('drone_run_project_id');
6818 my $time_cvterm_id_input = $c->req->param('time_cvterm_id');
6819 my $vegetative_indices = decode_json $c->req->param('vegetative_indices');
6820 my $phenotype_methods = $c->req->param('phenotype_types') ? decode_json $c->req->param('phenotype_types') : ['zonal'];
6821 my $standard_process_type = $c->req->param('standard_process_type');
6822 my $camera_rig_apply = $c->req->param('apply_to_all_drone_runs_from_same_camera_rig') eq 'Yes' ? 1 : 0;
6823 my ($user_id, $user_name, $user_role) = _check_user_login($c);
6825 my $rotate_angle_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_rotate_angle', 'project_property')->cvterm_id();
6826 my $cropping_polygon_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_cropped_polygon', 'project_property')->cvterm_id();
6827 my $plot_polygon_template_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
6828 my $drone_run_field_trial_project_relationship_type_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
6829 my $drone_run_drone_run_band_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
6830 my $drone_run_camera_rig_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_camera_rig_description', 'project_property')->cvterm_id();
6831 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
6832 my $processed_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_completed', 'project_property')->cvterm_id();
6833 my $processed_minimal_vi_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_vi_completed', 'project_property')->cvterm_id();
6834 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'stitched_drone_imagery', 'project_md_image')->cvterm_id();
6835 my $drone_run_band_type_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
6837 my @apply_projects;
6838 if ($camera_rig_apply) {
6839 my $q = "SELECT value FROM projectprop WHERE project_id = ? AND type_id = $drone_run_camera_rig_cvterm_id;";
6840 my $h = $bcs_schema->storage->dbh()->prepare($q);
6841 $h->execute($drone_run_project_id_input);
6842 my ($camera_rig) = $h->fetchrow_array();
6844 my $q2 = "SELECT drone_run_band.project_id, drone_run.project_id, processed.value, inprogress.value
6845 FROM project AS drone_run_band
6846 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
6847 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
6848 JOIN project_relationship AS field_trial_rel ON (drone_run.project_id = field_trial_rel.subject_project_id AND field_trial_rel.type_id=$drone_run_field_trial_project_relationship_type_id_cvterm_id)
6849 JOIN projectprop AS camera_rig ON(drone_run.project_id = camera_rig.project_id AND camera_rig.type_id=$drone_run_camera_rig_cvterm_id AND camera_rig.value=?)
6850 LEFT JOIN projectprop AS processed ON(drone_run.project_id = processed.project_id AND processed.type_id=$processed_cvterm_id)
6851 LEFT JOIN projectprop AS inprogress ON(drone_run.project_id = inprogress.project_id AND inprogress.type_id=$process_indicator_cvterm_id)
6852 WHERE field_trial_rel.object_project_id = ?;";
6854 my $h2 = $bcs_schema->storage->dbh()->prepare($q2);
6855 $h2->execute($camera_rig, $field_trial_id);
6856 my %apply_project_hash;
6857 while (my ($drone_run_band_project_id, $drone_run_project_id, $processed, $inprogress) = $h2->fetchrow_array()) {
6858 if (!$processed && !$inprogress) {
6859 push @{$apply_project_hash{$drone_run_project_id}}, $drone_run_band_project_id;
6862 while (my ($k, $v) = each %apply_project_hash) {
6863 my $time_hash = _perform_get_weeks_drone_run_after_planting($bcs_schema, $k);
6864 my $time_cvterm_id = $time_hash->{time_ontology_day_cvterm_id};
6865 push @apply_projects, {
6866 drone_run_band_project_id => $drone_run_band_project_id_input,
6867 apply_drone_run_band_project_ids => $v,
6868 drone_run_project_id => $k,
6869 time_cvterm_id => $time_cvterm_id
6872 } else {
6873 @apply_projects = (
6875 drone_run_band_project_id => $drone_run_band_project_id_input,
6876 apply_drone_run_band_project_ids => $apply_drone_run_band_project_ids_input,
6877 drone_run_project_id => $drone_run_project_id_input,
6878 time_cvterm_id => $time_cvterm_id_input
6882 print STDERR Dumper \@apply_projects;
6884 foreach (@apply_projects) {
6885 my $drone_run_project_id_in = $_->{drone_run_project_id};
6886 my $time_cvterm_id = $_->{time_cvterm_id};
6887 my $drone_run_band_project_id = $_->{drone_run_band_project_id};
6888 my $apply_drone_run_band_project_ids = $_->{apply_drone_run_band_project_ids};
6890 my $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
6891 type_id=>$process_indicator_cvterm_id,
6892 project_id=>$drone_run_project_id_in,
6893 rank=>0,
6894 value=>1
6897 key=>'projectprop_c1'
6900 my $drone_run_process_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
6901 type_id=>$processed_cvterm_id,
6902 project_id=>$drone_run_project_id_in,
6903 rank=>0,
6904 value=>0
6907 key=>'projectprop_c1'
6910 my $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
6911 type_id=>$processed_minimal_vi_cvterm_id,
6912 project_id=>$drone_run_project_id_in,
6913 rank=>0,
6914 value=>0
6917 key=>'projectprop_c1'
6920 my %vegetative_indices_hash;
6921 foreach (@$vegetative_indices) {
6922 $vegetative_indices_hash{$_}++;
6925 my $q = "SELECT rotate.value, plot_polygons.value, cropping.value, drone_run.project_id, drone_run.name
6926 FROM project AS drone_run_band
6927 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
6928 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
6929 JOIN projectprop AS rotate ON(drone_run_band.project_id = rotate.project_id AND rotate.type_id=$rotate_angle_type_id)
6930 JOIN projectprop AS plot_polygons ON(drone_run_band.project_id = plot_polygons.project_id AND plot_polygons.type_id=$plot_polygon_template_type_id)
6931 JOIN projectprop AS cropping ON(drone_run_band.project_id = cropping.project_id AND cropping.type_id=$cropping_polygon_type_id)
6932 WHERE drone_run_band.project_id = $drone_run_band_project_id;";
6934 my $h = $bcs_schema->storage->dbh()->prepare($q);
6935 $h->execute();
6936 my ($rotate_value, $plot_polygons_value, $cropping_value, $drone_run_project_id, $drone_run_project_name) = $h->fetchrow_array();
6938 my %selected_drone_run_band_types;
6939 my $q2 = "SELECT project_md_image.image_id, drone_run_band_type.value, drone_run_band.project_id
6940 FROM project AS drone_run_band
6941 JOIN projectprop AS drone_run_band_type ON(drone_run_band_type.project_id = drone_run_band.project_id AND drone_run_band_type.type_id = $drone_run_band_type_type_id)
6942 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id = drone_run_band.project_id)
6943 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
6944 WHERE project_md_image.type_id = $project_image_type_id
6945 AND drone_run_band.project_id = ?
6946 AND metadata.md_image.obsolete = 'f';";
6948 my $h2 = $bcs_schema->storage->dbh()->prepare($q2);
6949 $h2->execute($drone_run_band_project_id);
6950 my ($image_id, $drone_run_band_type, $drone_run_band_project_id_q) = $h2->fetchrow_array();
6951 $selected_drone_run_band_types{$drone_run_band_type} = $drone_run_band_project_id_q;
6953 my $check_image = SGN::Image->new( $bcs_schema->storage->dbh, $image_id, $c );
6954 my $check_image_fullpath = $check_image->get_filename('original_converted', 'full');
6955 my ($check_image_width, $check_image_height) = imgsize($check_image_fullpath);
6957 my $term_map = CXGN::DroneImagery::ImageTypes::get_base_imagery_observation_unit_plot_polygon_term_map();
6959 my %drone_run_band_info;
6960 foreach my $apply_drone_run_band_project_id (@$apply_drone_run_band_project_ids) {
6961 my $h2 = $bcs_schema->storage->dbh()->prepare($q2);
6962 $h2->execute($apply_drone_run_band_project_id);
6963 my ($image_id, $drone_run_band_type, $drone_run_band_project_id) = $h2->fetchrow_array();
6964 $selected_drone_run_band_types{$drone_run_band_type} = $drone_run_band_project_id;
6966 my $check_image_apply = SGN::Image->new( $bcs_schema->storage->dbh, $image_id, $c );
6967 my $check_image_apply_fullpath = $check_image_apply->get_filename('original_converted', 'full');
6968 my ($check_image_apply_width, $check_image_apply_height) = imgsize($check_image_apply_fullpath);
6970 my $apply_image_width_ratio = $check_image_width/$check_image_apply_width;
6971 my $apply_image_height_ratio = $check_image_height/$check_image_apply_height;
6973 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
6974 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
6975 $archive_rotate_temp_image .= '.png';
6977 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $drone_run_band_project_id, $image_id, $rotate_value, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, 1, 0);
6978 my $rotated_image_id = $rotate_return->{rotated_image_id};
6980 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
6981 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
6982 $archive_temp_image .= '.png';
6984 my $cropping_return = _perform_image_cropping($c, $bcs_schema, $drone_run_band_project_id, $rotated_image_id, $cropping_value, $user_id, $user_name, $user_role, $archive_temp_image, $apply_image_width_ratio, $apply_image_height_ratio);
6985 my $cropped_image_id = $cropping_return->{cropped_image_id};
6987 $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
6988 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
6989 $archive_denoise_temp_image .= '.png';
6991 my $denoise_return = _perform_image_denoise($c, $bcs_schema, $metadata_schema, $cropped_image_id, $drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
6992 my $denoised_image_id = $denoise_return->{denoised_image_id};
6994 $drone_run_band_info{$drone_run_band_project_id} = {
6995 denoised_image_id => $denoised_image_id,
6996 rotate_value => $rotate_value,
6997 cropping_value => $cropping_value,
6998 drone_run_band_type => $drone_run_band_type,
6999 drone_run_project_id => $drone_run_project_id_in,
7000 drone_run_project_name => $drone_run_project_name,
7001 plot_polygons_value => $plot_polygons_value,
7002 check_resize => 1,
7003 keep_original_size_rotate => 0
7006 my @denoised_plot_polygon_type = @{$term_map->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{base}};
7007 my @denoised_background_threshold_removed_imagery_types = @{$term_map->{$drone_run_band_type}->{imagery_types}->{threshold_background}};
7008 my @denoised_background_threshold_removed_plot_polygon_types = @{$term_map->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{threshold_background}};
7010 foreach (@denoised_plot_polygon_type) {
7011 my $plot_polygon_original_denoised_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $plot_polygons_value, $_, $user_id, $user_name, $user_role, 0, 0, $apply_image_width_ratio, $apply_image_height_ratio, 'rectangular_square');
7014 for my $iterator (0..(scalar(@denoised_background_threshold_removed_imagery_types)-1)) {
7015 $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
7016 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
7017 $archive_remove_background_temp_image .= '.png';
7019 my $background_removed_threshold_return = _perform_image_background_remove_threshold_percentage($c, $bcs_schema, $denoised_image_id, $drone_run_band_project_id, $denoised_background_threshold_removed_imagery_types[$iterator], '25', '25', $user_id, $user_name, $user_role, $archive_remove_background_temp_image);
7021 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $background_removed_threshold_return->{removed_background_image_id}, $drone_run_band_project_id, $plot_polygons_value, $denoised_background_threshold_removed_plot_polygon_types[$iterator], $user_id, $user_name, $user_role, 0, 0, $apply_image_width_ratio, $apply_image_height_ratio, 'rectangular_square');
7025 print STDERR Dumper \%selected_drone_run_band_types;
7026 print STDERR Dumper \%vegetative_indices_hash;
7028 _perform_minimal_vi_standard_process($c, $bcs_schema, $metadata_schema, \%vegetative_indices_hash, \%selected_drone_run_band_types, \%drone_run_band_info, $user_id, $user_name, $user_role, 'rectangular_square');
7030 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7031 type_id=>$process_indicator_cvterm_id,
7032 project_id=>$drone_run_project_id_in,
7033 rank=>0,
7034 value=>0
7037 key=>'projectprop_c1'
7040 $drone_run_process_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7041 type_id=>$processed_cvterm_id,
7042 project_id=>$drone_run_project_id_in,
7043 rank=>0,
7044 value=>1
7047 key=>'projectprop_c1'
7050 $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7051 type_id=>$processed_minimal_vi_cvterm_id,
7052 project_id=>$drone_run_project_id_in,
7053 rank=>0,
7054 value=>1
7057 key=>'projectprop_c1'
7060 my $return = _perform_phenotype_automated($c, $bcs_schema, $metadata_schema, $phenome_schema, $drone_run_project_id_in, $time_cvterm_id, $phenotype_methods, $standard_process_type, 1, undef, $user_id, $user_name, $user_role);
7063 my @result;
7064 $c->stash->{rest} = { data => \@result, success => 1 };
7067 sub standard_process_apply_ground_control_points : Path('/api/drone_imagery/standard_process_apply_ground_control_points') : ActionClass('REST') { }
7068 sub standard_process_apply_ground_control_points_POST : Args(0) {
7069 my $self = shift;
7070 my $c = shift;
7071 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
7072 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
7073 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
7074 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema', undef, $sp_person_id);
7075 my $field_trial_id = $c->req->param('field_trial_id');
7076 my $drone_run_project_id_input = $c->req->param('drone_run_project_id');
7077 my $drone_run_band_project_id_input = $c->req->param('drone_run_band_project_id');
7078 my $gcp_drone_run_project_id_input = $c->req->param('gcp_drone_run_project_id');
7079 my $time_cvterm_id = $c->req->param('time_cvterm_id');
7080 my $is_test = $c->req->param('is_test');
7081 my $is_test_run = $c->req->param('test_run');
7082 my ($user_id, $user_name, $user_role) = _check_user_login($c);
7084 my $phenotype_methods = ['zonal'];
7085 my $standard_process_type = 'minimal';
7087 my $vegetative_indices = ['TGI', 'VARI', 'NDVI', 'NDRE'];
7088 my %vegetative_indices_hash;
7089 foreach (@$vegetative_indices) {
7090 $vegetative_indices_hash{$_}++;
7093 if (!$gcp_drone_run_project_id_input) {
7094 $c->stash->{rest} = { error => "Please select an imaging event to use as a template!" };
7095 $c->detach();
7098 my $drone_run_band_drone_run_project_relationship_type_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
7099 my $drone_run_band_drone_run_project_type = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
7101 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'stitched_drone_imagery', 'project_md_image')->cvterm_id();
7102 my $rotated_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'rotated_stitched_drone_imagery', 'project_md_image')->cvterm_id();
7103 my $cropped_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'cropped_stitched_drone_imagery', 'project_md_image')->cvterm_id();
7104 my $denoised_project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
7106 my $apply_drone_run_band_project_ids;
7107 my %apply_drone_run_band_project_ids_type_hash;
7108 my $drone_run_band_q = "SELECT project.project_id, project_md_image.type_id, projectprop.value
7109 FROM project
7110 JOIN projectprop ON(project.project_id = projectprop.project_id)
7111 JOIN project_relationship ON(project.project_id=project_relationship.subject_project_id AND project_relationship.type_id=$drone_run_band_drone_run_project_relationship_type_id_cvterm_id)
7112 JOIN phenome.project_md_image AS project_md_image ON(project.project_id = project_md_image.project_id)
7113 WHERE project_relationship.object_project_id=?
7114 AND project_md_image.type_id=?
7115 AND projectprop.type_id=$drone_run_band_drone_run_project_type;";
7116 my $drone_run_band_h = $bcs_schema->storage->dbh()->prepare($drone_run_band_q);
7117 $drone_run_band_h->execute($drone_run_project_id_input, $project_image_type_id);
7118 while (my ($drone_run_band_project_id, $drone_run_band_project_image_type_id, $drone_run_band_project_type) = $drone_run_band_h->fetchrow_array()) {
7119 push @$apply_drone_run_band_project_ids, $drone_run_band_project_id;
7120 $apply_drone_run_band_project_ids_type_hash{$drone_run_band_project_id} = {
7121 image_type_id => $drone_run_band_project_image_type_id,
7122 band_type => $drone_run_band_project_type
7125 print STDERR Dumper \%apply_drone_run_band_project_ids_type_hash;
7126 my $drone_run_band_project_type_current = $apply_drone_run_band_project_ids_type_hash{$drone_run_band_project_id_input}->{band_type};
7128 my $gcp_drone_run_band_q = "SELECT project.project_id
7129 FROM project
7130 JOIN projectprop ON(project.project_id = projectprop.project_id)
7131 JOIN project_relationship ON(project.project_id=project_relationship.subject_project_id AND project_relationship.type_id=$drone_run_band_drone_run_project_relationship_type_id_cvterm_id)
7132 WHERE project_relationship.object_project_id=?
7133 AND projectprop.type_id=$drone_run_band_drone_run_project_type
7134 AND projectprop.value='$drone_run_band_project_type_current';";
7135 my $gcp_drone_run_band_h = $bcs_schema->storage->dbh()->prepare($gcp_drone_run_band_q);
7136 $gcp_drone_run_band_h->execute($gcp_drone_run_project_id_input);
7137 my ($gcp_drone_run_band_project_id) = $gcp_drone_run_band_h->fetchrow_array();
7139 my $drone_run_gcp_type_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_ground_control_points', 'project_property')->cvterm_id();
7141 my $template_gcp_q = "SELECT value
7142 FROM projectprop
7143 JOIN project USING(project_id)
7144 WHERE project.project_id=? AND projectprop.type_id=$drone_run_gcp_type_id_cvterm_id;";
7145 my $template_gcp_h = $bcs_schema->storage->dbh()->prepare($template_gcp_q);
7146 $template_gcp_h->execute($gcp_drone_run_project_id_input);
7147 my ($template_gcp_points_json) = $template_gcp_h->fetchrow_array();
7148 my $template_gcp_points = decode_json $template_gcp_points_json;
7149 # print STDERR Dumper $template_gcp_points;
7150 if (scalar(keys %$template_gcp_points)<3) {
7151 $c->stash->{rest} = { error => "Not enough GCP points defined in the template drone run!" };
7152 $c->detach();
7155 my $current_gcp_q = "SELECT value
7156 FROM projectprop
7157 JOIN project USING(project_id)
7158 WHERE project.project_id=? AND projectprop.type_id=$drone_run_gcp_type_id_cvterm_id;";
7159 my $current_gcp_h = $bcs_schema->storage->dbh()->prepare($current_gcp_q);
7160 $current_gcp_h->execute($drone_run_project_id_input);
7161 my ($current_gcp_points_json) = $current_gcp_h->fetchrow_array();
7162 my $current_gcp_points = decode_json $current_gcp_points_json;
7163 # print STDERR Dumper $current_gcp_points;
7164 if (scalar(keys %$current_gcp_points)<3) {
7165 $c->stash->{rest} = { error => "Not enough GCP points defined in the current drone run!" };
7166 $c->detach();
7169 my $tl_gcp_template_point_x = 1000000000;
7170 my $tl_gcp_template_point_y = 1000000000;
7171 my $tr_gcp_template_point_x = 0;
7172 my $tr_gcp_template_point_y = 1000000000;
7173 my $br_gcp_template_point_x = 0;
7174 my $br_gcp_template_point_y = 0;
7175 my $bl_gcp_template_point_x = 1000000000;
7176 my $bl_gcp_template_point_y = 0;
7178 my @template_x_vals;
7179 my @template_y_vals;
7180 my @gcp_points_template;
7181 my @gcp_names_template;
7182 while (my ($name, $o) = each %$template_gcp_points) {
7183 if (exists($current_gcp_points->{$name})) {
7184 my $x = $o->{x_pos};
7185 my $y = $o->{y_pos};
7186 push @template_x_vals, $x;
7187 push @template_y_vals, $y;
7188 push @gcp_points_template, [$x, $y];
7189 push @gcp_names_template, $name;
7191 if ($x < $tl_gcp_template_point_x) {
7192 $tl_gcp_template_point_x = $x;
7194 if ($y < $tl_gcp_template_point_y) {
7195 $tl_gcp_template_point_y = $y;
7197 if ($x > $tr_gcp_template_point_x) {
7198 $tr_gcp_template_point_x = $x;
7200 if ($y < $tr_gcp_template_point_y) {
7201 $tr_gcp_template_point_y = $y;
7203 if ($x > $br_gcp_template_point_x) {
7204 $br_gcp_template_point_x = $x;
7206 if ($y > $br_gcp_template_point_y) {
7207 $br_gcp_template_point_y = $y;
7209 if ($x < $bl_gcp_template_point_x) {
7210 $bl_gcp_template_point_x = $x;
7212 if ($y > $bl_gcp_template_point_y) {
7213 $bl_gcp_template_point_y = $y;
7217 print STDERR Dumper \@gcp_names_template;
7219 my $template_central_x = sum(@template_x_vals)/scalar(@template_x_vals);
7220 my $template_central_y = sum(@template_y_vals)/scalar(@template_y_vals);
7222 my @current_x_vals;
7223 my @current_y_vals;
7224 my @gcp_points_current;
7225 foreach my $name (@gcp_names_template) {
7226 my $o = $current_gcp_points->{$name};
7227 my $x = $o->{x_pos};
7228 my $y = $o->{y_pos};
7229 push @current_x_vals, $x;
7230 push @current_y_vals, $y;
7231 push @gcp_points_current, [$x, $y];
7234 my $current_central_x = sum(@current_x_vals)/scalar(@current_x_vals);
7235 my $current_central_y = sum(@current_y_vals)/scalar(@current_y_vals);
7237 my $rad_conversion = 0.0174533;
7239 my @angle_rad_templates;
7240 foreach my $g (@gcp_points_template) {
7241 my $x_diff = $g->[0]-$template_central_x;
7242 my $y_diff = $g->[1]-$template_central_y;
7243 if ($x_diff > 0 && $y_diff > 0) {
7244 push @angle_rad_templates, atan(abs($x_diff/$y_diff));
7246 # elsif ($x_diff < 0 && $y_diff > 0) {
7247 # push @angle_rad_templates, 360*$rad_conversion - atan(abs($x_diff/$y_diff));
7249 elsif ($x_diff < 0 && $y_diff < 0) {
7250 push @angle_rad_templates, 180*$rad_conversion + atan(abs($x_diff/$y_diff));
7252 elsif ($x_diff > 0 && $y_diff < 0) {
7253 push @angle_rad_templates, 180*$rad_conversion - atan(abs($x_diff/$y_diff));
7255 else {
7256 push @angle_rad_templates, undef;
7260 my @angle_rad_currents;
7261 foreach my $g (@gcp_points_current) {
7262 my $x_diff = $g->[0]-$current_central_x;
7263 my $y_diff = $g->[1]-$current_central_y;
7264 if ($x_diff > 0 && $y_diff > 0) {
7265 push @angle_rad_currents, atan(abs($x_diff/$y_diff));
7267 # elsif ($x_diff < 0 && $y_diff > 0) {
7268 # push @angle_rad_currents, 360*$rad_conversion - atan(abs($x_diff/$y_diff));
7270 elsif ($x_diff < 0 && $y_diff < 0) {
7271 push @angle_rad_currents, 180*$rad_conversion + atan(abs($x_diff/$y_diff));
7273 elsif ($x_diff > 0 && $y_diff < 0) {
7274 push @angle_rad_currents, 180*$rad_conversion - atan(abs($x_diff/$y_diff));
7276 else {
7277 push @angle_rad_currents, undef;
7280 # print STDERR Dumper \@angle_rad_templates;
7281 # print STDERR Dumper \@angle_rad_currents;
7283 my $counter = 0;
7284 my @angle_diffs;
7285 foreach (@angle_rad_templates) {
7286 if ($_ && $angle_rad_currents[$counter]) {
7287 my $diff = $_ - $angle_rad_currents[$counter];
7288 # print STDERR "DIFF:". $diff."\n";
7289 push @angle_diffs, $diff;
7291 $counter++;
7293 print STDERR Dumper \@angle_diffs;
7295 my $rotate_rad_gcp = sum(@angle_diffs)/scalar(@angle_diffs);
7296 print STDERR "AVG ROTATION: $rotate_rad_gcp\n";
7298 my $q2 = "SELECT project_md_image.image_id, drone_run_band_type.value
7299 FROM project AS drone_run_band
7300 JOIN projectprop AS drone_run_band_type ON(drone_run_band_type.project_id = drone_run_band.project_id AND drone_run_band_type.type_id = $drone_run_band_drone_run_project_type)
7301 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id = drone_run_band.project_id)
7302 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
7303 WHERE project_md_image.type_id = ?
7304 AND drone_run_band.project_id = ?
7305 AND metadata.md_image.obsolete = 'f'
7306 AND drone_run_band_type.value='$drone_run_band_project_type_current';";
7308 my $h2 = $bcs_schema->storage->dbh()->prepare($q2);
7309 $h2->execute($project_image_type_id, $drone_run_band_project_id_input);
7310 my ($check_image_id, $check_drone_run_band_type) = $h2->fetchrow_array();
7312 my $check_image = SGN::Image->new( $bcs_schema->storage->dbh, $check_image_id, $c );
7313 my $check_image_url = $check_image->get_image_url("original");
7314 my $check_image_fullpath = $check_image->get_filename('original_converted', 'full');
7315 my ($check_image_width, $check_image_height) = imgsize($check_image_fullpath);
7317 my $tl_o_x = 0;
7318 my $tl_o_y = 0;
7319 my $tr_o_x = $check_image_width;
7320 my $tr_o_y = 0;
7321 my $br_o_x = $check_image_width;
7322 my $br_o_y = $check_image_height;
7323 my $bl_o_x = 0;
7324 my $bl_o_y = $check_image_height;
7325 my $tl_o_rotated_x = ($tl_o_x - $check_image_width/2)*cos($rotate_rad_gcp*-1) - ($tl_o_y - $check_image_height/2)*sin($rotate_rad_gcp*-1) + $check_image_width/2;
7326 my $tl_o_rotated_y = ($tl_o_x - $check_image_width/2)*sin($rotate_rad_gcp*-1) + ($tl_o_y - $check_image_height/2)*cos($rotate_rad_gcp*-1) + $check_image_height/2;
7327 my $tr_o_rotated_x = ($tr_o_x - $check_image_width/2)*cos($rotate_rad_gcp*-1) - ($tr_o_y - $check_image_height/2)*sin($rotate_rad_gcp*-1) + $check_image_width/2;
7328 my $tr_o_rotated_y = ($tr_o_x - $check_image_width/2)*sin($rotate_rad_gcp*-1) + ($tr_o_y - $check_image_height/2)*cos($rotate_rad_gcp*-1) + $check_image_height/2;
7329 my $br_o_rotated_x = ($br_o_x - $check_image_width/2)*cos($rotate_rad_gcp*-1) - ($br_o_y - $check_image_height/2)*sin($rotate_rad_gcp*-1) + $check_image_width/2;
7330 my $br_o_rotated_y = ($br_o_x - $check_image_width/2)*sin($rotate_rad_gcp*-1) + ($br_o_y - $check_image_height/2)*cos($rotate_rad_gcp*-1) + $check_image_height/2;
7331 my $bl_o_rotated_x = ($bl_o_x - $check_image_width/2)*cos($rotate_rad_gcp*-1) - ($bl_o_y - $check_image_height/2)*sin($rotate_rad_gcp*-1) + $check_image_width/2;
7332 my $bl_o_rotated_y = ($bl_o_x - $check_image_width/2)*sin($rotate_rad_gcp*-1) + ($bl_o_y - $check_image_height/2)*cos($rotate_rad_gcp*-1) + $check_image_height/2;
7333 my $min_o_rot_x = 100000000;
7334 my $min_o_rot_y = 100000000;
7335 foreach (($tl_o_rotated_x, $tr_o_rotated_x, $br_o_rotated_x, $bl_o_rotated_x)) {
7336 if ($_ < $min_o_rot_x) {
7337 $min_o_rot_x = $_;
7340 foreach (($tl_o_rotated_y, $tr_o_rotated_y, $br_o_rotated_y, $bl_o_rotated_y)) {
7341 if ($_ < $min_o_rot_y) {
7342 $min_o_rot_y = $_;
7345 print STDERR Dumper [$min_o_rot_x, $min_o_rot_y];
7347 my @rotated_current_points;
7348 foreach (@gcp_points_current) {
7349 my $x_rot = ($_->[0] - $check_image_width/2)*cos($rotate_rad_gcp*-1) - ($_->[1] - $check_image_height/2)*sin($rotate_rad_gcp*-1) + $check_image_width/2 - $min_o_rot_x;
7350 my $y_rot = ($_->[0] - $check_image_width/2)*sin($rotate_rad_gcp*-1) + ($_->[1] - $check_image_height/2)*cos($rotate_rad_gcp*-1) + $check_image_height/2 - $min_o_rot_y;
7351 push @rotated_current_points, [$x_rot, $y_rot];
7354 my $tl_gcp_current_point_x = 1000000000;
7355 my $tl_gcp_current_point_y = 1000000000;
7356 my $tr_gcp_current_point_x = 0;
7357 my $tr_gcp_current_point_y = 1000000000;
7358 my $br_gcp_current_point_x = 0;
7359 my $br_gcp_current_point_y = 0;
7360 my $bl_gcp_current_point_x = 1000000000;
7361 my $bl_gcp_current_point_y = 0;
7363 foreach (@rotated_current_points) {
7364 my $x = $_->[0];
7365 my $y = $_->[1];
7367 if ($x < $tl_gcp_current_point_x) {
7368 $tl_gcp_current_point_x = $x;
7370 if ($y < $tl_gcp_current_point_y) {
7371 $tl_gcp_current_point_y = $y;
7373 if ($x > $tr_gcp_current_point_x) {
7374 $tr_gcp_current_point_x = $x;
7376 if ($y < $tr_gcp_current_point_y) {
7377 $tr_gcp_current_point_y = $y;
7379 if ($x > $br_gcp_current_point_x) {
7380 $br_gcp_current_point_x = $x;
7382 if ($y > $br_gcp_current_point_y) {
7383 $br_gcp_current_point_y = $y;
7385 if ($x < $bl_gcp_current_point_x) {
7386 $bl_gcp_current_point_x = $x;
7388 if ($y > $bl_gcp_current_point_y) {
7389 $bl_gcp_current_point_y = $y;
7393 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
7394 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
7395 $archive_rotate_temp_image .= '.png';
7396 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $drone_run_band_project_id_input, $check_image_id, $rotate_rad_gcp/$rad_conversion, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, 1, 0);
7397 my $rotated_image_id = $rotate_return->{rotated_image_id};
7399 my $h_rotate_check = $bcs_schema->storage->dbh()->prepare($q2);
7400 $h_rotate_check->execute($rotated_image_type_id, $gcp_drone_run_band_project_id);
7401 my ($rotate_check_image_id, $rotate_check_drone_run_band_type) = $h_rotate_check->fetchrow_array();
7403 my $rotate_check_target_image = SGN::Image->new( $bcs_schema->storage->dbh, $rotated_image_id, $c );
7404 my $rotate_check_target_image_url = $rotate_check_target_image->get_image_url("original");
7405 my $rotate_check_target_image_fullpath = $rotate_check_target_image->get_filename('original_converted', 'full');
7406 my ($rotate_check_target_image_width, $rotate_check_target_image_height) = imgsize($rotate_check_target_image_fullpath);
7407 print STDERR "Target Rotation: $rotate_check_target_image_width $rotate_check_target_image_height \n";
7409 my $rotate_check_image = SGN::Image->new( $bcs_schema->storage->dbh, $rotate_check_image_id, $c );
7410 my $rotate_check_image_url = $rotate_check_image->get_image_url("original");
7411 my $rotate_check_image_fullpath = $rotate_check_image->get_filename('original_converted', 'full');
7412 my ($rotate_check_image_width, $rotate_check_image_height) = imgsize($rotate_check_image_fullpath);
7413 print STDERR "Template Rotation: $rotate_check_image_width $rotate_check_image_height \n";
7415 # my $template_gcp_x_scale = $rotate_check_image_width/$rotate_check_target_image_width;
7416 # my $template_gcp_y_scale = $rotate_check_image_height/$rotate_check_target_image_height;
7417 my $template_gcp_x_scale;
7418 if ($tr_gcp_template_point_x - $tl_gcp_template_point_x != 0 && $tr_gcp_current_point_x - $tl_gcp_current_point_x != 0) {
7419 $template_gcp_x_scale = ($tr_gcp_template_point_x - $tl_gcp_template_point_x) / ($tr_gcp_current_point_x - $tl_gcp_current_point_x);
7421 elsif ($br_gcp_template_point_x - $bl_gcp_template_point_x != 0 && $br_gcp_current_point_x - $bl_gcp_current_point_x != 0) {
7422 $template_gcp_x_scale = ($br_gcp_template_point_x - $bl_gcp_template_point_x) / ($br_gcp_current_point_x - $bl_gcp_current_point_x);
7424 else {
7425 $c->stash->{rest} = { error => "Not enough GCP points to get the x scale!" };
7426 $c->detach();
7428 my $template_gcp_y_scale;
7429 if ($bl_gcp_template_point_y - $tl_gcp_template_point_y != 0 && $bl_gcp_current_point_y - $tl_gcp_current_point_y != 0) {
7430 $template_gcp_y_scale = ($bl_gcp_template_point_y - $tl_gcp_template_point_y) / ($bl_gcp_current_point_y - $tl_gcp_current_point_y);
7432 if ($br_gcp_template_point_y - $tr_gcp_template_point_y != 0 && $br_gcp_current_point_y - $tr_gcp_current_point_y != 0) {
7433 $template_gcp_y_scale = ($br_gcp_template_point_y - $tr_gcp_template_point_y) / ($br_gcp_current_point_y - $tr_gcp_current_point_y);
7435 else {
7436 $c->stash->{rest} = { error => "Not enough GCP points to get the y scale!" };
7437 $c->detach();
7439 print STDERR Dumper [$template_gcp_x_scale, $template_gcp_y_scale];
7441 my $rotate_angle_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_rotate_angle', 'project_property')->cvterm_id();
7442 my $cropping_polygon_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_cropped_polygon', 'project_property')->cvterm_id();
7443 my $plot_polygon_template_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
7444 my $drone_run_drone_run_band_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
7446 my $q = "SELECT rotate.value, plot_polygons.value, cropping.value, drone_run.project_id, drone_run.name
7447 FROM project AS drone_run_band
7448 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
7449 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
7450 JOIN projectprop AS rotate ON(drone_run_band.project_id = rotate.project_id AND rotate.type_id=$rotate_angle_type_id)
7451 JOIN projectprop AS plot_polygons ON(drone_run_band.project_id = plot_polygons.project_id AND plot_polygons.type_id=$plot_polygon_template_type_id)
7452 JOIN projectprop AS cropping ON(drone_run_band.project_id = cropping.project_id AND cropping.type_id=$cropping_polygon_type_id)
7453 WHERE drone_run_band.project_id = $gcp_drone_run_band_project_id;";
7455 my $h = $bcs_schema->storage->dbh()->prepare($q);
7456 $h->execute();
7457 my ($rotate_value_old, $plot_polygons_value_json, $cropping_value_json, $drone_run_project_id, $drone_run_project_name) = $h->fetchrow_array();
7458 print STDERR Dumper $rotate_value_old;
7459 print STDERR Dumper $rotate_value_old * $rad_conversion;
7460 print STDERR Dumper $cropping_value_json;
7461 print STDERR Dumper $plot_polygons_value_json;
7462 my $cropping_value_old = decode_json $cropping_value_json;
7463 my $plot_polygons_value_old = decode_json $plot_polygons_value_json;
7465 my $min_old_crop_x = 1000000000;
7466 my $min_old_crop_y = 1000000000;
7467 foreach (@{$cropping_value_old->[0]}) {
7468 my $x = $_->{'x'};
7469 my $y = $_->{'y'};
7470 if ($x < $min_old_crop_x) {
7471 $min_old_crop_x = $x;
7473 if ($y < $min_old_crop_y) {
7474 $min_old_crop_y = $y;
7478 my @old_cropping_val_dists;
7479 foreach (@{$cropping_value_old->[0]}) {
7480 my $x = $_->{'x'} - $min_old_crop_x;
7481 my $y = $_->{'y'} - $min_old_crop_y;
7482 my @diffs;
7483 foreach my $t (@gcp_points_template) {
7484 push @diffs, [$t->[0] - $x, $t->[1] - $y];
7486 push @old_cropping_val_dists, \@diffs;
7488 # print STDERR Dumper \@old_cropping_val_dists;
7490 my $image_crop;
7491 my $counter_c = 0;
7492 foreach my $o (@old_cropping_val_dists) {
7493 my @pos_x;
7494 my @pos_y;
7495 my $counter = 0;
7496 foreach my $r (@rotated_current_points) {
7497 my $o_x = $o->[$counter]->[0]/$template_gcp_x_scale;
7498 my $o_y = $o->[$counter]->[1]/$template_gcp_y_scale;
7499 my $r_x = $r->[0];
7500 my $r_y = $r->[1];
7501 push @pos_x, $r_x - $o_x;
7502 push @pos_y, $r_y - $o_y;
7503 $counter++;
7505 $image_crop->[0]->[$counter_c] = {
7506 x => sum(@pos_x)/scalar(@pos_x),
7507 y => sum(@pos_y)/scalar(@pos_y)
7509 $counter_c++;
7511 # print STDERR Dumper $image_crop;
7513 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
7514 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
7515 $archive_temp_image .= '.png';
7517 my $check_cropping_return = _perform_image_cropping($c, $bcs_schema, $drone_run_band_project_id_input, $rotated_image_id, encode_json $image_crop, $user_id, $user_name, $user_role, $archive_temp_image, 1, 1);
7518 my $check_cropped_image_id = $check_cropping_return->{cropped_image_id};
7520 my $crop_check_target_image = SGN::Image->new( $bcs_schema->storage->dbh, $check_cropped_image_id, $c );
7521 my $crop_check_target_image_url = $crop_check_target_image->get_image_url("original");
7522 my $crop_check_target_image_fullpath = $crop_check_target_image->get_filename('original_converted', 'full');
7524 my $min_new_crop_x = 1000000000;
7525 my $min_new_crop_y = 1000000000;
7526 foreach (@{$image_crop->[0]}) {
7527 my $x = $_->{'x'};
7528 my $y = $_->{'y'};
7529 if ($x < $min_new_crop_x) {
7530 $min_new_crop_x = $x;
7532 if ($y < $min_new_crop_y) {
7533 $min_new_crop_y = $y;
7537 my @old_plot_val_names;
7538 my @old_plot_val_dists;
7539 foreach my $key (sort keys %$plot_polygons_value_old) {
7540 push @old_plot_val_names, $key;
7541 my $v = $plot_polygons_value_old->{$key};
7542 my @points;
7543 foreach (@{$v}) {
7544 my $x = $_->{'x'};
7545 my $y = $_->{'y'};
7546 my @diffs;
7547 foreach my $t (@gcp_points_template) {
7548 push @diffs, [$t->[0] - $x, $t->[1] - $y];
7550 push @points, \@diffs;
7552 push @old_plot_val_dists, \@points;
7555 my %scaled_plot_polygons;
7556 my $counter_p = 0;
7557 foreach my $o (@old_plot_val_names) {
7558 my $point_diffs = $old_plot_val_dists[$counter_p];
7559 my @adjusted;
7560 my @adjusted_display;
7561 foreach my $p (@$point_diffs) {
7562 my @pos_x;
7563 my @pos_y;
7564 my $counter = 0;
7565 foreach my $r (@rotated_current_points) {
7566 my $o_x = $p->[$counter]->[0]/$template_gcp_x_scale;
7567 my $o_y = $p->[$counter]->[1]/$template_gcp_y_scale;
7568 my $r_x = $r->[0] - $min_new_crop_x;
7569 my $r_y = $r->[1] - $min_new_crop_y;
7570 push @pos_x, $r_x - $o_x;
7571 push @pos_y, $r_y - $o_y;
7572 $counter++;
7574 push @adjusted, {
7575 x => sum(@pos_x)/scalar(@pos_x),
7576 y => sum(@pos_y)/scalar(@pos_y)
7579 $scaled_plot_polygons{$o} = \@adjusted;
7580 $counter_p++;
7583 if ($is_test_run eq 'Yes') {
7584 $c->stash->{rest} = { old_cropped_points => $cropping_value_old, cropped_points => $image_crop, rotated_points => \@rotated_current_points, rotated_image_id => $check_cropped_image_id, plot_polygons => \%scaled_plot_polygons };
7585 $c->detach();
7588 my $rotate_value = $rotate_rad_gcp/$rad_conversion;
7589 my $cropping_value = encode_json $image_crop;
7590 my $plot_polygons_value = encode_json \%scaled_plot_polygons;
7592 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
7593 my $processed_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_completed', 'project_property')->cvterm_id();
7594 my $processed_minimal_vi_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_vi_completed', 'project_property')->cvterm_id();
7595 my $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7596 type_id=>$process_indicator_cvterm_id,
7597 project_id=>$drone_run_project_id_input,
7598 rank=>0,
7599 value=>1
7602 key=>'projectprop_c1'
7605 my $drone_run_process_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7606 type_id=>$processed_cvterm_id,
7607 project_id=>$drone_run_project_id_input,
7608 rank=>0,
7609 value=>0
7612 key=>'projectprop_c1'
7615 my $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7616 type_id=>$processed_minimal_vi_cvterm_id,
7617 project_id=>$drone_run_project_id_input,
7618 rank=>0,
7619 value=>0
7622 key=>'projectprop_c1'
7625 my %selected_drone_run_band_types;
7627 my $q4 = "SELECT project_md_image.image_id, drone_run_band_type.value, drone_run_band.project_id
7628 FROM project AS drone_run_band
7629 JOIN projectprop AS drone_run_band_type ON(drone_run_band_type.project_id = drone_run_band.project_id AND drone_run_band_type.type_id = $drone_run_band_drone_run_project_type)
7630 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id = drone_run_band.project_id)
7631 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
7632 WHERE project_md_image.type_id = ?
7633 AND drone_run_band.project_id = ?
7634 AND metadata.md_image.obsolete = 'f';";
7635 my $h4 = $bcs_schema->storage->dbh()->prepare($q4);
7637 my $term_map = CXGN::DroneImagery::ImageTypes::get_base_imagery_observation_unit_plot_polygon_term_map();
7638 my %drone_run_band_info;
7639 foreach my $apply_drone_run_band_project_id (@$apply_drone_run_band_project_ids) {
7640 $h4->execute($project_image_type_id, $apply_drone_run_band_project_id);
7641 my ($image_id, $drone_run_band_type, $drone_run_band_project_id) = $h4->fetchrow_array();
7642 $selected_drone_run_band_types{$drone_run_band_type} = $drone_run_band_project_id;
7644 my $check_image_apply_crop = SGN::Image->new( $bcs_schema->storage->dbh, $image_id, $c );
7645 my $check_image_apply_crop_fullpath = $check_image_apply_crop->get_filename('original_converted', 'full');
7646 my ($check_image_apply_crop_width, $check_image_apply_crop_height) = imgsize($check_image_apply_crop_fullpath);
7648 my $apply_image_width_ratio = $check_image_width/$check_image_apply_crop_width;
7649 my $apply_image_height_ratio = $check_image_height/$check_image_apply_crop_height;
7651 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
7652 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
7653 $archive_rotate_temp_image .= '.png';
7655 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $drone_run_band_project_id, $image_id, $rotate_value, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, 1, 0);
7656 my $rotated_image_id = $rotate_return->{rotated_image_id};
7658 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
7659 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
7660 $archive_temp_image .= '.png';
7662 my $cropping_return = _perform_image_cropping($c, $bcs_schema, $drone_run_band_project_id, $rotated_image_id, $cropping_value, $user_id, $user_name, $user_role, $archive_temp_image, $apply_image_width_ratio, $apply_image_height_ratio);
7663 my $cropped_image_id = $cropping_return->{cropped_image_id};
7665 $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
7666 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
7667 $archive_denoise_temp_image .= '.png';
7669 my $denoise_return = _perform_image_denoise($c, $bcs_schema, $metadata_schema, $cropped_image_id, $drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
7670 my $denoised_image_id = $denoise_return->{denoised_image_id};
7672 $drone_run_band_info{$drone_run_band_project_id} = {
7673 denoised_image_id => $denoised_image_id,
7674 rotate_value => $rotate_value,
7675 cropping_value => $cropping_value,
7676 drone_run_band_type => $drone_run_band_type,
7677 drone_run_project_id => $drone_run_project_id_input,
7678 drone_run_project_name => $drone_run_project_name,
7679 plot_polygons_value => $plot_polygons_value,
7680 check_resize => 1,
7681 keep_original_size_rotate => 0
7684 my @denoised_plot_polygon_type = @{$term_map->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{base}};
7685 my @denoised_background_threshold_removed_imagery_types = @{$term_map->{$drone_run_band_type}->{imagery_types}->{threshold_background}};
7686 my @denoised_background_threshold_removed_plot_polygon_types = @{$term_map->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{threshold_background}};
7688 foreach (@denoised_plot_polygon_type) {
7689 my $plot_polygon_original_denoised_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $plot_polygons_value, $_, $user_id, $user_name, $user_role, 0, 0, $apply_image_width_ratio, $apply_image_height_ratio, 'rectangular_square');
7692 for my $iterator (0..(scalar(@denoised_background_threshold_removed_imagery_types)-1)) {
7693 $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
7694 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
7695 $archive_remove_background_temp_image .= '.png';
7697 my $background_removed_threshold_return = _perform_image_background_remove_threshold_percentage($c, $bcs_schema, $denoised_image_id, $drone_run_band_project_id, $denoised_background_threshold_removed_imagery_types[$iterator], '25', '25', $user_id, $user_name, $user_role, $archive_remove_background_temp_image);
7699 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $background_removed_threshold_return->{removed_background_image_id}, $drone_run_band_project_id, $plot_polygons_value, $denoised_background_threshold_removed_plot_polygon_types[$iterator], $user_id, $user_name, $user_role, 0, 0, $apply_image_width_ratio, $apply_image_height_ratio, 'rectangular_square');
7703 print STDERR Dumper \%selected_drone_run_band_types;
7704 print STDERR Dumper \%vegetative_indices_hash;
7706 _perform_minimal_vi_standard_process($c, $bcs_schema, $metadata_schema, \%vegetative_indices_hash, \%selected_drone_run_band_types, \%drone_run_band_info, $user_id, $user_name, $user_role, 'rectangular_square');
7708 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7709 type_id=>$process_indicator_cvterm_id,
7710 project_id=>$drone_run_project_id_input,
7711 rank=>0,
7712 value=>0
7715 key=>'projectprop_c1'
7718 $drone_run_process_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7719 type_id=>$processed_cvterm_id,
7720 project_id=>$drone_run_project_id_input,
7721 rank=>0,
7722 value=>1
7725 key=>'projectprop_c1'
7728 $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7729 type_id=>$processed_minimal_vi_cvterm_id,
7730 project_id=>$drone_run_project_id_input,
7731 rank=>0,
7732 value=>1
7735 key=>'projectprop_c1'
7738 if (!$is_test) {
7739 my $return = _perform_phenotype_automated($c, $bcs_schema, $metadata_schema, $phenome_schema, $drone_run_project_id_input, $time_cvterm_id, $phenotype_methods, $standard_process_type, 1, undef, $user_id, $user_name, $user_role);
7742 my @result;
7743 $c->stash->{rest} = { data => \@result, success => 1 };
7746 sub standard_process_apply_previous_imaging_event : Path('/api/drone_imagery/standard_process_apply_previous_imaging_event') : ActionClass('REST') { }
7747 sub standard_process_apply_previous_imaging_event_POST : Args(0) {
7748 my $self = shift;
7749 my $c = shift;
7750 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
7751 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
7752 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
7753 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema', undef, $sp_person_id);
7754 my $field_trial_id = $c->req->param('field_trial_id');
7755 my $drone_run_band_project_id_input = $c->req->param('drone_run_band_project_id');
7756 my $drone_run_project_id_input = $c->req->param('drone_run_project_id');
7757 my $gcp_drone_run_project_id_input = $c->req->param('previous_drone_run_project_id');
7758 my $time_cvterm_id = $c->req->param('time_cvterm_id');
7759 my ($user_id, $user_name, $user_role) = _check_user_login($c);
7761 my $phenotype_methods = ['zonal'];
7762 my $standard_process_type = 'minimal';
7764 my $vegetative_indices = ['TGI', 'VARI', 'NDVI', 'NDRE'];
7765 my %vegetative_indices_hash;
7766 foreach (@$vegetative_indices) {
7767 $vegetative_indices_hash{$_}++;
7770 if (!$gcp_drone_run_project_id_input) {
7771 $c->stash->{rest} = { error => "Please select an imaging event to use as a template!" };
7772 $c->detach();
7775 my $drone_run_band_drone_run_project_relationship_type_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
7776 my $drone_run_band_drone_run_project_type = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
7778 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'stitched_drone_imagery', 'project_md_image')->cvterm_id();
7779 my $rotated_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'rotated_stitched_drone_imagery', 'project_md_image')->cvterm_id();
7780 my $cropped_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'cropped_stitched_drone_imagery', 'project_md_image')->cvterm_id();
7781 my $denoised_project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
7783 my $apply_drone_run_band_project_ids;
7784 my %apply_drone_run_band_project_ids_type_hash;
7785 my $drone_run_band_q = "SELECT project.project_id, project_md_image.type_id, projectprop.value
7786 FROM project
7787 JOIN projectprop ON(project.project_id = projectprop.project_id)
7788 JOIN project_relationship ON(project.project_id=project_relationship.subject_project_id AND project_relationship.type_id=$drone_run_band_drone_run_project_relationship_type_id_cvterm_id)
7789 JOIN phenome.project_md_image AS project_md_image ON(project.project_id = project_md_image.project_id)
7790 WHERE project_relationship.object_project_id=?
7791 AND project_md_image.type_id=?
7792 AND projectprop.type_id=$drone_run_band_drone_run_project_type;";
7793 my $drone_run_band_h = $bcs_schema->storage->dbh()->prepare($drone_run_band_q);
7794 $drone_run_band_h->execute($drone_run_project_id_input, $project_image_type_id);
7795 while (my ($drone_run_band_project_id, $drone_run_band_project_image_type_id, $drone_run_band_project_type) = $drone_run_band_h->fetchrow_array()) {
7796 push @$apply_drone_run_band_project_ids, $drone_run_band_project_id;
7797 $apply_drone_run_band_project_ids_type_hash{$drone_run_band_project_id} = {
7798 image_type_id => $drone_run_band_project_image_type_id,
7799 band_type => $drone_run_band_project_type
7802 print STDERR Dumper \%apply_drone_run_band_project_ids_type_hash;
7803 my $drone_run_band_project_type_current = $apply_drone_run_band_project_ids_type_hash{$drone_run_band_project_id_input}->{band_type};
7805 my $gcp_drone_run_band_q = "SELECT project.project_id
7806 FROM project
7807 JOIN projectprop ON(project.project_id = projectprop.project_id)
7808 JOIN project_relationship ON(project.project_id=project_relationship.subject_project_id AND project_relationship.type_id=$drone_run_band_drone_run_project_relationship_type_id_cvterm_id)
7809 WHERE project_relationship.object_project_id=?
7810 AND projectprop.type_id=$drone_run_band_drone_run_project_type
7811 AND projectprop.value='$drone_run_band_project_type_current';";
7812 my $gcp_drone_run_band_h = $bcs_schema->storage->dbh()->prepare($gcp_drone_run_band_q);
7813 $gcp_drone_run_band_h->execute($gcp_drone_run_project_id_input);
7814 my ($gcp_drone_run_band_project_id) = $gcp_drone_run_band_h->fetchrow_array();
7816 my $rotate_angle_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_rotate_angle', 'project_property')->cvterm_id();
7817 my $cropping_polygon_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_cropped_polygon', 'project_property')->cvterm_id();
7818 my $plot_polygon_template_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
7819 my $drone_run_drone_run_band_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
7821 my $q = "SELECT rotate.value, plot_polygons.value, cropping.value, drone_run.project_id, drone_run.name
7822 FROM project AS drone_run_band
7823 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
7824 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
7825 JOIN projectprop AS rotate ON(drone_run_band.project_id = rotate.project_id AND rotate.type_id=$rotate_angle_type_id)
7826 JOIN projectprop AS plot_polygons ON(drone_run_band.project_id = plot_polygons.project_id AND plot_polygons.type_id=$plot_polygon_template_type_id)
7827 JOIN projectprop AS cropping ON(drone_run_band.project_id = cropping.project_id AND cropping.type_id=$cropping_polygon_type_id)
7828 WHERE drone_run_band.project_id = $gcp_drone_run_band_project_id;";
7830 my $h = $bcs_schema->storage->dbh()->prepare($q);
7831 $h->execute();
7832 my ($rotate_value, $plot_polygons_value_json, $cropping_value_json, $drone_run_project_id, $drone_run_project_name) = $h->fetchrow_array();
7833 print STDERR Dumper $rotate_value;
7834 print STDERR Dumper $cropping_value_json;
7835 print STDERR Dumper $plot_polygons_value_json;
7837 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
7838 my $processed_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_completed', 'project_property')->cvterm_id();
7839 my $processed_minimal_vi_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_vi_completed', 'project_property')->cvterm_id();
7840 my $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7841 type_id=>$process_indicator_cvterm_id,
7842 project_id=>$drone_run_project_id_input,
7843 rank=>0,
7844 value=>1
7847 key=>'projectprop_c1'
7850 my $drone_run_process_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7851 type_id=>$processed_cvterm_id,
7852 project_id=>$drone_run_project_id_input,
7853 rank=>0,
7854 value=>0
7857 key=>'projectprop_c1'
7860 my $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7861 type_id=>$processed_minimal_vi_cvterm_id,
7862 project_id=>$drone_run_project_id_input,
7863 rank=>0,
7864 value=>0
7867 key=>'projectprop_c1'
7870 my %selected_drone_run_band_types;
7872 my $q4 = "SELECT project_md_image.image_id, drone_run_band_type.value, drone_run_band.project_id
7873 FROM project AS drone_run_band
7874 JOIN projectprop AS drone_run_band_type ON(drone_run_band_type.project_id = drone_run_band.project_id AND drone_run_band_type.type_id = $drone_run_band_drone_run_project_type)
7875 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id = drone_run_band.project_id)
7876 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
7877 WHERE project_md_image.type_id = ?
7878 AND drone_run_band.project_id = ?
7879 AND metadata.md_image.obsolete = 'f';";
7880 my $h4 = $bcs_schema->storage->dbh()->prepare($q4);
7882 my $term_map = CXGN::DroneImagery::ImageTypes::get_base_imagery_observation_unit_plot_polygon_term_map();
7883 my %drone_run_band_info;
7884 foreach my $apply_drone_run_band_project_id (@$apply_drone_run_band_project_ids) {
7885 $h4->execute($project_image_type_id, $apply_drone_run_band_project_id);
7886 my ($image_id, $drone_run_band_type, $drone_run_band_project_id) = $h4->fetchrow_array();
7887 $selected_drone_run_band_types{$drone_run_band_type} = $drone_run_band_project_id;
7889 my $apply_image_width_ratio = 1;
7890 my $apply_image_height_ratio = 1;
7892 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
7893 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
7894 $archive_rotate_temp_image .= '.png';
7896 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $drone_run_band_project_id, $image_id, $rotate_value, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, 1, 0);
7897 my $rotated_image_id = $rotate_return->{rotated_image_id};
7899 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
7900 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
7901 $archive_temp_image .= '.png';
7903 my $cropping_return = _perform_image_cropping($c, $bcs_schema, $drone_run_band_project_id, $rotated_image_id, $cropping_value_json, $user_id, $user_name, $user_role, $archive_temp_image, $apply_image_width_ratio, $apply_image_height_ratio);
7904 my $cropped_image_id = $cropping_return->{cropped_image_id};
7906 $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
7907 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
7908 $archive_denoise_temp_image .= '.png';
7910 my $denoise_return = _perform_image_denoise($c, $bcs_schema, $metadata_schema, $cropped_image_id, $drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
7911 my $denoised_image_id = $denoise_return->{denoised_image_id};
7913 $drone_run_band_info{$drone_run_band_project_id} = {
7914 denoised_image_id => $denoised_image_id,
7915 rotate_value => $rotate_value,
7916 cropping_value => $cropping_value_json,
7917 drone_run_band_type => $drone_run_band_type,
7918 drone_run_project_id => $drone_run_project_id_input,
7919 drone_run_project_name => $drone_run_project_name,
7920 plot_polygons_value => $plot_polygons_value_json,
7921 check_resize => 1,
7922 keep_original_size_rotate => 0
7925 my @denoised_plot_polygon_type = @{$term_map->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{base}};
7926 my @denoised_background_threshold_removed_imagery_types = @{$term_map->{$drone_run_band_type}->{imagery_types}->{threshold_background}};
7927 my @denoised_background_threshold_removed_plot_polygon_types = @{$term_map->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{threshold_background}};
7929 foreach (@denoised_plot_polygon_type) {
7930 my $plot_polygon_original_denoised_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $plot_polygons_value_json, $_, $user_id, $user_name, $user_role, 0, 0, $apply_image_width_ratio, $apply_image_height_ratio, 'rectangular_square');
7933 for my $iterator (0..(scalar(@denoised_background_threshold_removed_imagery_types)-1)) {
7934 $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
7935 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
7936 $archive_remove_background_temp_image .= '.png';
7938 my $background_removed_threshold_return = _perform_image_background_remove_threshold_percentage($c, $bcs_schema, $denoised_image_id, $drone_run_band_project_id, $denoised_background_threshold_removed_imagery_types[$iterator], '25', '25', $user_id, $user_name, $user_role, $archive_remove_background_temp_image);
7940 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $background_removed_threshold_return->{removed_background_image_id}, $drone_run_band_project_id, $plot_polygons_value_json, $denoised_background_threshold_removed_plot_polygon_types[$iterator], $user_id, $user_name, $user_role, 0, 0, $apply_image_width_ratio, $apply_image_height_ratio, 'rectangular_square');
7944 print STDERR Dumper \%selected_drone_run_band_types;
7945 print STDERR Dumper \%vegetative_indices_hash;
7947 _perform_minimal_vi_standard_process($c, $bcs_schema, $metadata_schema, \%vegetative_indices_hash, \%selected_drone_run_band_types, \%drone_run_band_info, $user_id, $user_name, $user_role, 'rectangular_square');
7949 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7950 type_id=>$process_indicator_cvterm_id,
7951 project_id=>$drone_run_project_id_input,
7952 rank=>0,
7953 value=>0
7956 key=>'projectprop_c1'
7959 $drone_run_process_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7960 type_id=>$processed_cvterm_id,
7961 project_id=>$drone_run_project_id_input,
7962 rank=>0,
7963 value=>1
7966 key=>'projectprop_c1'
7969 $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
7970 type_id=>$processed_minimal_vi_cvterm_id,
7971 project_id=>$drone_run_project_id_input,
7972 rank=>0,
7973 value=>1
7976 key=>'projectprop_c1'
7979 my $return = _perform_phenotype_automated($c, $bcs_schema, $metadata_schema, $phenome_schema, $drone_run_project_id_input, $time_cvterm_id, $phenotype_methods, $standard_process_type, 1, undef, $user_id, $user_name, $user_role);
7981 my @result;
7982 $c->stash->{rest} = { data => \@result, success => 1 };
7985 sub standard_process_apply_raw_images_interactive : Path('/api/drone_imagery/standard_process_apply_raw_images_interactive') : ActionClass('REST') { }
7986 sub standard_process_apply_raw_images_interactive_POST : Args(0) {
7987 my $self = shift;
7988 my $c = shift;
7989 print STDERR Dumper $c->req->params();
7990 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
7991 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
7992 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
7993 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema', undef, $sp_person_id);
7994 my $apply_drone_run_band_project_ids = decode_json $c->req->param('apply_drone_run_band_project_ids');
7995 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
7996 my $drone_run_project_id_input = $c->req->param('drone_run_project_id');
7997 my $vegetative_indices = decode_json $c->req->param('vegetative_indices');
7998 my $phenotype_methods = $c->req->param('phenotype_types') ? decode_json $c->req->param('phenotype_types') : ['zonal'];
7999 my $time_cvterm_id = $c->req->param('time_cvterm_id');
8000 my $standard_process_type = $c->req->param('standard_process_type');
8001 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8003 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
8004 my $processed_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_standard_process_completed', 'project_property')->cvterm_id();
8005 my $processed_minimal_vi_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_standard_process_vi_completed', 'project_property')->cvterm_id();
8007 my $drone_run_process_in_progress = $schema->resultset('Project::Projectprop')->update_or_create({
8008 type_id=>$process_indicator_cvterm_id,
8009 project_id=>$drone_run_project_id_input,
8010 rank=>0,
8011 value=>1
8014 key=>'projectprop_c1'
8017 my $drone_run_process_completed = $schema->resultset('Project::Projectprop')->update_or_create({
8018 type_id=>$processed_cvterm_id,
8019 project_id=>$drone_run_project_id_input,
8020 rank=>0,
8021 value=>0
8024 key=>'projectprop_c1'
8027 my $drone_run_process_minimal_vi_completed = $schema->resultset('Project::Projectprop')->update_or_create({
8028 type_id=>$processed_minimal_vi_cvterm_id,
8029 project_id=>$drone_run_project_id_input,
8030 rank=>0,
8031 value=>0
8034 key=>'projectprop_c1'
8037 my %vegetative_indices_hash;
8038 foreach (@$vegetative_indices) {
8039 $vegetative_indices_hash{$_}++;
8042 my $saved_gps_positions_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_raw_images_saved_gps_pixel_positions', 'project_property')->cvterm_id();
8043 my $drone_run_band_saved_gps = $schema->resultset('Project::Projectprop')->find({
8044 type_id=>$saved_gps_positions_type_id,
8045 project_id=>$drone_run_project_id_input,
8047 my $saved_gps_positions_separated = decode_json $drone_run_band_saved_gps->value();
8049 my $drone_run_band_plot_polygons_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons_separated', 'project_property')->cvterm_id();
8050 my $previous_plot_polygons_rs = $schema->resultset('Project::Projectprop')->search({type_id=>$drone_run_band_plot_polygons_type_id, project_id=>$drone_run_band_project_id});
8051 if ($previous_plot_polygons_rs->count > 1) {
8052 $c->stash->{rest} = { error => "There should not be more than one saved entry for plot polygons for a drone run band" };
8053 $c->detach();
8056 my $save_stock_polygons_separated;
8057 if ($previous_plot_polygons_rs->count > 0) {
8058 $save_stock_polygons_separated = decode_json $previous_plot_polygons_rs->first->value;
8060 if (!$save_stock_polygons_separated) {
8061 $c->stash->{rest} = { error => "There are no stock polygons saved!" };
8062 $c->detach();
8064 # print STDERR Dumper $save_stock_polygons;
8065 # print STDERR Dumper $saved_gps_positions;
8067 #if (scalar(keys %$saved_gps_positions_separated) != scalar(keys %$save_stock_polygons_separated)) {
8068 # $c->stash->{rest} = { error => "The number of imaging passes is not equal for the image positions and the plot polygons!" };
8069 # $c->detach();
8072 my %polygons_images_positions;
8073 foreach my $flight_pass_counter (keys %$saved_gps_positions_separated) {
8074 my $saved_gps_positions = $saved_gps_positions_separated->{$flight_pass_counter};
8075 my $save_stock_polygons = $save_stock_polygons_separated->{$flight_pass_counter};
8077 while (my ($lat, $lo) = each %$saved_gps_positions) {
8078 while (my ($long, $pos) = each %$lo) {
8079 my $size = $pos->{image_size};
8080 my $rotated_bound = $pos->{rotated_bound_translated};
8081 my $x1_pos = $pos->{x_pos} + 0;
8082 my $y1_pos = $pos->{y_pos} + 0;
8083 my $x1_min = 10000000000;
8084 my $y1_min = 10000000000;
8085 foreach (@$rotated_bound) {
8086 if ($_->[0] < $x1_min) {
8087 $x1_min = $_->[0];
8089 if ($_->[1] < $y1_min) {
8090 $y1_min = $_->[1];
8094 my @image_bound = (@$rotated_bound, $rotated_bound->[0]);
8095 my $bound = Math::Polygon->new(points => \@image_bound);
8097 while (my ($plot_name, $points) = each %$save_stock_polygons) {
8098 my $polygon_x1 = $points->[0]->{x} + 0;
8099 my $polygon_y1 = $points->[0]->{y} + 0;
8100 my $polygon_x2 = $points->[1]->{x} + 0;
8101 my $polygon_y2 = $points->[1]->{y} + 0;
8102 my $polygon_x3 = $points->[2]->{x} + 0;
8103 my $polygon_y3 = $points->[2]->{y} + 0;
8104 my $polygon_x4 = $points->[3]->{x} + 0;
8105 my $polygon_y4 = $points->[3]->{y} + 0;
8107 if ($bound->contains([$polygon_x1,$polygon_y1]) && $bound->contains([$polygon_x2,$polygon_y2]) && $bound->contains([$polygon_x3,$polygon_y3]) && $bound->contains([$polygon_x4,$polygon_y4])) {
8108 my $points_shifted = [
8109 {'x' => $polygon_x1 - $x1_min, 'y' => $polygon_y1 - $y1_min},
8110 {'x' => $polygon_x2 - $x1_min, 'y' => $polygon_y2 - $y1_min},
8111 {'x' => $polygon_x3 - $x1_min, 'y' => $polygon_y3 - $y1_min},
8112 {'x' => $polygon_x4 - $x1_min, 'y' => $polygon_y4 - $y1_min},
8114 my $obj = {
8115 images => $pos,
8116 points => $points_shifted,
8117 image_bound => \@image_bound
8119 push @{$polygons_images_positions{$plot_name}}, $obj;
8120 } else {
8121 print STDERR "Polygon outside image!\n";
8127 # print STDERR Dumper \%polygons_images_positions;
8129 my $term_map = CXGN::DroneImagery::ImageTypes::get_base_imagery_observation_unit_plot_polygon_term_map();
8130 my $drone_image_types = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
8131 my @plot_polygon_type_ids = (
8132 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_blue_imagery', 'project_md_image')->cvterm_id(),
8133 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_green_imagery', 'project_md_image')->cvterm_id(),
8134 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_red_imagery', 'project_md_image')->cvterm_id(),
8135 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_nir_imagery', 'project_md_image')->cvterm_id(),
8136 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_red_edge_imagery', 'project_md_image')->cvterm_id()
8138 my @plot_polygon_type_objects;
8139 my @plot_polygon_type_tags;
8140 foreach (@plot_polygon_type_ids) {
8141 push @plot_polygon_type_objects, $drone_image_types->{$_};
8142 my $assign_plot_polygons_type = $drone_image_types->{$_}->{name};
8144 my $image_tag_id = CXGN::Tag::exists_tag_named($schema->storage->dbh, $assign_plot_polygons_type);
8145 if (!$image_tag_id) {
8146 my $image_tag = CXGN::Tag->new($schema->storage->dbh);
8147 $image_tag->set_name($assign_plot_polygons_type);
8148 $image_tag->set_description('Drone run band project type for plot polygon assignment: '.$assign_plot_polygons_type);
8149 $image_tag->set_sp_person_id($user_id);
8150 $image_tag_id = $image_tag->store();
8152 my $image_tag = CXGN::Tag->new($schema->storage->dbh, $image_tag_id);
8153 push @plot_polygon_type_tags, $image_tag;
8156 my %drone_run_band_info;
8157 my $band_counter = 0;
8159 my $dir = $c->tempfiles_subdir('/drone_imagery_plot_polygons');
8160 my $bulk_input_temp_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_plot_polygons/bulkinputXXXX');
8162 open(my $F, ">", $bulk_input_temp_file) || die "Can't open file ".$bulk_input_temp_file;
8163 # print STDERR Dumper \%polygons_images_positions;
8165 my $plot_polygon_type_hash = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
8166 my @input_bulk_hash;
8167 foreach my $apply_drone_run_band_project_id (@$apply_drone_run_band_project_ids) {
8168 while (my ($plot_name, $pi_array) = each %polygons_images_positions) {
8170 my $stock = $schema->resultset("Stock::Stock")->find({uniquename => $plot_name});
8171 if (!$stock) {
8172 $c->stash->{rest} = {error=>'Error: Stock name '.$plot_name.' does not exist in the database!'};
8173 $c->detach();
8175 my $stock_id = $stock->stock_id;
8177 foreach my $pi (@$pi_array) {
8178 my $points = $pi->{points};
8179 my $images = $pi->{images};
8180 my $image_ids = $images->{rotated_image_ids};
8182 my $current_image_id = $image_ids->[$band_counter];
8184 if ($current_image_id) {
8185 my $plot_polygon_json = encode_json [$points];
8187 my $linking_table_type_id = $plot_polygon_type_ids[$band_counter];
8188 my $corresponding_channel = $plot_polygon_type_hash->{$linking_table_type_id}->{corresponding_channel};
8190 my $image = SGN::Image->new( $schema->storage->dbh, $current_image_id, $c );
8191 my $image_url = $image->get_image_url("original");
8192 my $image_fullpath = $image->get_filename('original_converted', 'full');
8193 my $archive_plot_polygons_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_plot_polygons/imageXXXX');
8194 $archive_plot_polygons_temp_image .= '.png';
8196 print $F "$image_fullpath\t$archive_plot_polygons_temp_image\t$plot_polygon_json\trectangular_square\t$corresponding_channel\n";
8198 push @input_bulk_hash, {
8199 plot_temp_image => $archive_plot_polygons_temp_image,
8200 plot_id => $stock_id,
8201 band_counter => $band_counter,
8202 drone_run_band_project_id => $apply_drone_run_band_project_id
8204 # my $return = _perform_plot_polygon_assign_bulk($c, $bcs_schema, $metadata_schema, $current_image_id, $apply_drone_run_band_project_id, $plot_polygon_json, $plot_polygon_type, $user_id, $user_name, $user_role, 0, 1, 1, 1, 'rectangular_square');
8208 $band_counter++;
8210 close($F);
8211 # print STDERR Dumper \@input_bulk_hash;
8213 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/ImageCropping/CropToPolygonBulk.py --inputfile_path '$bulk_input_temp_file'";
8214 print STDERR Dumper $cmd;
8215 my $status = system("$cmd > /dev/null");
8217 my $number_system_cores = `getconf _NPROCESSORS_ONLN` or die "Could not get number of system cores!\n";
8218 chomp($number_system_cores);
8219 print STDERR "NUMCORES $number_system_cores\n";
8221 my $pm = Parallel::ForkManager->new(ceil($number_system_cores/4));
8222 $pm->run_on_finish( sub {
8223 my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
8226 foreach my $obj (@input_bulk_hash) {
8227 my $pid = $pm->start and next;
8229 my $archive_plot_polygons_temp_image = $obj->{plot_temp_image};
8230 my $stock_id = $obj->{plot_id};
8231 print STDERR Dumper $stock_id;
8232 my $drone_run_band_project_id = $obj->{drone_run_band_project_id};
8234 my $drone_run_band_project_type = $plot_polygon_type_objects[$band_counter]->{drone_run_project_types}->[0];
8235 my $plot_polygon_type = $plot_polygon_type_objects[$band_counter]->{name};
8236 my $image_tag = $plot_polygon_type_tags[$band_counter];
8237 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $plot_polygon_type, 'project_md_image')->cvterm_id();
8239 my $plot_polygon_image_fullpath;
8240 my $plot_polygon_image_url;
8241 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
8242 $image->set_sp_person_id($user_id);
8243 my $ret = $image->process_image($archive_plot_polygons_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
8244 my $stock_associate = $image->associate_stock($stock_id, $user_name);
8245 $plot_polygon_image_fullpath = $image->get_filename('original_converted', 'full');
8246 $plot_polygon_image_url = $image->get_image_url('original');
8247 my $added_image_tag_id = $image->add_tag($image_tag);
8249 $pm->finish(0, {});
8251 $pm->wait_all_children;
8253 $drone_run_process_in_progress = $schema->resultset('Project::Projectprop')->update_or_create({
8254 type_id=>$process_indicator_cvterm_id,
8255 project_id=>$drone_run_project_id_input,
8256 rank=>0,
8257 value=>0
8260 key=>'projectprop_c1'
8263 $drone_run_process_completed = $schema->resultset('Project::Projectprop')->update_or_create({
8264 type_id=>$processed_cvterm_id,
8265 project_id=>$drone_run_project_id_input,
8266 rank=>0,
8267 value=>1
8270 key=>'projectprop_c1'
8273 $drone_run_process_minimal_vi_completed = $schema->resultset('Project::Projectprop')->update_or_create({
8274 type_id=>$processed_minimal_vi_cvterm_id,
8275 project_id=>$drone_run_project_id_input,
8276 rank=>0,
8277 value=>1
8280 key=>'projectprop_c1'
8283 my $return = _perform_phenotype_automated($c, $schema, $metadata_schema, $phenome_schema, $drone_run_project_id_input, $time_cvterm_id, $phenotype_methods, $standard_process_type, 1, undef, $user_id, $user_name, $user_role);
8285 my @result;
8286 $c->stash->{rest} = { data => \@result, success => 1 };
8289 sub drone_imagery_get_vehicle : Path('/api/drone_imagery/get_vehicle') : ActionClass('REST') { }
8290 sub drone_imagery_get_vehicle_GET : Args(0) {
8291 my $self = shift;
8292 my $c = shift;
8293 $c->response->headers->header( "Access-Control-Allow-Origin" => '*' );
8294 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
8295 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
8296 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
8297 my $vehicle_id = $c->req->param('vehicle_id');
8298 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8300 my $imaging_vehicle_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'imaging_event_vehicle', 'stock_type')->cvterm_id();
8301 my $imaging_vehicle_properties_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'imaging_event_vehicle_json', 'stock_property')->cvterm_id();
8303 my $q = "SELECT stock.stock_id, stock.uniquename, stock.description, stockprop.value
8304 FROM stock
8305 JOIN stockprop ON(stock.stock_id=stockprop.stock_id AND stockprop.type_id=$imaging_vehicle_properties_cvterm_id)
8306 WHERE stock.type_id=$imaging_vehicle_cvterm_id";
8307 if ($vehicle_id) {
8308 $q .= " AND stock.stock_id=?"
8310 $q .= ";";
8311 my $h = $bcs_schema->storage->dbh()->prepare($q);
8312 if ($vehicle_id) {
8313 $h->execute($vehicle_id);
8315 else {
8316 $h->execute();
8318 my @vehicles;
8319 while (my ($stock_id, $name, $description, $prop) = $h->fetchrow_array()) {
8320 my $prop_hash = decode_json $prop;
8321 push @vehicles, {
8322 vehicle_id => $stock_id,
8323 name => $name,
8324 description => $description,
8325 properties => $prop_hash
8329 $c->stash->{rest} = { vehicles => \@vehicles, success => 1 };
8332 sub drone_imagery_get_vehicles : Path('/api/drone_imagery/imaging_vehicles') : ActionClass('REST') { }
8333 sub drone_imagery_get_vehicles_GET : Args(0) {
8334 my $self = shift;
8335 my $c = shift;
8336 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
8337 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
8338 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
8339 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8341 my $imaging_vehicle_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'imaging_event_vehicle', 'stock_type')->cvterm_id();
8342 my $imaging_vehicle_properties_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'imaging_event_vehicle_json', 'stock_property')->cvterm_id();
8344 my $q = "SELECT stock.stock_id, stock.uniquename, stock.description, stockprop.value
8345 FROM stock
8346 JOIN stockprop ON(stock.stock_id=stockprop.stock_id AND stockprop.type_id=$imaging_vehicle_properties_cvterm_id)
8347 WHERE stock.type_id=$imaging_vehicle_cvterm_id;";
8348 my $h = $bcs_schema->storage->dbh()->prepare($q);
8349 $h->execute();
8350 my @vehicles;
8351 while (my ($stock_id, $name, $description, $prop) = $h->fetchrow_array()) {
8352 my $prop_hash = decode_json $prop;
8353 my @batt_info;
8354 foreach (sort keys %{$prop_hash->{batteries}}) {
8355 my $p = $prop_hash->{batteries}->{$_};
8356 push @batt_info, "$_: Usage = ".$p->{usage}." Obsolete = ".$p->{obsolete};
8358 my $batt_info_string = join '<br/>', @batt_info;
8359 push @vehicles, [$name, $description, $batt_info_string]
8362 $c->stash->{rest} = { data => \@vehicles };
8365 sub drone_imagery_accession_phenotype_histogram : Path('/api/drone_imagery/accession_phenotype_histogram') : ActionClass('REST') { }
8366 sub drone_imagery_accession_phenotype_histogram_GET : Args(0) {
8367 my $self = shift;
8368 my $c = shift;
8369 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
8370 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
8371 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
8372 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8373 my $plot_id = $c->req->param('plot_id');
8374 my $accession_id = $c->req->param('accession_id');
8375 my $trait_id = $c->req->param('trait_id');
8376 my $field_trial_id = $c->req->param('field_trial_id');
8377 my $figure_type = $c->req->param('figure_type');
8379 my $dir = $c->tempfiles_subdir('/drone_imagery_pheno_plot_dir');
8380 my $phenos_tempfile = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_pheno_plot_dir/phenoXXXX');
8381 my $pheno_plot_tempfile = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_pheno_plot_dir/phenoplotXXXX');
8382 my $pheno_accession_tempfile = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_pheno_plot_dir/phenoplotaccXXXX');
8383 my $pheno_figure_tempfile_string = $c->tempfile( TEMPLATE => 'drone_imagery_pheno_plot_dir/figureXXXX');
8384 my $pheno_figure_tempfile = $c->config->{basepath}."/".$pheno_figure_tempfile_string;
8386 my $search_params = {
8387 bcs_schema=>$bcs_schema,
8388 data_level=>'all',
8389 trait_list=>[$trait_id],
8390 include_timestamp=>0,
8391 exclude_phenotype_outlier=>0
8394 # Comparing plot_id pheno against all phenotypes in trial
8395 if ($field_trial_id && $figure_type eq 'all_pheno_of_this_trial') {
8396 $search_params->{trial_list} = [$field_trial_id];
8398 # Comparing plot_id pheno against all phenotypes for accession
8399 if ($accession_id && $figure_type eq 'all_pheno_of_this_accession'){
8400 $search_params->{accession_list} = [$accession_id];
8403 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
8404 'MaterializedViewTable',
8405 $search_params
8407 my ($data, $unique_traits) = $phenotypes_search->search();
8408 my @sorted_trait_names = sort keys %$unique_traits;
8410 if (scalar(@$data) == 0) {
8411 $c->stash->{rest} = { error => "There are no phenotypes for the trait you have selected in the current field trial!"};
8412 $c->detach();
8415 my @accession_phenotypes;
8416 if ($accession_id) {
8417 my $accession_phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
8418 'MaterializedViewTable',
8420 bcs_schema=>$bcs_schema,
8421 data_level=>'plot',
8422 trait_list=>[$trait_id],
8423 accession_list=>[$accession_id],
8424 include_timestamp=>0,
8425 exclude_phenotype_outlier=>0
8428 my ($accession_data, $accession_unique_traits) = $accession_phenotypes_search->search();
8429 my @accession_sorted_trait_names = sort keys %$accession_unique_traits;
8431 foreach my $obs_unit (@$accession_data){
8432 my $observations = $obs_unit->{observations};
8433 foreach (@$observations){
8434 push @accession_phenotypes, $_->{value};
8439 my $plot_phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
8440 'MaterializedViewTable',
8442 bcs_schema=>$bcs_schema,
8443 data_level=>'plot',
8444 trait_list=>[$trait_id],
8445 plot_list=>[$plot_id],
8446 include_timestamp=>0,
8447 exclude_phenotype_outlier=>0
8450 my ($plot_data, $plot_unique_traits) = $plot_phenotypes_search->search();
8451 my @plot_sorted_trait_names = sort keys %$plot_unique_traits;
8453 my @all_phenotypes;
8454 foreach my $obs_unit (@$data){
8455 my $observations = $obs_unit->{observations};
8456 foreach (@$observations){
8457 push @all_phenotypes, $_->{value};
8461 my @plot_phenotypes;
8462 foreach my $obs_unit (@$plot_data){
8463 my $observations = $obs_unit->{observations};
8464 foreach (@$observations){
8465 push @plot_phenotypes, $_->{value};
8469 open(my $F, ">", $phenos_tempfile) || die "Can't open file ".$phenos_tempfile;
8470 print $F "phenotype\n";
8471 foreach (@all_phenotypes) {
8472 print $F "$_\n";
8474 close($F);
8476 open(my $F2, ">", $pheno_plot_tempfile) || die "Can't open file ".$pheno_plot_tempfile;
8477 print $F2 "phenotype\n";
8478 foreach (@plot_phenotypes) {
8479 print $F2 "$_\n";
8481 close($F2);
8483 open(my $F3, ">", $pheno_accession_tempfile) || die "Can't open file ".$pheno_accession_tempfile;
8484 print $F3 "phenotype\n";
8485 foreach (@accession_phenotypes) {
8486 print $F3 "$_\n";
8488 close($F3);
8490 my $cmd = 'R -e "library(ggplot2);
8491 options(device=\'png\');
8492 par();
8493 pheno_all <- read.table(\''.$phenos_tempfile.'\', header=TRUE, sep=\',\');
8494 pheno_plot <- read.table(\''.$pheno_plot_tempfile.'\', header=TRUE, sep=\',\');
8495 pheno_accession <- read.table(\''.$pheno_accession_tempfile.'\', header=TRUE, sep=\',\');
8496 sp <- ggplot(pheno_all, aes(x=phenotype)) + geom_histogram();
8497 if (length(pheno_plot\$phenotype) > 0) {
8498 sp <- sp + geom_vline(xintercept = pheno_plot\$phenotype[1], color = \'red\', size=1.2);
8500 if (length(pheno_accession\$phenotype) > 0) {
8501 sp <- sp + geom_vline(xintercept = mean(pheno_accession\$phenotype), color = \'green\', size=1.2);
8503 ggsave(\''.$pheno_figure_tempfile.'\', sp, device=\'png\', width=3, height=3, units=\'in\');
8504 dev.off();"';
8505 print STDERR Dumper $cmd;
8506 my $status = system("$cmd > /dev/null");
8508 $c->stash->{rest} = { success => 1, figure => $pheno_figure_tempfile_string };
8511 sub drone_imagery_save_single_plot_image : Path('/api/drone_imagery/save_single_plot_image') : ActionClass('REST') { }
8512 sub drone_imagery_save_single_plot_image_POST : Args(0) {
8513 my $self = shift;
8514 my $c = shift;
8515 $c->response->headers->header( "Access-Control-Allow-Origin" => '*' );
8516 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
8517 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
8518 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
8519 my $observation_unit_id = $c->req->param('observation_unit_id');
8520 my $drone_run_band_project_id_input = $c->req->param('drone_run_band_project_id');
8521 my $image_input = $c->req->upload('image');
8522 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8524 my %expected_types = (
8525 'observation_unit_polygon_blue_imagery' => 1,
8526 'observation_unit_polygon_green_imagery' => 1,
8527 'observation_unit_polygon_red_imagery' => 1,
8528 'observation_unit_polygon_nir_imagery' => 1,
8529 'observation_unit_polygon_red_edge_imagery' => 1
8532 my $drone_run_band_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
8533 my $q = "SELECT name,value FROM projectprop JOIN project USING(project_id) WHERE type_id=$drone_run_band_type_cvterm_id and project_id=?;";
8534 my $h = $bcs_schema->storage->dbh()->prepare($q);
8535 $h->execute($drone_run_band_project_id_input);
8536 my ($project_band_name, $project_band_type) = $h->fetchrow_array();
8537 if (!$project_band_name || !$project_band_type) {
8538 $c->stash->{rest} = { error => "Drone run band not found or the drone run band is not of a known type!" };
8539 $c->detach();
8542 my $plot_polygon_types = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($bcs_schema);
8543 my %band_type_image_hash;
8544 while ( my ($plot_image_type_id, $o) = each %$plot_polygon_types) {
8545 foreach my $band_type (@{$o->{drone_run_project_types}}) {
8546 if ($band_type eq $project_band_type && exists($expected_types{$o->{name}})) {
8547 $band_type_image_hash{$band_type} = {
8548 cvterm_id => $plot_image_type_id,
8549 name => $o->{name}
8554 my $linking_table_type_id = $band_type_image_hash{$project_band_type}->{cvterm_id};
8555 my $assign_plot_polygons_type = $band_type_image_hash{$project_band_type}->{name};
8557 my $image_tag_id = CXGN::Tag::exists_tag_named($bcs_schema->storage->dbh, $assign_plot_polygons_type);
8558 if (!$image_tag_id) {
8559 my $image_tag = CXGN::Tag->new($bcs_schema->storage->dbh);
8560 $image_tag->set_name($assign_plot_polygons_type);
8561 $image_tag->set_description('Drone run band project type for plot polygon assignment: '.$assign_plot_polygons_type);
8562 $image_tag->set_sp_person_id($user_id);
8563 $image_tag_id = $image_tag->store();
8565 my $image_tag = CXGN::Tag->new($bcs_schema->storage->dbh, $image_tag_id);
8567 if (!$image_input) {
8568 $c->stash->{rest} = { error => "ERROR!" };
8569 $c->detach();
8571 my $image_input_filename = $image_input->tempname();
8572 if (!$image_input_filename) {
8573 $c->stash->{rest} = { error => "ERROR! filename" };
8574 $c->detach();
8577 my $stock = $bcs_schema->resultset("Stock::Stock")->find({stock_id => $observation_unit_id});
8578 if (!$stock) {
8579 $c->stash->{rest} = {error=>'Error: Stock '.$observation_unit_id.' does not exist in the database!'};
8580 $c->detach();
8583 my $image = SGN::Image->new( $bcs_schema->storage->dbh, undef, $c );
8584 $image->set_sp_person_id($user_id);
8585 my $ret = $image->process_image($image_input_filename, 'project', $drone_run_band_project_id_input, $linking_table_type_id);
8586 my $stock_associate = $image->associate_stock($observation_unit_id, $user_name);
8587 my $plot_polygon_image_fullpath = $image->get_filename('original_converted', 'full');
8588 my $plot_polygon_image_url = $image->get_image_url('original');
8589 my $added_image_tag_id = $image->add_tag($image_tag);
8591 $c->stash->{rest} = { success => 1 };
8594 sub standard_process_minimal_vi_apply : Path('/api/drone_imagery/standard_process_minimal_vi_apply') : ActionClass('REST') { }
8595 sub standard_process_minimal_vi_apply_POST : Args(0) {
8596 my $self = shift;
8597 my $c = shift;
8598 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
8599 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
8600 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
8601 my $drone_run_project_id_input = $c->req->param('drone_run_project_id');
8602 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8604 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
8605 my $processed_minimal_vi_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_vi_completed', 'project_property')->cvterm_id();
8606 my $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8607 type_id=>$process_indicator_cvterm_id,
8608 project_id=>$drone_run_project_id_input,
8609 rank=>0,
8610 value=>1
8613 key=>'projectprop_c1'
8616 my $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8617 type_id=>$processed_minimal_vi_cvterm_id,
8618 project_id=>$drone_run_project_id_input,
8619 rank=>0,
8620 value=>0
8623 key=>'projectprop_c1'
8626 my $extended_process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
8627 my $extended_processed_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_extended_completed', 'project_property')->cvterm_id();
8628 my $extended_drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8629 type_id=>$extended_process_indicator_cvterm_id,
8630 project_id=>$drone_run_project_id_input,
8631 rank=>0,
8632 value=>1
8635 key=>'projectprop_c1'
8638 $extended_drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8639 type_id=>$extended_processed_cvterm_id,
8640 project_id=>$drone_run_project_id_input,
8641 rank=>0,
8642 value=>0
8645 key=>'projectprop_c1'
8648 my %vegetative_indices_hash = (
8649 'TGI' => 1,
8650 'VARI' => 1,
8651 'NDVI' => 1,
8652 'NDRE' => 1
8655 my $rotate_angle_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_rotate_angle', 'project_property')->cvterm_id();
8656 my $cropping_polygon_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_cropped_polygon', 'project_property')->cvterm_id();
8657 my $plot_polygon_template_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
8658 my $drone_run_drone_run_band_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
8659 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
8660 my $drone_run_band_type_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
8662 my %selected_drone_run_band_types;
8663 my %drone_run_band_info;
8664 my $q = "SELECT rotate.value, plot_polygons.value, cropping.value, drone_run.project_id, drone_run.name, drone_run_band.project_id, drone_run_band.name, drone_run_band_type.value, project_md_image.image_id
8665 FROM project AS drone_run_band
8666 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
8667 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
8668 JOIN projectprop AS rotate ON(drone_run_band.project_id = rotate.project_id AND rotate.type_id=$rotate_angle_type_id)
8669 JOIN projectprop AS plot_polygons ON(drone_run_band.project_id = plot_polygons.project_id AND plot_polygons.type_id=$plot_polygon_template_type_id)
8670 JOIN projectprop AS cropping ON(drone_run_band.project_id = cropping.project_id AND cropping.type_id=$cropping_polygon_type_id)
8671 JOIN projectprop AS drone_run_band_type ON(drone_run_band_type.project_id = drone_run_band.project_id AND drone_run_band_type.type_id = $drone_run_band_type_type_id)
8672 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id=drone_run_band.project_id AND project_md_image.type_id = $project_image_type_id)
8673 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
8674 WHERE drone_run.project_id = $drone_run_project_id_input
8675 AND metadata.md_image.obsolete = 'f';";
8677 my $h = $bcs_schema->storage->dbh()->prepare($q);
8678 $h->execute();
8679 while (my ($rotate_value, $plot_polygons_value, $cropping_value, $drone_run_project_id, $drone_run_project_name, $drone_run_band_project_id, $drone_run_band_project_name, $drone_run_band_type, $denoised_image_id) = $h->fetchrow_array()) {
8680 $selected_drone_run_band_types{$drone_run_band_type} = $drone_run_band_project_id;
8681 $drone_run_band_info{$drone_run_band_project_id} = {
8682 drone_run_project_id => $drone_run_project_id,
8683 drone_run_project_name => $drone_run_project_name,
8684 drone_run_band_project_id => $drone_run_band_project_id,
8685 drone_run_band_project_name => $drone_run_band_project_name,
8686 drone_run_band_type => $drone_run_band_type,
8687 rotate_value => $rotate_value,
8688 plot_polygons_value => $plot_polygons_value,
8689 cropping_value => $cropping_value,
8690 denoised_image_id => $denoised_image_id,
8691 check_resize => 1,
8692 keep_original_size_rotate => 0
8696 print STDERR Dumper \%selected_drone_run_band_types;
8697 print STDERR Dumper \%vegetative_indices_hash;
8699 _perform_minimal_vi_standard_process($c, $bcs_schema, $metadata_schema, \%vegetative_indices_hash, \%selected_drone_run_band_types, \%drone_run_band_info, $user_id, $user_name, $user_role, 'rectangular_square');
8701 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8702 type_id=>$process_indicator_cvterm_id,
8703 project_id=>$drone_run_project_id_input,
8704 rank=>0,
8705 value=>0
8708 key=>'projectprop_c1'
8711 $drone_run_process_minimal_vi_completed = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8712 type_id=>$processed_minimal_vi_cvterm_id,
8713 project_id=>$drone_run_project_id_input,
8714 rank=>0,
8715 value=>1
8718 key=>'projectprop_c1'
8721 _perform_extended_vi_standard_process($c, $bcs_schema, $metadata_schema, \%vegetative_indices_hash, \%selected_drone_run_band_types, \%drone_run_band_info, $user_id, $user_name, $user_role);
8723 $extended_drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8724 type_id=>$extended_process_indicator_cvterm_id,
8725 project_id=>$drone_run_project_id_input,
8726 rank=>0,
8727 value=>0
8730 key=>'projectprop_c1'
8733 $extended_drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8734 type_id=>$extended_processed_cvterm_id,
8735 project_id=>$drone_run_project_id_input,
8736 rank=>0,
8737 value=>1
8740 key=>'projectprop_c1'
8743 my @result;
8744 $c->stash->{rest} = { data => \@result, success => 1 };
8747 sub standard_process_extended_apply : Path('/api/drone_imagery/standard_process_extended_apply') : ActionClass('REST') { }
8748 sub standard_process_extended_apply_GET : Args(0) {
8749 my $self = shift;
8750 my $c = shift;
8751 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
8752 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
8753 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
8754 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema', undef, $sp_person_id);
8755 my $drone_run_project_id_input = $c->req->param('drone_run_project_id');
8756 my $time_cvterm_id = $c->req->param('time_days_cvterm_id');
8757 my $standard_process_type = $c->req->param('standard_process_type');
8758 my $phenotype_methods = $c->req->param('phenotype_types') ? decode_json $c->req->param('phenotype_types') : ['zonal'];
8759 my ($user_id, $user_name, $user_role) = _check_user_login($c);
8761 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
8762 my $processed_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_standard_process_extended_completed', 'project_property')->cvterm_id();
8763 my $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8764 type_id=>$process_indicator_cvterm_id,
8765 project_id=>$drone_run_project_id_input,
8766 rank=>0,
8767 value=>1
8770 key=>'projectprop_c1'
8773 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8774 type_id=>$processed_cvterm_id,
8775 project_id=>$drone_run_project_id_input,
8776 rank=>0,
8777 value=>0
8780 key=>'projectprop_c1'
8783 my %vegetative_indices_hash = (
8784 'TGI' => 1,
8785 'VARI' => 1,
8786 'NDVI' => 1,
8787 'NDRE' => 1
8790 my $rotate_angle_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_rotate_angle', 'project_property')->cvterm_id();
8791 my $cropping_polygon_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_cropped_polygon', 'project_property')->cvterm_id();
8792 my $plot_polygon_template_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
8793 my $drone_run_drone_run_band_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
8794 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
8795 my $drone_run_band_type_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
8797 my %selected_drone_run_band_types;
8798 my %drone_run_band_info;
8799 my $q = "SELECT rotate.value, plot_polygons.value, cropping.value, drone_run.project_id, drone_run.name, drone_run_band.project_id, drone_run_band.name, drone_run_band_type.value, project_md_image.image_id
8800 FROM project AS drone_run_band
8801 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
8802 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
8803 JOIN projectprop AS rotate ON(drone_run_band.project_id = rotate.project_id AND rotate.type_id=$rotate_angle_type_id)
8804 JOIN projectprop AS plot_polygons ON(drone_run_band.project_id = plot_polygons.project_id AND plot_polygons.type_id=$plot_polygon_template_type_id)
8805 JOIN projectprop AS cropping ON(drone_run_band.project_id = cropping.project_id AND cropping.type_id=$cropping_polygon_type_id)
8806 JOIN projectprop AS drone_run_band_type ON(drone_run_band_type.project_id = drone_run_band.project_id AND drone_run_band_type.type_id = $drone_run_band_type_type_id)
8807 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id=drone_run_band.project_id AND project_md_image.type_id = $project_image_type_id)
8808 WHERE drone_run.project_id = $drone_run_project_id_input;";
8810 my $h = $bcs_schema->storage->dbh()->prepare($q);
8811 $h->execute();
8812 while (my ($rotate_value, $plot_polygons_value, $cropping_value, $drone_run_project_id, $drone_run_project_name, $drone_run_band_project_id, $drone_run_band_project_name, $drone_run_band_type, $denoised_image_id) = $h->fetchrow_array()) {
8813 $selected_drone_run_band_types{$drone_run_band_type} = $drone_run_band_project_id;
8814 $drone_run_band_info{$drone_run_band_project_id} = {
8815 drone_run_project_name => $drone_run_project_name,
8816 drone_run_project_id => $drone_run_project_id,
8817 drone_run_band_project_id => $drone_run_band_project_id,
8818 drone_run_band_project_name => $drone_run_band_project_name,
8819 drone_run_band_type => $drone_run_band_type,
8820 rotate_value => $rotate_value,
8821 plot_polygons_value => $plot_polygons_value,
8822 cropping_value => $cropping_value,
8823 denoised_image_id => $denoised_image_id
8827 my $original_denoised_imagery_terms = CXGN::DroneImagery::ImageTypes::get_base_imagery_observation_unit_plot_polygon_term_map();
8829 my $q2 = "SELECT project_md_image.image_id
8830 FROM project AS drone_run_band
8831 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id=drone_run_band.project_id AND project_md_image.type_id = ?)
8832 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
8833 WHERE drone_run_band.project_id = ?
8834 AND metadata.md_image.obsolete = 'f';";
8836 my $h2 = $bcs_schema->storage->dbh()->prepare($q2);
8837 foreach (keys %drone_run_band_info) {
8838 my $threshold_term = $original_denoised_imagery_terms->{$drone_run_band_info{$_}->{drone_run_band_type}}->{imagery_types}->{threshold_background};
8839 if ($threshold_term) {
8840 my $image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, $threshold_term, 'project_md_image')->cvterm_id();
8841 $h2->execute($image_type_id, $_);
8842 my ($threshold_image_id) = $h2->fetchrow_array();
8843 $drone_run_band_info{$_}->{thresholded_image_id} = $threshold_image_id;
8847 foreach my $drone_run_band_project_id (keys %drone_run_band_info) {
8848 my $image_id = $drone_run_band_info{$drone_run_band_project_id}->{denoised_image_id};
8849 my $drone_run_band_type = $drone_run_band_info{$drone_run_band_project_id}->{drone_run_band_type};
8850 my $denoised_image_id = $drone_run_band_info{$drone_run_band_project_id}->{denoised_image_id};
8851 my $plot_polygons_value = $drone_run_band_info{$drone_run_band_project_id}->{plot_polygons_value};
8852 my $background_removed_threshold_image_id = $drone_run_band_info{$drone_run_band_project_id}->{thresholded_image_id};
8854 if ($original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{20}) {
8855 my @ft_hpf20_imagery_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{20}};
8856 my @ft_hpf30_imagery_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{30}};
8857 my @ft_hpf40_imagery_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{40}};
8858 my @ft_hpf20_plot_polygon_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{ft_hpf}->{20}};
8859 my @ft_hpf30_plot_polygon_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{ft_hpf}->{30}};
8860 my @ft_hpf40_plot_polygon_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{ft_hpf}->{40}};
8861 my @ft_hpf20_background_threshold_removed_imagery_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{'20_threshold_background'}};
8862 my @ft_hpf30_background_threshold_removed_imagery_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{'30_threshold_background'}};
8863 my @ft_hpf40_background_threshold_removed_imagery_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{imagery_types}->{ft_hpf}->{'40_threshold_background'}};
8864 my @ft_hpf20_background_threshold_removed_plot_polygon_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{ft_hpf}->{'20_threshold_background'}};
8865 my @ft_hpf30_background_threshold_removed_plot_polygon_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{ft_hpf}->{'30_threshold_background'}};
8866 my @ft_hpf40_background_threshold_removed_plot_polygon_types = @{$original_denoised_imagery_terms->{$drone_run_band_type}->{observation_unit_plot_polygon_types}->{ft_hpf}->{'40_threshold_background'}};
8868 for my $iterator (0..(scalar(@ft_hpf20_imagery_types)-1)) {
8869 _perform_extended_base_standard_process($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf20_imagery_types[$iterator], $ft_hpf20_plot_polygon_types[$iterator], $ft_hpf30_imagery_types[$iterator], $ft_hpf30_plot_polygon_types[$iterator], $ft_hpf40_imagery_types[$iterator], $ft_hpf40_plot_polygon_types[$iterator], $background_removed_threshold_image_id, $ft_hpf20_background_threshold_removed_imagery_types[$iterator], $ft_hpf20_background_threshold_removed_plot_polygon_types[$iterator], $ft_hpf30_background_threshold_removed_imagery_types[$iterator], $ft_hpf30_background_threshold_removed_plot_polygon_types[$iterator], $ft_hpf40_background_threshold_removed_imagery_types[$iterator], $ft_hpf40_background_threshold_removed_plot_polygon_types[$iterator], $user_id, $user_name, $user_role);
8874 print STDERR Dumper \%selected_drone_run_band_types;
8875 print STDERR Dumper \%vegetative_indices_hash;
8877 _perform_extended_vi_standard_process($c, $bcs_schema, $metadata_schema, \%vegetative_indices_hash, \%selected_drone_run_band_types, \%drone_run_band_info, $user_id, $user_name, $user_role);
8879 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8880 type_id=>$process_indicator_cvterm_id,
8881 project_id=>$drone_run_project_id_input,
8882 rank=>0,
8883 value=>0
8886 key=>'projectprop_c1'
8889 $drone_run_process_in_progress = $bcs_schema->resultset('Project::Projectprop')->update_or_create({
8890 type_id=>$processed_cvterm_id,
8891 project_id=>$drone_run_project_id_input,
8892 rank=>0,
8893 value=>1
8896 key=>'projectprop_c1'
8899 my $return = _perform_phenotype_automated($c, $bcs_schema, $metadata_schema, $phenome_schema, $drone_run_project_id_input, $time_cvterm_id, $phenotype_methods, $standard_process_type, 1, undef, $user_id, $user_name, $user_role);
8901 $c->stash->{rest} = {success => 1};
8904 sub _perform_standard_process_minimal_vi_calc {
8905 my $c = shift;
8906 my $bcs_schema = shift;
8907 my $metadata_schema = shift;
8908 my $denoised_image_id = shift;
8909 my $merged_drone_run_band_project_id = shift;
8910 my $user_id = shift;
8911 my $user_name = shift;
8912 my $user_role = shift;
8913 my $plot_polygons_value = shift;
8914 my $vi = shift;
8915 my $bands = shift;
8916 my $cropping_polygon_type = shift || 'rectangular_square';
8918 my $vi_map_hash = CXGN::DroneImagery::ImageTypes::get_vegetative_index_image_type_term_map();
8919 my %vi_map = %$vi_map_hash;
8921 my $index_return = _perform_vegetative_index_calculation($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $vi, 0, $bands, $user_id, $user_name, $user_role);
8922 my $index_image_id = $index_return->{index_image_id};
8924 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $index_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{index}->{(%{$vi_map{$vi}->{index}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, $cropping_polygon_type);
8927 sub _perform_standard_process_extended_vi_calc {
8928 my $c = shift;
8929 my $bcs_schema = shift;
8930 my $metadata_schema = shift;
8931 my $denoised_image_id = shift;
8932 my $merged_drone_run_band_project_id = shift;
8933 my $user_id = shift;
8934 my $user_name = shift;
8935 my $user_role = shift;
8936 my $plot_polygons_value = shift;
8937 my $vi = shift;
8938 my $bands = shift;
8940 my $vi_map_hash = CXGN::DroneImagery::ImageTypes::get_vegetative_index_image_type_term_map();
8941 my %vi_map = %$vi_map_hash;
8942 my $index_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, (%{$vi_map{$vi}->{index}})[0], 'project_md_image')->cvterm_id();
8943 my $q = "SELECT project_md_image.image_id
8944 FROM project AS drone_run_band
8945 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.project_id=drone_run_band.project_id AND project_md_image.type_id = $index_image_type_id)
8946 JOIN metadata.md_image ON(project_md_image.image_id = metadata.md_image.image_id)
8947 WHERE drone_run_band.project_id = $merged_drone_run_band_project_id
8948 AND metadata.md_image.obsolete = 'f';";
8949 my $h = $bcs_schema->storage->dbh()->prepare($q);
8950 $h->execute();
8951 my ($index_image_id) = $h->fetchrow_array();
8953 #my $fourier_transform_hpf20_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $index_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
8955 #my $plot_polygon_ft_hpf20_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20}->{(%{$vi_map{$vi}->{ft_hpf20}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8957 #my $fourier_transform_hpf30_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $index_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
8959 #my $plot_polygon_ft_hpf30_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30}->{(%{$vi_map{$vi}->{ft_hpf30}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8961 #my $fourier_transform_hpf40_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $index_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
8963 #my $plot_polygon_ft_hpf40_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40}->{(%{$vi_map{$vi}->{ft_hpf40}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8965 my $dir = $c->tempfiles_subdir('/drone_imagery_remove_background');
8966 my $archive_remove_background_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_remove_background/imageXXXX');
8967 $archive_remove_background_temp_image .= '.png';
8969 my $background_removed_threshold_return = _perform_image_background_remove_threshold_percentage($c, $bcs_schema, $index_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{index_threshold_background}})[0], '25', '25', $user_id, $user_name, $user_role, $archive_remove_background_temp_image);
8970 my $background_removed_threshold_image_id = $background_removed_threshold_return->{removed_background_image_id};
8972 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{index_threshold_background}->{(%{$vi_map{$vi}->{index_threshold_background}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8974 #my $fourier_transform_hpf20_thresholded_vi_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_index_threshold_background}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
8976 #$plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_thresholded_vi_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_index_threshold_background}->{(%{$vi_map{$vi}->{ft_hpf20_index_threshold_background}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8978 #my $fourier_transform_hpf30_thresholded_vi_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_index_threshold_background}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
8980 #$plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_thresholded_vi_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_index_threshold_background}->{(%{$vi_map{$vi}->{ft_hpf30_index_threshold_background}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8982 #my $fourier_transform_hpf40_thresholded_vi_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_index_threshold_background}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
8984 #$plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_thresholded_vi_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_index_threshold_background}->{(%{$vi_map{$vi}->{ft_hpf40_index_threshold_background}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1);
8986 #my $threshold_masked_return = _perform_image_background_remove_mask($c, $bcs_schema, $denoised_image_id, $background_removed_threshold_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{original_thresholded_index_mask_background}})[0], $user_id, $user_name, $user_role);
8987 #my $threshold_masked_image_id = $threshold_masked_return->{masked_image_id};
8989 #$plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_thresholded_index_mask_background}->{(%{$vi_map{$vi}->{original_thresholded_index_mask_background}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8991 #$plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_thresholded_index_mask_background}->{(%{$vi_map{$vi}->{original_thresholded_index_mask_background}})[0]}->[1], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8993 #$plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_thresholded_index_mask_background}->{(%{$vi_map{$vi}->{original_thresholded_index_mask_background}})[0]}->[2], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8995 #if ($vi_map{$vi}->{original_thresholded_index_mask_background}->{(%{$vi_map{$vi}->{original_thresholded_index_mask_background}})[0]}->[3]) {
8996 # $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_thresholded_index_mask_background}->{(%{$vi_map{$vi}->{original_thresholded_index_mask_background}})[0]}->[3], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
8999 #my $fourier_transform_hpf20_original_background_removed_thresholded_vi_mask_channel_1_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_1}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
9001 #my $plot_polygon_ft_hpf20_background_threshold_mask_channel_1_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_original_background_removed_thresholded_vi_mask_channel_1_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_1}->{(%{$vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_1}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9003 #my $fourier_transform_hpf30_original_background_removed_thresholded_vi_mask_channel_1_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_1}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
9005 #my $plot_polygon_ft_hpf30_background_threshold_mask_channel_1_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_original_background_removed_thresholded_vi_mask_channel_1_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_1}->{(%{$vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_1}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9007 #my $fourier_transform_hpf40_original_background_removed_thresholded_vi_mask_channel_1_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_1}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
9009 #my $plot_polygon_ft_hpf40_background_threshold_mask_channel_1_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_original_background_removed_thresholded_vi_mask_channel_1_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_1}->{(%{$vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_1}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9011 #my $fourier_transform_hpf20_original_background_removed_thresholded_vi_mask_channel_2_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_2}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
9013 #my $plot_polygon_ft_hpf20_background_threshold_mask_channel_2_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_original_background_removed_thresholded_vi_mask_channel_2_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_2}->{(%{$vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_2}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9015 #my $fourier_transform_hpf30_original_background_removed_thresholded_vi_mask_channel_2_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_2}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
9017 #my $plot_polygon_ft_hpf30_background_threshold_mask_channel_2_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_original_background_removed_thresholded_vi_mask_channel_2_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_2}->{(%{$vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_2}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9019 #my $fourier_transform_hpf40_original_background_removed_thresholded_vi_mask_channel_2_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_2}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
9021 #my $plot_polygon_ft_hpf40_background_threshold_mask_channel_2_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_original_background_removed_thresholded_vi_mask_channel_2_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_2}->{(%{$vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_2}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9023 #if ($vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_3}) {
9024 # my $fourier_transform_hpf20_original_background_removed_thresholded_vi_mask_channel_3_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_3}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
9026 # my $plot_polygon_ft_hpf20_background_threshold_mask_channel_3_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_original_background_removed_thresholded_vi_mask_channel_3_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_3}->{(%{$vi_map{$vi}->{ft_hpf20_original_thresholded_index_mask_background_channel_3}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9029 #if ($vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_3}) {
9030 # my $fourier_transform_hpf30_original_background_removed_thresholded_vi_mask_channel_3_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_3}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
9032 # my $plot_polygon_ft_hpf30_background_threshold_mask_channel_3_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_original_background_removed_thresholded_vi_mask_channel_3_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_3}->{(%{$vi_map{$vi}->{ft_hpf30_original_thresholded_index_mask_background_channel_3}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9035 #if ($vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_3}) {
9036 # my $fourier_transform_hpf40_original_background_removed_thresholded_vi_mask_channel_3_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $threshold_masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_3}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
9038 # my $plot_polygon_ft_hpf40_background_threshold_mask_channel_3_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_original_background_removed_thresholded_vi_mask_channel_3_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_3}->{(%{$vi_map{$vi}->{ft_hpf40_original_thresholded_index_mask_background_channel_3}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9041 # my $masked_return = _perform_image_background_remove_mask($c, $bcs_schema, $denoised_image_id, $index_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{original_index_mask_background}})[0], $user_id, $user_name, $user_role);
9042 # my $masked_image_id = $masked_return->{masked_image_id};
9044 # $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_index_mask_background}->{(%{$vi_map{$vi}->{original_index_mask_background}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9046 # $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_index_mask_background}->{(%{$vi_map{$vi}->{original_index_mask_background}})[0]}->[1], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9048 # $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_index_mask_background}->{(%{$vi_map{$vi}->{original_index_mask_background}})[0]}->[2], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9050 # if ($vi_map{$vi}->{original_index_mask_background}->{(%{$vi_map{$vi}->{original_index_mask_background}})[0]}->[3]) {
9051 # $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{original_index_mask_background}->{(%{$vi_map{$vi}->{original_index_mask_background}})[0]}->[3], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9054 #my $fourier_transform_hpf20_original_vi_mask_channel_1_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_1}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
9056 #my $plot_polygon_ft_hpf20_vi_return_channel_1 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_original_vi_mask_channel_1_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_1}->{(%{$vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_1}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9058 #my $fourier_transform_hpf30_original_vi_mask_channel_1_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_1}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
9060 #my $plot_polygon_ft_hpf30_vi_return_channel_1 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_original_vi_mask_channel_1_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_1}->{(%{$vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_1}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9062 #my $fourier_transform_hpf40_original_vi_mask_channel_1_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_1}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
9064 #my $plot_polygon_ft_hpf40_vi_return_channel_1 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_original_vi_mask_channel_1_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_1}->{(%{$vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_1}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9066 #my $fourier_transform_hpf20_original_vi_mask_channel_2_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_2}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
9068 #my $plot_polygon_ft_hpf20_vi_return_channel_2 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_original_vi_mask_channel_2_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_2}->{(%{$vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_2}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9070 #my $fourier_transform_hpf30_original_vi_mask_channel_2_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_2}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
9072 #my $plot_polygon_ft_hpf30_vi_return_channel_2 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_original_vi_mask_channel_2_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_2}->{(%{$vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_2}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9074 #my $fourier_transform_hpf40_original_vi_mask_channel_2_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_2}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
9076 #my $plot_polygon_ft_hpf40_vi_return_channel_2 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_original_vi_mask_channel_2_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_2}->{(%{$vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_2}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9078 #if ($vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_3}) {
9079 # my $fourier_transform_hpf20_original_vi_mask_channel_3_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_3}})[0], '20', 'frequency', $user_id, $user_name, $user_role);
9081 # my $plot_polygon_ft_hpf20_vi_return_channel_3 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_original_vi_mask_channel_3_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_3}->{(%{$vi_map{$vi}->{ft_hpf20_original_index_mask_background_channel_3}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9084 #if ($vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_3}) {
9085 # my $fourier_transform_hpf30_original_vi_mask_channel_3_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_3}})[0], '30', 'frequency', $user_id, $user_name, $user_role);
9087 # my $plot_polygon_ft_hpf30_vi_return_channel_3 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_original_vi_mask_channel_3_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_3}->{(%{$vi_map{$vi}->{ft_hpf30_original_index_mask_background_channel_3}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9090 #if ($vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_3}) {
9091 # my $fourier_transform_hpf40_original_vi_mask_channel_3_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $masked_image_id, $merged_drone_run_band_project_id, (%{$vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_3}})[0], '40', 'frequency', $user_id, $user_name, $user_role);
9093 # my $plot_polygon_ft_hpf40_vi_return_channel_3 = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_original_vi_mask_channel_3_return->{ft_image_id}, $merged_drone_run_band_project_id, $plot_polygons_value, $vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_3}->{(%{$vi_map{$vi}->{ft_hpf40_original_index_mask_background_channel_3}})[0]}->[0], $user_id, $user_name, $user_role, 0, 0, 1, 1, 'rectangular_square');
9097 sub _perform_extended_base_standard_process {
9098 my $c = shift;
9099 my $bcs_schema = shift;
9100 my $metadata_schema = shift;
9101 my $denoised_image_id = shift;
9102 my $drone_run_band_project_id = shift;
9103 my $plot_polygons_value = shift;
9104 my $ft_hpf20_imagery_type = shift;
9105 my $ft_hpf20_plot_polygon_type = shift;
9106 my $ft_hpf30_imagery_type = shift;
9107 my $ft_hpf30_plot_polygon_type = shift;
9108 my $ft_hpf40_imagery_type = shift;
9109 my $ft_hpf40_plot_polygon_type = shift;
9110 my $background_removed_threshold_image_id = shift;
9111 my $ft_hpf20_background_threshold_removed_imagery_type = shift;
9112 my $ft_hpf20_background_threshold_removed_plot_polygon_type = shift;
9113 my $ft_hpf30_background_threshold_removed_imagery_type = shift;
9114 my $ft_hpf30_background_threshold_removed_plot_polygon_type = shift;
9115 my $ft_hpf40_background_threshold_removed_imagery_type = shift;
9116 my $ft_hpf40_background_threshold_removed_plot_polygon_type = shift;
9117 my $user_id = shift;
9118 my $user_name = shift;
9119 my $user_role = shift;
9121 #my $fourier_transform_hpf20_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $ft_hpf20_imagery_type, '20', 'frequency', $user_id, $user_name, $user_role);
9123 #my $plot_polygon_ft_hpf20_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_return->{ft_image_id}, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf20_plot_polygon_type, $user_id, $user_name, $user_role, 0, 0, 1, 1);
9125 #my $fourier_transform_hpf30_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $ft_hpf30_imagery_type, '30', 'frequency', $user_id, $user_name, $user_role);
9127 #my $plot_polygon_ft_hpf30_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_return->{ft_image_id}, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf30_plot_polygon_type, $user_id, $user_name, $user_role, 0, 0, 1, 1);
9129 #my $fourier_transform_hpf40_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $denoised_image_id, $drone_run_band_project_id, $ft_hpf40_imagery_type, '40', 'frequency', $user_id, $user_name, $user_role);
9131 #my $plot_polygon_ft_hpf40_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_return->{ft_image_id}, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf40_plot_polygon_type, $user_id, $user_name, $user_role, 0, 0, 1, 1);
9133 #my $fourier_transform_hpf20_background_removed_threshold_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $drone_run_band_project_id, $ft_hpf20_background_threshold_removed_imagery_type, '20', 'frequency', $user_id, $user_name, $user_role);
9135 #my $plot_polygon_ft_hpf20_background_removed_threshold_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf20_background_removed_threshold_return->{ft_image_id}, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf20_background_threshold_removed_plot_polygon_type, $user_id, $user_name, $user_role, 0, 0, 1, 1);
9137 #my $fourier_transform_hpf30_background_removed_threshold_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $drone_run_band_project_id, $ft_hpf30_background_threshold_removed_imagery_type, '30', 'frequency', $user_id, $user_name, $user_role);
9139 #my $plot_polygon_ft_hpf30_background_removed_threshold_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf30_background_removed_threshold_return->{ft_image_id}, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf30_background_threshold_removed_plot_polygon_type, $user_id, $user_name, $user_role, 0, 0, 1, 1);
9141 #my $fourier_transform_hpf40_background_removed_threshold_return = _perform_fourier_transform_calculation($c, $bcs_schema, $metadata_schema, $background_removed_threshold_image_id, $drone_run_band_project_id, $ft_hpf40_background_threshold_removed_imagery_type, '40', 'frequency', $user_id, $user_name, $user_role);
9143 #my $plot_polygon_ft_hpf40_background_removed_threshold_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $fourier_transform_hpf40_background_removed_threshold_return->{ft_image_id}, $drone_run_band_project_id, $plot_polygons_value, $ft_hpf40_background_threshold_removed_plot_polygon_type, $user_id, $user_name, $user_role, 0, 0, 1, 1);
9146 sub _perform_minimal_vi_standard_process {
9147 my $c = shift;
9148 my $bcs_schema = shift;
9149 my $metadata_schema = shift;
9150 my $vegetative_indices = shift;
9151 my $selected_drone_run_band_types = shift;
9152 my $drone_run_band_info = shift;
9153 my $user_id = shift;
9154 my $user_name = shift;
9155 my $user_role = shift;
9156 my $cropping_polygon_type = shift || 'rectangular_square';
9158 if (exists($vegetative_indices->{'TGI'}) || exists($vegetative_indices->{'VARI'})) {
9159 if(exists($selected_drone_run_band_types->{'Blue (450-520nm)'}) && exists($selected_drone_run_band_types->{'Green (515-600nm)'}) && exists($selected_drone_run_band_types->{'Red (600-690nm)'}) ) {
9160 my $merged_return = _perform_image_merge($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{drone_run_project_id}, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{drone_run_project_name}, $selected_drone_run_band_types->{'Blue (450-520nm)'}, $selected_drone_run_band_types->{'Green (515-600nm)'}, $selected_drone_run_band_types->{'Red (600-690nm)'}, 'BGR', $user_id, $user_name, $user_role);
9161 my $merged_image_id = $merged_return->{merged_image_id};
9162 my $merged_drone_run_band_project_id = $merged_return->{merged_drone_run_band_project_id};
9164 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
9165 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
9166 $archive_rotate_temp_image .= '.png';
9168 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $merged_drone_run_band_project_id, $merged_image_id, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{rotate_value}, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image,0,0, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{check_resize}, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{keep_original_size_rotate});
9169 my $rotated_image_id = $rotate_return->{rotated_image_id};
9171 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
9172 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
9173 $archive_temp_image .= '.png';
9175 my $cropping_return = _perform_image_cropping($c, $bcs_schema, $merged_drone_run_band_project_id, $rotated_image_id, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{cropping_value}, $user_id, $user_name, $user_role, $archive_temp_image, 1, 1);
9176 my $cropped_image_id = $cropping_return->{cropped_image_id};
9178 $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
9179 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
9180 $archive_denoise_temp_image .= '.png';
9182 my $denoise_return = _perform_image_denoise($c, $bcs_schema, $metadata_schema, $cropped_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
9183 my $denoised_image_id = $denoise_return->{denoised_image_id};
9185 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{plot_polygons_value}, 'observation_unit_polygon_rgb_imagery', $user_id, $user_name, $user_role, 0, 0, 1, 1, $cropping_polygon_type);
9187 if (exists($vegetative_indices->{'TGI'})) {
9188 _perform_standard_process_minimal_vi_calc($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{plot_polygons_value}, 'TGI', 'BGR', $cropping_polygon_type);
9190 if (exists($vegetative_indices->{'VARI'})) {
9191 _perform_standard_process_minimal_vi_calc($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{$selected_drone_run_band_types->{'Blue (450-520nm)'}}->{plot_polygons_value}, 'VARI', 'BGR', $cropping_polygon_type);
9194 if (exists($selected_drone_run_band_types->{'RGB Color Image'})) {
9195 if (exists($vegetative_indices->{'TGI'})) {
9196 _perform_standard_process_minimal_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{$selected_drone_run_band_types->{'RGB Color Image'}}->{denoised_image_id}, $selected_drone_run_band_types->{'RGB Color Image'}, $user_id, $user_name, $user_role, $drone_run_band_info->{$selected_drone_run_band_types->{'RGB Color Image'}}->{plot_polygons_value}, 'TGI', 'BGR', $cropping_polygon_type);
9198 if (exists($vegetative_indices->{'VARI'})) {
9199 _perform_standard_process_minimal_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{$selected_drone_run_band_types->{'RGB Color Image'}}->{denoised_image_id}, $selected_drone_run_band_types->{'RGB Color Image'}, $user_id, $user_name, $user_role, $drone_run_band_info->{$selected_drone_run_band_types->{'RGB Color Image'}}->{plot_polygons_value}, 'VARI', 'BGR', $cropping_polygon_type);
9203 if (exists($vegetative_indices->{'NDVI'})) {
9204 if(exists($selected_drone_run_band_types->{'NIR (780-3000nm)'}) && exists($selected_drone_run_band_types->{'Red (600-690nm)'}) ) {
9205 my $merged_return = _perform_image_merge($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{drone_run_project_id}, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{drone_run_project_name}, $selected_drone_run_band_types->{'NIR (780-3000nm)'}, $selected_drone_run_band_types->{'Red (600-690nm)'}, $selected_drone_run_band_types->{'NIR (780-3000nm)'}, 'NRN', $user_id, $user_name, $user_role);
9206 my $merged_image_id = $merged_return->{merged_image_id};
9207 my $merged_drone_run_band_project_id = $merged_return->{merged_drone_run_band_project_id};
9209 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
9210 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
9211 $archive_rotate_temp_image .= '.png';
9213 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $merged_drone_run_band_project_id, $merged_image_id, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{rotate_value}, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{check_resize}, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{keep_original_size_rotate});
9214 my $rotated_image_id = $rotate_return->{rotated_image_id};
9216 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
9217 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
9218 $archive_temp_image .= '.png';
9220 my $cropping_return = _perform_image_cropping($c, $bcs_schema, $merged_drone_run_band_project_id, $rotated_image_id, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{cropping_value}, $user_id, $user_name, $user_role, $archive_temp_image, 1, 1);
9221 my $cropped_image_id = $cropping_return->{cropped_image_id};
9223 $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
9224 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
9225 $archive_denoise_temp_image .= '.png';
9227 my $denoise_return = _perform_image_denoise($c, $bcs_schema, $metadata_schema, $cropped_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
9228 my $denoised_image_id = $denoise_return->{denoised_image_id};
9230 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{plot_polygons_value}, 'observation_unit_polygon_nrn_imagery', $user_id, $user_name, $user_role, 0, 0, 1, 1, $cropping_polygon_type);
9232 _perform_standard_process_minimal_vi_calc($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{plot_polygons_value}, 'NDVI', 'NRN', $cropping_polygon_type);
9235 if (exists($vegetative_indices->{'NDRE'})) {
9236 if(exists($selected_drone_run_band_types->{'NIR (780-3000nm)'}) && exists($selected_drone_run_band_types->{'Red Edge (690-750nm)'}) ) {
9237 my $merged_return = _perform_image_merge($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{drone_run_project_id}, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{drone_run_project_name}, $selected_drone_run_band_types->{'NIR (780-3000nm)'}, $selected_drone_run_band_types->{'Red Edge (690-750nm)'}, $selected_drone_run_band_types->{'NIR (780-3000nm)'}, 'NReN', $user_id, $user_name, $user_role);
9238 my $merged_image_id = $merged_return->{merged_image_id};
9239 my $merged_drone_run_band_project_id = $merged_return->{merged_drone_run_band_project_id};
9241 my $dir = $c->tempfiles_subdir('/drone_imagery_rotate');
9242 my $archive_rotate_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_rotate/imageXXXX');
9243 $archive_rotate_temp_image .= '.png';
9245 my $rotate_return = _perform_image_rotate($c, $bcs_schema, $metadata_schema, $merged_drone_run_band_project_id, $merged_image_id, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{rotate_value}, 0, $user_id, $user_name, $user_role, $archive_rotate_temp_image, 0, 0, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{check_resize}, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{keep_original_size_rotate});
9246 my $rotated_image_id = $rotate_return->{rotated_image_id};
9248 $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
9249 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
9250 $archive_temp_image .= '.png';
9252 my $cropping_return = _perform_image_cropping($c, $bcs_schema, $merged_drone_run_band_project_id, $rotated_image_id, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{cropping_value}, $user_id, $user_name, $user_role, $archive_temp_image, 1, 1);
9253 my $cropped_image_id = $cropping_return->{cropped_image_id};
9255 $dir = $c->tempfiles_subdir('/drone_imagery_denoise');
9256 my $archive_denoise_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_denoise/imageXXXX');
9257 $archive_denoise_temp_image .= '.png';
9259 my $denoise_return = _perform_image_denoise($c, $bcs_schema, $metadata_schema, $cropped_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $archive_denoise_temp_image);
9260 my $denoised_image_id = $denoise_return->{denoised_image_id};
9262 my $plot_polygon_return = _perform_plot_polygon_assign($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{plot_polygons_value}, 'observation_unit_polygon_nren_imagery', $user_id, $user_name, $user_role, 0, 0, 1, 1, $cropping_polygon_type);
9264 _perform_standard_process_minimal_vi_calc($c, $bcs_schema, $metadata_schema, $denoised_image_id, $merged_drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{$selected_drone_run_band_types->{'NIR (780-3000nm)'}}->{plot_polygons_value}, 'NDRE', 'NReN', $cropping_polygon_type);
9269 sub _perform_extended_vi_standard_process {
9270 my $c = shift;
9271 my $bcs_schema = shift;
9272 my $metadata_schema = shift;
9273 my $vegetative_indices = shift;
9274 my %vegetative_indices_hash = %$vegetative_indices;
9275 my $selected_drone_run_band_types_input = shift;
9276 my %selected_drone_run_band_types = %$selected_drone_run_band_types_input;
9277 my $drone_run_band_info = shift;
9278 my $user_id = shift;
9279 my $user_name = shift;
9280 my $user_role = shift;
9282 if (exists($vegetative_indices_hash{'TGI'}) || exists($vegetative_indices_hash{'VARI'})) {
9283 if(exists($selected_drone_run_band_types{'Merged 3 Bands BGR'}) ) {
9284 my $drone_run_band_project_id = $selected_drone_run_band_types{'Merged 3 Bands BGR'};
9285 my $drone_run_band_info = $drone_run_band_info->{$drone_run_band_project_id};
9286 if (exists($vegetative_indices_hash{'TGI'})) {
9287 _perform_standard_process_extended_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{denoised_image_id}, $drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{plot_polygons_value}, 'TGI', 'BGR');
9289 if (exists($vegetative_indices_hash{'VARI'})) {
9290 _perform_standard_process_extended_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{denoised_image_id}, $selected_drone_run_band_types{'Merged 3 Bands BGR'}, $user_id, $user_name, $user_role, $drone_run_band_info->{plot_polygons_value}, 'VARI', 'BGR');
9293 if (exists($selected_drone_run_band_types{'RGB Color Image'})) {
9294 my $drone_run_band_project_id = $selected_drone_run_band_types{'RGB Color Image'};
9295 my $drone_run_band_info = $drone_run_band_info->{$drone_run_band_project_id};
9296 if (exists($vegetative_indices_hash{'TGI'})) {
9297 _perform_standard_process_extended_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{denoised_image_id}, $drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{plot_polygons_value}, 'TGI', 'BGR');
9299 if (exists($vegetative_indices_hash{'VARI'})) {
9300 _perform_standard_process_extended_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{denoised_image_id}, $drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{plot_polygons_value}, 'VARI', 'BGR');
9304 if (exists($vegetative_indices_hash{'NDVI'})) {
9305 if(exists($selected_drone_run_band_types{'Merged 3 Bands NRN'}) ) {
9306 my $drone_run_band_project_id = $selected_drone_run_band_types{'Merged 3 Bands NRN'};
9307 my $drone_run_band_info = $drone_run_band_info->{$drone_run_band_project_id};
9308 _perform_standard_process_extended_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{denoised_image_id}, $drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{plot_polygons_value}, 'NDVI', 'NRN');
9311 if (exists($vegetative_indices_hash{'NDRE'})) {
9312 if(exists($selected_drone_run_band_types{'Merged 3 Bands NReN'}) ) {
9313 my $drone_run_band_project_id = $selected_drone_run_band_types{'Merged 3 Bands NReN'};
9314 my $drone_run_band_info = $drone_run_band_info->{$drone_run_band_project_id};
9315 _perform_standard_process_extended_vi_calc($c, $bcs_schema, $metadata_schema, $drone_run_band_info->{denoised_image_id}, $drone_run_band_project_id, $user_id, $user_name, $user_role, $drone_run_band_info->{plot_polygons_value}, 'NDRE', 'NReN');
9320 sub get_project_md_image : Path('/api/drone_imagery/get_project_md_image') : ActionClass('REST') { }
9321 sub get_project_md_image_GET : Args(0) {
9322 my $self = shift;
9323 my $c = shift;
9324 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9325 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
9326 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
9327 my $project_image_type_name = $c->req->param('project_image_type_name');
9329 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($bcs_schema, $project_image_type_name, 'project_md_image')->cvterm_id();
9331 my $q = "SELECT project_md_image.image_id
9332 FROM project AS drone_run_band
9333 JOIN phenome.project_md_image AS project_md_image USING(project_id)
9334 WHERE project_md_image.type_id = $project_image_type_id AND project_id = $drone_run_band_project_id
9335 ORDER BY project_id;";
9337 my $h = $bcs_schema->storage->dbh()->prepare($q);
9338 $h->execute();
9339 my @result;
9340 while (my ($image_id) = $h->fetchrow_array()) {
9341 push @result, {
9342 image_id => $image_id
9346 $c->stash->{rest} = { data => \@result };
9349 sub drone_imagery_get_image : Path('/api/drone_imagery/get_image') : ActionClass('REST') { }
9350 sub drone_imagery_get_image_GET : Args(0) {
9351 my $self = shift;
9352 my $c = shift;
9353 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9354 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9355 my $image_id = $c->req->param('image_id');
9356 my $size = $c->req->param('size') || 'original_converted';
9357 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9359 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9360 my $image_url = $image->get_image_url($size);
9361 my $image_fullpath = $image->get_filename('original_converted', 'full');
9362 my @size = imgsize($image_fullpath);
9364 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
9365 bcs_schema=>$schema,
9366 image_id_list=>[$image_id],
9368 my ($result, $total_count) = $images_search->search();
9369 my $drone_run_band_project_id = $result->[0]->{drone_run_band_project_id};
9371 $c->stash->{rest} = { image_url => $image_url, image_fullpath => $image_fullpath, image_width => $size[0], image_height => $size[1], drone_run_band_project_id => $drone_run_band_project_id };
9374 sub drone_imagery_remove_image : Path('/api/drone_imagery/remove_image') : ActionClass('REST') { }
9375 sub drone_imagery_remove_image_GET : Args(0) {
9376 my $self = shift;
9377 my $c = shift;
9378 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9379 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9380 my $image_id = $c->req->param('image_id');
9381 my ($user_id, $user_name, $user_role) = _check_user_login($c, 'curator');
9383 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9384 my $resp = $image->delete(); #Sets to obsolete
9386 $c->stash->{rest} = { status => $resp };
9389 sub drone_imagery_crop_image : Path('/api/drone_imagery/crop_image') : ActionClass('REST') { }
9390 sub drone_imagery_crop_image_GET : Args(0) {
9391 my $self = shift;
9392 my $c = shift;
9393 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9394 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9395 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
9396 my $image_id = $c->req->param('image_id');
9397 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
9398 my $polygon = $c->req->param('polygon');
9399 my $polygon_obj = decode_json $polygon;
9400 if (scalar(@$polygon_obj) != 4){
9401 $c->stash->{rest} = {error=>'Polygon should be 4 long!'};
9402 $c->detach();
9404 my $polygons = encode_json [$polygon_obj];
9405 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9407 my $dir = $c->tempfiles_subdir('/drone_imagery_cropped_image');
9408 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_cropped_image/imageXXXX');
9409 $archive_temp_image .= '.png';
9411 my $return = _perform_image_cropping($c, $schema, $drone_run_band_project_id, $image_id, $polygons, $user_id, $user_name, $user_role, $archive_temp_image, 1, 1);
9413 $c->stash->{rest} = $return;
9416 sub _perform_image_cropping {
9417 my $c = shift;
9418 my $schema = shift;
9419 my $drone_run_band_project_id = shift;
9420 my $image_id = shift;
9421 my $polygons = shift;
9422 my $user_id = shift;
9423 my $user_name = shift;
9424 my $user_role = shift;
9425 my $archive_temp_image = shift;
9426 my $apply_image_width_ratio = shift;
9427 my $apply_image_height_ratio = shift;
9429 my $polygons_array = decode_json $polygons;
9430 my @polygons_rescaled = ();
9431 foreach my $p (@$polygons_array) {
9432 my @p_rescaled;
9433 foreach my $point (@$p) {
9434 my $x = $point->{x};
9435 my $y = $point->{y};
9436 push @p_rescaled, {x=>round($x/$apply_image_width_ratio), y=>round($y/$apply_image_height_ratio)};
9438 push @polygons_rescaled, \@p_rescaled;
9440 $polygons = encode_json \@polygons_rescaled;
9442 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9443 my $image_url = $image->get_image_url("original");
9444 my $image_fullpath = $image->get_filename('original_converted', 'full');
9446 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/ImageCropping/CropToPolygon.py --inputfile_path '$image_fullpath' --outputfile_path '$archive_temp_image' --polygon_json '$polygons' --polygon_type rectangular_square";
9447 print STDERR Dumper $cmd;
9448 my $status = system("$cmd > /dev/null");
9450 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
9451 $image->set_sp_person_id($user_id);
9452 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'cropped_stitched_drone_imagery', 'project_md_image')->cvterm_id();
9454 my $previous_cropped_images_search = CXGN::DroneImagery::ImagesSearch->new({
9455 bcs_schema=>$schema,
9456 project_image_type_id=>$linking_table_type_id,
9457 drone_run_band_project_id_list=>[$drone_run_band_project_id]
9459 my ($previous_result, $previous_total_count) = $previous_cropped_images_search->search();
9460 foreach (@$previous_result) {
9461 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
9462 $previous_image->delete(); #Sets to obsolete
9465 my $ret = $image->process_image($archive_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
9466 my $cropped_image_fullpath = $image->get_filename('original_converted', 'full');
9467 my $cropped_image_url = $image->get_image_url('original');
9468 my $cropped_image_id = $image->get_image_id();
9470 my $drone_run_band_cropped_polygon_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_cropped_polygon', 'project_property')->cvterm_id();
9471 my $drone_run_band_cropped_polygon = $schema->resultset('Project::Projectprop')->update_or_create({
9472 type_id=>$drone_run_band_cropped_polygon_type_id,
9473 project_id=>$drone_run_band_project_id,
9474 rank=>0,
9475 value=>$polygons
9478 key=>'projectprop_c1'
9481 unlink($archive_temp_image);
9482 return {
9483 cropped_image_id => $cropped_image_id, image_url => $image_url, image_fullpath => $image_fullpath, cropped_image_url => $cropped_image_url, cropped_image_fullpath => $cropped_image_fullpath
9487 sub drone_imagery_calculate_fourier_transform : Path('/api/drone_imagery/calculate_fourier_transform') : ActionClass('REST') { }
9488 sub drone_imagery_calculate_fourier_transform_POST : Args(0) {
9489 my $self = shift;
9490 my $c = shift;
9491 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9492 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9493 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
9494 my $image_id = $c->req->param('image_id');
9495 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
9496 my $drone_run_band_project_type = $c->req->param('drone_run_band_project_type');
9497 my $image_type = $c->req->param('image_type');
9498 my $high_pass_filter = $c->req->param('high_pass_filter');
9499 my $high_pass_filter_type = $c->req->param('high_pass_filter_type') || 'frequency';
9501 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9503 my $return = _perform_fourier_transform_calculation($c, $schema, $metadata_schema, $image_id, $drone_run_band_project_id, $image_type, $high_pass_filter, $high_pass_filter_type, $user_id, $user_name, $user_role);
9505 $c->stash->{rest} = $return;
9508 sub _perform_fourier_transform_calculation {
9509 my $c = shift;
9510 my $schema = shift;
9511 my $metadata_schema = shift;
9512 my $image_id = shift;
9513 my $drone_run_band_project_id = shift;
9514 my $drone_run_band_project_type;
9515 my $image_type = shift;
9516 my $high_pass_filter = shift;
9517 my $high_pass_filter_type = shift;
9518 my $user_id = shift;
9519 my $user_name = shift;
9520 my $user_role = shift;
9521 print STDERR "FT Linking Table Type: $image_type\n";
9522 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $image_type, 'project_md_image')->cvterm_id();
9523 my $image_channel_lookup = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_types_whole_images($schema)->{$linking_table_type_id}->{corresponding_channel};
9525 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9526 my $image_url = $image->get_image_url("original");
9527 my $image_fullpath = $image->get_filename('original_converted', 'full');
9529 my $dir = $c->tempfiles_subdir('/drone_imagery_fourier_transform_hpf_image');
9530 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_fourier_transform_hpf_image/imageXXXX');
9531 $archive_temp_image .= '.png';
9533 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/ImageProcess/FourierTransform.py --image_path '$image_fullpath' --outfile_path '$archive_temp_image' --image_band_index ".$image_channel_lookup." --frequency_threshold $high_pass_filter --frequency_threshold_method $high_pass_filter_type";
9534 print STDERR Dumper $cmd;
9535 my $status = system("$cmd > /dev/null");
9537 my $ft_image_fullpath;
9538 my $ft_image_url;
9539 my $ft_image_id;
9540 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
9541 my $md5checksum = $image->calculate_md5sum($archive_temp_image);
9542 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
9543 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
9544 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
9545 my $h = $schema->storage->dbh->prepare($q);
9546 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id);
9547 my ($saved_image_id) = $h->fetchrow_array();
9549 if ($saved_image_id) {
9550 print STDERR Dumper "Image $archive_temp_image has already been added to the database and will not be added again.";
9551 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
9552 $ft_image_fullpath = $image->get_filename('original_converted', 'full');
9553 $ft_image_url = $image->get_image_url('original');
9554 $ft_image_id = $image->get_image_id();
9555 } else {
9556 my $previous_index_images_search = CXGN::DroneImagery::ImagesSearch->new({
9557 bcs_schema=>$schema,
9558 project_image_type_id=>$linking_table_type_id,
9559 drone_run_band_project_id_list=>[$drone_run_band_project_id]
9561 my ($previous_result, $previous_total_count) = $previous_index_images_search->search();
9562 foreach (@$previous_result){
9563 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
9564 $previous_image->delete(); #Sets to obsolete
9567 $image->set_sp_person_id($user_id);
9568 my $ret = $image->process_image($archive_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
9569 $ft_image_fullpath = $image->get_filename('original_converted', 'full');
9570 $ft_image_url = $image->get_image_url('original');
9571 $ft_image_id = $image->get_image_id();
9574 unlink($archive_temp_image);
9575 return {
9576 image_url => $image_url, image_fullpath => $image_fullpath, ft_image_id => $ft_image_id, ft_image_url => $ft_image_url, ft_image_fullpath => $ft_image_fullpath
9580 sub drone_imagery_calculate_vegetative_index : Path('/api/drone_imagery/calculate_vegetative_index') : ActionClass('REST') { }
9581 sub drone_imagery_calculate_vegetative_index_POST : Args(0) {
9582 my $self = shift;
9583 my $c = shift;
9584 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9585 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9586 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
9587 my $image_id = $c->req->param('image_id');
9588 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
9589 my $vegetative_index = $c->req->param('vegetative_index');
9590 my $image_type = $c->req->param('image_type');
9591 my $view_only = $c->req->param('view_only');
9593 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9595 my $return = _perform_vegetative_index_calculation($c, $schema, $metadata_schema, $image_id, $drone_run_band_project_id, $vegetative_index, $view_only, $image_type, $user_id, $user_name, $user_role);
9597 $c->stash->{rest} = $return;
9600 sub _perform_vegetative_index_calculation {
9601 my $c = shift;
9602 my $schema = shift;
9603 my $metadata_schema = shift;
9604 my $image_id = shift;
9605 my $drone_run_band_project_id = shift;
9606 my $vegetative_index = shift;
9607 my $view_only = shift;
9608 my $image_type = shift;
9609 my $user_id = shift;
9610 my $user_name = shift;
9611 my $user_role = shift;
9613 my $index_script = '';
9614 my $linking_table_type_id;
9615 if ($image_type eq 'BGR') {
9616 if ($vegetative_index eq 'TGI') {
9617 $index_script = 'TGI';
9618 if ($view_only == 1){
9619 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_tgi_temporary_drone_imagery', 'project_md_image')->cvterm_id();
9620 } else {
9621 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_tgi_drone_imagery', 'project_md_image')->cvterm_id();
9624 if ($vegetative_index eq 'VARI') {
9625 $index_script = 'VARI';
9626 if ($view_only == 1){
9627 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_vari_temporary_drone_imagery', 'project_md_image')->cvterm_id();
9628 } else {
9629 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_vari_drone_imagery', 'project_md_image')->cvterm_id();
9633 elsif ($image_type eq 'NRN') {
9634 if ($vegetative_index eq 'NDVI') {
9635 $index_script = 'NDVI';
9636 if ($view_only == 1){
9637 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_ndvi_temporary_drone_imagery', 'project_md_image')->cvterm_id();
9638 } else {
9639 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_ndvi_drone_imagery', 'project_md_image')->cvterm_id();
9643 elsif ($image_type eq 'NReN') {
9644 if ($vegetative_index eq 'NDRE') {
9645 $index_script = 'NDRE';
9646 if ($view_only == 1){
9647 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_ndre_temporary_drone_imagery', 'project_md_image')->cvterm_id();
9648 } else {
9649 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_ndre_drone_imagery', 'project_md_image')->cvterm_id();
9653 if (!$linking_table_type_id) {
9654 die "Could not get vegetative index image type id\n";
9657 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9658 my $image_url = $image->get_image_url("original");
9659 my $image_fullpath = $image->get_filename('original_converted', 'full');
9661 my $dir = $c->tempfiles_subdir('/drone_imagery_vegetative_index_image');
9662 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_vegetative_index_image/imageXXXX');
9663 $archive_temp_image .= '.png';
9665 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/VegetativeIndex/$index_script.py --image_path '$image_fullpath' --outfile_path '$archive_temp_image'";
9666 print STDERR Dumper $cmd;
9667 my $status = system("$cmd > /dev/null");
9669 my $index_image_fullpath;
9670 my $index_image_url;
9671 my $index_image_id;
9672 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
9673 my $md5checksum = $image->calculate_md5sum($archive_temp_image);
9674 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
9675 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
9676 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
9677 my $h = $schema->storage->dbh->prepare($q);
9678 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id);
9679 my ($saved_image_id) = $h->fetchrow_array();
9681 if ($view_only == 1 && $saved_image_id) {
9682 print STDERR Dumper "Image $archive_temp_image has already been added to the database and will not be added again.";
9683 $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
9684 $index_image_fullpath = $image->get_filename('original_converted', 'full');
9685 $index_image_url = $image->get_image_url('original');
9686 $index_image_id = $image->get_image_id();
9687 } else {
9688 my $previous_index_images_search = CXGN::DroneImagery::ImagesSearch->new({
9689 bcs_schema=>$schema,
9690 project_image_type_id=>$linking_table_type_id,
9691 drone_run_band_project_id_list=>[$drone_run_band_project_id]
9693 my ($previous_result, $previous_total_count) = $previous_index_images_search->search();
9694 foreach (@$previous_result){
9695 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
9696 $previous_image->delete(); #Sets to obsolete
9698 $image->set_sp_person_id($user_id);
9699 my $ret = $image->process_image($archive_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
9700 $index_image_fullpath = $image->get_filename('original_converted', 'full');
9701 $index_image_url = $image->get_image_url('original');
9702 $index_image_id = $image->get_image_id();
9705 unlink($archive_temp_image);
9706 return {
9707 image_url => $image_url, image_fullpath => $image_fullpath, index_image_id => $index_image_id, index_image_url => $index_image_url, index_image_fullpath => $index_image_fullpath
9711 sub drone_imagery_mask_remove_background : Path('/api/drone_imagery/mask_remove_background') : ActionClass('REST') { }
9712 sub drone_imagery_mask_remove_background_POST : Args(0) {
9713 my $self = shift;
9714 my $c = shift;
9715 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9716 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9717 my $image_id = $c->req->param('image_id');
9718 my $mask_image_id = $c->req->param('mask_image_id');
9719 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
9720 my $mask_type = $c->req->param('mask_type');
9722 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9724 my $return = _perform_image_background_remove_mask($c, $schema, $image_id, $mask_image_id, $drone_run_band_project_id, $mask_type, $user_id, $user_name, $user_role);
9726 $c->stash->{rest} = $return;
9729 sub _perform_image_background_remove_mask {
9730 my $c = shift;
9731 my $schema = shift;
9732 my $image_id = shift;
9733 my $mask_image_id = shift;
9734 my $drone_run_band_project_id = shift;
9735 my $mask_type = shift;
9736 my $user_id = shift;
9737 my $user_name = shift;
9738 my $user_role = shift;
9740 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9741 my $image_url = $image->get_image_url("original");
9742 my $image_fullpath = $image->get_filename('original_converted', 'full');
9744 my $mask_image = SGN::Image->new( $schema->storage->dbh, $mask_image_id, $c );
9745 my $mask_image_url = $mask_image->get_image_url("original");
9746 my $mask_image_fullpath = $mask_image->get_filename('original_converted', 'full');
9748 my $dir = $c->tempfiles_subdir('/drone_imagery_mask_remove_background');
9749 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_mask_remove_background/imageXXXX');
9750 $archive_temp_image .= '.png';
9752 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/ImageProcess/MaskRemoveBackground.py --image_path '$image_fullpath' --mask_image_path '$mask_image_fullpath' --outfile_path '$archive_temp_image'";
9753 print STDERR Dumper $cmd;
9754 my $status = system("$cmd > /dev/null");
9756 $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
9757 $image->set_sp_person_id($user_id);
9759 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, $mask_type, 'project_md_image')->cvterm_id();;
9761 my $previous_images_search = CXGN::DroneImagery::ImagesSearch->new({
9762 bcs_schema=>$schema,
9763 project_image_type_id=>$linking_table_type_id,
9764 drone_run_band_project_id_list=>[$drone_run_band_project_id]
9766 my ($previous_result, $previous_total_count) = $previous_images_search->search();
9767 foreach (@$previous_result){
9768 my $previous_image = SGN::Image->new( $schema->storage->dbh, $_->{image_id}, $c );
9769 $previous_image->delete(); #Sets to obsolete
9772 my $ret = $image->process_image($archive_temp_image, 'project', $drone_run_band_project_id, $linking_table_type_id);
9773 my $masked_image_fullpath = $image->get_filename('original_converted', 'full');
9774 my $masked_image_url = $image->get_image_url('original');
9775 my $masked_image_id = $image->get_image_id();
9777 unlink($archive_temp_image);
9778 return {
9779 image_url => $image_url, image_fullpath => $image_fullpath, masked_image_id => $masked_image_id, masked_image_url => $masked_image_url, masked_image_fullpath => $masked_image_fullpath
9783 sub drone_imagery_get_plot_polygon_images : Path('/api/drone_imagery/get_plot_polygon_images') : ActionClass('REST') { }
9784 sub drone_imagery_get_plot_polygon_images_GET : Args(0) {
9785 my $self = shift;
9786 my $c = shift;
9787 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9788 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9789 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
9790 my $plot_polygons_type = $c->req->param('plot_polygons_type');
9791 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9793 my $plot_polygons_images_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, $plot_polygons_type, 'project_md_image')->cvterm_id();
9794 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
9795 bcs_schema=>$schema,
9796 drone_run_band_project_id_list=>[$drone_run_band_project_id],
9797 project_image_type_id=>$plot_polygons_images_cvterm_id
9799 my ($result, $total_count) = $images_search->search();
9800 #print STDERR Dumper $result;
9802 my @image_paths;
9803 my @image_urls;
9804 foreach (@$result) {
9805 my $image_id = $_->{image_id};
9806 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
9807 my $image_url = $image->get_image_url("original");
9808 my $image_fullpath = $image->get_filename('original_converted', 'full');
9809 push @image_urls, $image_url;
9810 push @image_paths, $image_fullpath;
9813 $c->stash->{rest} = { image_urls => \@image_urls };
9816 sub drone_imagery_merge_bands : Path('/api/drone_imagery/merge_bands') : ActionClass('REST') { }
9817 sub drone_imagery_merge_bands_POST : Args(0) {
9818 my $self = shift;
9819 my $c = shift;
9820 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
9821 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
9822 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
9823 my ($user_id, $user_name, $user_role) = _check_user_login($c);
9825 my $drone_run_project_id = $c->req->param('drone_run_project_id');
9826 my $drone_run_project_name = $c->req->param('drone_run_project_name');
9827 my $band_1_drone_run_band_project_id = $c->req->param('band_1_drone_run_band_project_id');
9828 my $band_2_drone_run_band_project_id = $c->req->param('band_2_drone_run_band_project_id');
9829 my $band_3_drone_run_band_project_id = $c->req->param('band_3_drone_run_band_project_id');
9830 my $merged_image_type = $c->req->param('merged_image_type');
9832 my $return = _perform_image_merge($c, $schema, $metadata_schema, $drone_run_project_id, $drone_run_project_name, $band_1_drone_run_band_project_id, $band_2_drone_run_band_project_id, $band_3_drone_run_band_project_id, $merged_image_type, $user_id, $user_name, $user_role);
9834 $c->stash->{rest} = $return;
9837 sub _perform_image_merge {
9838 my $c = shift;
9839 my $schema = shift;
9840 my $metadata_schema = shift;
9841 my $drone_run_project_id = shift;
9842 my $drone_run_project_name = shift;
9843 my $band_1_drone_run_band_project_id = shift;
9844 my $band_2_drone_run_band_project_id = shift;
9845 my $band_3_drone_run_band_project_id = shift;
9846 my $merged_image_type = shift;
9847 my $user_id = shift;
9848 my $user_name = shift;
9849 my $user_role = shift;
9851 if (!$band_1_drone_run_band_project_id || !$band_2_drone_run_band_project_id || !$band_3_drone_run_band_project_id) {
9852 $c->stash->{rest} = { error => 'Please select 3 drone run bands' };
9853 $c->detach();
9855 my @drone_run_bands = ($band_1_drone_run_band_project_id, $band_2_drone_run_band_project_id, $band_3_drone_run_band_project_id);
9857 my $project_image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'stitched_drone_imagery', 'project_md_image')->cvterm_id();
9858 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
9859 bcs_schema=>$schema,
9860 project_image_type_id=>$project_image_type_id,
9861 drone_run_band_project_id_list=>\@drone_run_bands,
9863 my ($result, $total_count) = $images_search->search();
9864 #print STDERR Dumper $result;
9866 my %drone_run_bands_images;
9867 foreach (@$result) {
9868 $drone_run_bands_images{$_->{drone_run_band_project_id}} = $_->{image_id};
9870 #print STDERR Dumper \%drone_run_bands_images;
9872 my @image_filesnames;
9873 foreach (@drone_run_bands) {
9874 my $image = SGN::Image->new( $schema->storage->dbh, $drone_run_bands_images{$_}, $c );
9875 my $image_url = $image->get_image_url("original");
9876 my $image_fullpath = $image->get_filename('original_converted', 'full');
9877 push @image_filesnames, $image_fullpath;
9880 my $dir = $c->tempfiles_subdir('/drone_imagery_merge_bands');
9881 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_merge_bands/imageXXXX');
9882 $archive_temp_image .= '.png';
9884 my $cmd = $c->config->{python_executable}." ".$c->config->{rootpath}."/DroneImageScripts/ImageProcess/MergeChannels.py --image_path_band_1 '".$image_filesnames[0]."' --image_path_band_2 '".$image_filesnames[1]."' --image_path_band_3 '".$image_filesnames[2]."' --outfile_path '$archive_temp_image'";
9885 print STDERR Dumper $cmd;
9886 my $status = system("$cmd > /dev/null");
9888 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
9889 $image->set_sp_person_id($user_id);
9891 my $drone_run_band_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
9892 my $design_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'design', 'project_property')->cvterm_id();
9893 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
9895 my $band_1_drone_run_band_project_type = $schema->resultset("Project::Projectprop")->search({project_id => $band_1_drone_run_band_project_id, type_id => $drone_run_band_type_cvterm_id})->first->value;
9896 my $band_2_drone_run_band_project_type = $schema->resultset("Project::Projectprop")->search({project_id => $band_2_drone_run_band_project_id, type_id => $drone_run_band_type_cvterm_id})->first->value;
9897 my $band_3_drone_run_band_project_type = $schema->resultset("Project::Projectprop")->search({project_id => $band_3_drone_run_band_project_id, type_id => $drone_run_band_type_cvterm_id})->first->value;
9899 my $merged_drone_run_band_id;
9900 my $project_rs_check = $schema->resultset("Project::Project")->find({
9901 name => "$drone_run_project_name Merged:$band_1_drone_run_band_project_type (project_id:$band_1_drone_run_band_project_id),$band_2_drone_run_band_project_type (project_id:$band_2_drone_run_band_project_id),$band_3_drone_run_band_project_type (project_id:$band_3_drone_run_band_project_id)"
9903 if ($project_rs_check) {
9904 $merged_drone_run_band_id = $project_rs_check->project_id;
9905 } else {
9906 my $project_rs = $schema->resultset("Project::Project")->create({
9907 name => "$drone_run_project_name Merged:$band_1_drone_run_band_project_type (project_id:$band_1_drone_run_band_project_id),$band_2_drone_run_band_project_type (project_id:$band_2_drone_run_band_project_id),$band_3_drone_run_band_project_type (project_id:$band_3_drone_run_band_project_id)",
9908 description => "Merged $band_1_drone_run_band_project_type (project_id:$band_1_drone_run_band_project_id),$band_2_drone_run_band_project_type (project_id:$band_2_drone_run_band_project_id),$band_3_drone_run_band_project_type (project_id:$band_3_drone_run_band_project_id)",
9909 projectprops => [{type_id => $drone_run_band_type_cvterm_id, value => 'Merged 3 Bands '.$merged_image_type}, {type_id => $design_cvterm_id, value => 'drone_run_band'}],
9910 project_relationship_subject_projects => [{type_id => $project_relationship_type_id, object_project_id => $drone_run_project_id}]
9912 $merged_drone_run_band_id = $project_rs->project_id();
9915 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'stitched_drone_imagery', 'project_md_image')->cvterm_id();
9916 my $ret = $image->process_image($archive_temp_image, 'project', $merged_drone_run_band_id, $linking_table_type_id);
9917 my $merged_image_fullpath = $image->get_filename('original_converted', 'full');
9918 my $merged_image_url = $image->get_image_url('original');
9919 my $merged_image_id = $image->get_image_id();
9921 unlink($archive_temp_image);
9922 return {
9923 merged_drone_run_band_project_id => $merged_drone_run_band_id, merged_image_url => $merged_image_url, merged_image_fullpath => $merged_image_fullpath, merged_image_id => $merged_image_id
9927 sub _perform_phenotype_automated {
9928 my $c = shift;
9929 my $schema = shift;
9930 my $metadata_schema = shift;
9931 my $phenome_schema = shift;
9932 my $drone_run_project_id = shift;
9933 my $time_cvterm_id = shift;
9934 my $phenotype_types = shift;
9935 my $standard_process_type = shift;
9936 my $ignore_new_phenotype_values = shift;
9937 my $overwrite_phenotype_values = shift;
9938 my $user_id = shift;
9939 my $user_name = shift;
9940 my $user_role = shift;
9942 my $number_system_cores = `getconf _NPROCESSORS_ONLN` or die "Could not get number of system cores!\n";
9943 chomp($number_system_cores);
9944 print STDERR "NUMCORES $number_system_cores\n";
9946 my @allowed_composed_cvs = split ',', $c->config->{composable_cvs};
9947 my $composable_cvterm_delimiter = $c->config->{composable_cvterm_delimiter};
9948 my $composable_cvterm_format = $c->config->{composable_cvterm_format};
9950 my $drone_run_phenotype_calc_progress_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_standard_process_phenotype_calculation_in_progress', 'project_property')->cvterm_id();
9951 my $drone_run_phenotype_calc_progress = $schema->resultset('Project::Projectprop')->update_or_create({
9952 type_id=>$drone_run_phenotype_calc_progress_type_id,
9953 project_id=>$drone_run_project_id,
9954 rank=>0,
9955 value=>1
9958 key=>'projectprop_c1'
9961 my $in_progress_indicator = 1;
9962 while ($in_progress_indicator == 1) {
9963 sleep(30);
9964 print STDERR "Waiting for drone standard image process to finish before calculating phenotypes\n";
9965 my $process_indicator_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_standard_process_in_progress', 'project_property')->cvterm_id();
9966 my $drone_run_band_remove_background_threshold_rs = $schema->resultset('Project::Projectprop')->search({
9967 type_id=>$process_indicator_cvterm_id,
9968 project_id=>$drone_run_project_id,
9970 $in_progress_indicator = $drone_run_band_remove_background_threshold_rs->first ? $drone_run_band_remove_background_threshold_rs->first->value() : 0;
9973 my $project_image_type_id_map = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
9974 my %project_observation_unit_plot_polygons_types;
9975 while (my ($k, $v) = each %$project_image_type_id_map) {
9976 foreach my $p (@{$v->{drone_run_project_types}}) {
9977 if (!$p) {
9978 die "No project for ".$v->{name}."\n";
9980 foreach my $t (@{$v->{standard_process}}) {
9981 if (!$t) {
9982 die "No standard process type for ".$v->{name}."\n";
9984 push @{$project_observation_unit_plot_polygons_types{$p}->{$t}}, $v->{name};
9989 my $drone_run_band_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
9990 my $drone_run_band_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
9991 my $q = "SELECT drone_run_band.project_id, drone_run_band.name, drone_run_band_project_type.value
9992 FROM project AS drone_run_band
9993 JOIN projectprop AS drone_run_band_project_type ON (drone_run_band_project_type.project_id=drone_run_band.project_id AND drone_run_band_project_type.type_id=$drone_run_band_type_cvterm_id)
9994 JOIN project_relationship AS drone_run_band_rel ON(drone_run_band.project_id=drone_run_band_rel.subject_project_id AND drone_run_band_rel.type_id=$drone_run_band_relationship_type_id)
9995 JOIN project ON (drone_run_band_rel.object_project_id = project.project_id)
9996 WHERE project.project_id = ?;";
9998 my $h = $schema->storage->dbh()->prepare($q);
9999 $h->execute($drone_run_project_id);
10001 my @result;
10002 while (my ($drone_run_band_project_id, $drone_run_band_name, $drone_run_band_project_type) = $h->fetchrow_array()) {
10003 print STDERR Dumper [$drone_run_band_name, $drone_run_band_project_type];
10004 foreach my $phenotype_method (@$phenotype_types) {
10005 #my $pm = Parallel::ForkManager->new(floor(int($number_system_cores)*0.5));
10006 foreach my $plot_polygon_type (@{$project_observation_unit_plot_polygons_types{$drone_run_band_project_type}->{$standard_process_type}}) {
10007 #my $pid = $pm->start and next;
10008 my $return = _perform_phenotype_calculation($c, $schema, $metadata_schema, $phenome_schema, $drone_run_band_project_id, $drone_run_band_project_type, $phenotype_method, $time_cvterm_id, $plot_polygon_type, $user_id, $user_name, $user_role, \@allowed_composed_cvs, $composable_cvterm_delimiter, $composable_cvterm_format, 1, $ignore_new_phenotype_values, $overwrite_phenotype_values);
10009 if ($return->{error}){
10010 print STDERR Dumper $return->{error};
10012 #$pm->finish();
10014 #$pm->wait_all_children;
10018 my $bs = CXGN::BreederSearch->new( { dbh=>$c->dbc->dbh, dbname=>$c->config->{dbname}, } );
10019 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'fullview', 'nonconcurrent', $c->config->{basepath});
10021 $drone_run_phenotype_calc_progress = $schema->resultset('Project::Projectprop')->update_or_create({
10022 type_id=>$drone_run_phenotype_calc_progress_type_id,
10023 project_id=>$drone_run_project_id,
10024 rank=>0,
10025 value=>0
10028 key=>'projectprop_c1'
10031 return {
10032 success => 1
10036 sub drone_imagery_get_drone_run_image_counts : Path('/api/drone_imagery/get_drone_run_image_counts') : ActionClass('REST') { }
10037 sub drone_imagery_get_drone_run_image_counts_GET : Args(0) {
10038 my $self = shift;
10039 my $c = shift;
10040 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10041 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10042 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10043 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10044 my $drone_run_id = $c->req->param('drone_run_id');
10045 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10047 my $plot_polygon_types = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
10048 my @plot_polygon_minimal_cvterm_ids;
10049 while (my ($plot_polygon_type_cvterm_id, $plot_polygon_type) = each %$plot_polygon_types) {
10050 my $processes = $plot_polygon_type->{standard_process};
10051 foreach (@$processes) {
10052 if ($_ eq 'minimal') {
10053 push @plot_polygon_minimal_cvterm_ids, $plot_polygon_type_cvterm_id;
10058 my $plot_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot number', 'stock_property')->cvterm_id();
10059 my $q = "SELECT value FROM stockprop WHERE stock_id=? and type_id=$plot_number_cvterm_id;";
10060 my $h = $schema->storage->dbh()->prepare($q);
10062 my %plot_image_counts;
10063 my %plot_numbers;
10064 foreach my $plot_polygons_images_cvterm_id (@plot_polygon_minimal_cvterm_ids) {
10065 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
10066 bcs_schema=>$schema,
10067 drone_run_project_id_list=>[$drone_run_id],
10068 project_image_type_id=>$plot_polygons_images_cvterm_id
10070 my ($result, $total_count) = $images_search->search();
10071 foreach (@$result) {
10072 my $plot_id = $_->{stock_id};
10073 my $plot_name = $_->{stock_uniquename};
10074 $plot_image_counts{$plot_name}->{$_->{project_image_type_name}}++;
10075 $h->execute($plot_id);
10076 my ($plot_number) = $h->fetchrow_array();
10077 $plot_numbers{$plot_name} = $plot_number;
10081 my @return;
10082 while (my ($stock_name, $obj) = each %plot_image_counts) {
10083 my $image_counts_string = '';
10084 while (my ($image_type, $count) = each %$obj) {
10085 $image_counts_string .= "$image_type: $count<br/>";
10087 push @return, {plot_name => $stock_name, plot_number => $plot_numbers{$stock_name}, image_counts => $image_counts_string};
10090 $c->stash->{rest} = {data => \@return};
10093 sub drone_imagery_update_details : Path('/api/drone_imagery/update_details') : ActionClass('REST') { }
10094 sub drone_imagery_update_details_POST : Args(0) {
10095 my $self = shift;
10096 my $c = shift;
10097 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10098 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10099 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10100 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10101 my $drone_run_project_id = $c->req->param('drone_run_project_id');
10102 my $drone_run_date = $c->req->param('drone_run_date');
10103 my $description = $c->req->param('description');
10104 my $drone_run_name = $c->req->param('drone_run_name');
10105 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10107 my $trial = CXGN::Trial->new({bcs_schema=>$schema, trial_id=>$drone_run_project_id});
10109 if ($drone_run_date) {
10110 $trial->set_drone_run_date($drone_run_date);
10112 if ($description) {
10113 $trial->set_description($description);
10115 if ($drone_run_name) {
10116 $trial->set_name($drone_run_name);
10119 $c->stash->{rest} = {success => 1};
10122 sub drone_imagery_quality_control_get_images : Path('/api/drone_imagery/quality_control_get_images') : ActionClass('REST') { }
10123 sub drone_imagery_quality_control_get_images_GET : Args(0) {
10124 my $self = shift;
10125 my $c = shift;
10126 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10127 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10128 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10129 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10130 my $drone_run_project_id = $c->req->param('drone_run_project_id');
10132 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
10133 bcs_schema=>$schema,
10134 drone_run_project_id_list=>[$drone_run_project_id]
10136 my ($result, $total_count) = $images_search->search();
10137 # print STDERR Dumper $total_count;
10139 my %stock_images;
10140 foreach (@$result) {
10141 my $image_id = $_->{image_id};
10142 my $stock_id = $_->{stock_id};
10143 my $stock_uniquename = $_->{stock_uniquename};
10145 if ($stock_uniquename) {
10146 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
10147 my $image_url = $image->get_image_url("original");
10148 my $image_fullpath = $image->get_filename('original_converted', 'full');
10149 my $image_source_tag_small = $image->get_img_src_tag("thumbnail");
10151 push @{$stock_images{$stock_uniquename}}, {
10152 stock_id => $stock_id,
10153 stock_uniquename => $_->{stock_uniquename},
10154 stock_type_id => $_->{stock_type_id},
10155 image => '<a href="/image/view/'.$image_id.'" target="_blank">'.$image_source_tag_small.'</a>',
10156 image_id => $image_id,
10157 project_image_type_name => $_->{project_image_type_name}
10161 my @result;
10162 foreach (sort keys %stock_images) {
10163 my $i = $stock_images{$_};
10164 my $image_string = '';
10165 my $counter = 0;
10166 foreach my $j (@$i) {
10167 if ($counter == 0) {
10168 $image_string .= '<div class="row">';
10170 $image_string .= '<div class="col-sm-2"><div class="well well-sm>"><span title="'.$j->{project_image_type_name}.'">'.$j->{image}."</span><input type='checkbox' name='manage_drone_imagery_quality_control_image_select' value='".$j->{image_id}."'></div></div>";
10171 if ($counter == 5) {
10172 $image_string .= '</div>';
10173 $counter = 0;
10174 } else {
10175 $counter++;
10178 push @result, [$_, $image_string];
10181 $c->stash->{rest} = {success => 1, result => \@result};
10184 sub drone_imagery_get_image_for_saving_gcp : Path('/api/drone_imagery/get_image_for_saving_gcp') : ActionClass('REST') { }
10185 sub drone_imagery_get_image_for_saving_gcp_GET : Args(0) {
10186 my $self = shift;
10187 my $c = shift;
10188 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10189 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10190 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10191 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10192 my $drone_run_project_id = $c->req->param('drone_run_project_id');
10193 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10195 my $image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
10196 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
10197 bcs_schema=>$schema,
10198 drone_run_project_id_list=>[$drone_run_project_id],
10199 project_image_type_id_list => [$image_type_id]
10201 my ($result, $total_count) = $images_search->search();
10202 # print STDERR Dumper $result;
10204 my @image_ids;
10205 my @image_types;
10206 foreach (@$result) {
10207 push @image_ids, $_->{image_id};
10208 push @image_types, $_->{drone_run_band_project_type};
10211 my $gcps_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_ground_control_points', 'project_property')->cvterm_id();
10212 my $saved_gcps_json = $schema->resultset("Project::Projectprop")->find({
10213 project_id => $drone_run_project_id,
10214 type_id => $gcps_type_id
10216 my $saved_gcps_full = {};
10217 if ($saved_gcps_json) {
10218 $saved_gcps_full = decode_json $saved_gcps_json->value();
10221 my @saved_gcps_array = values %$saved_gcps_full;
10223 $c->stash->{rest} = {success => 1, result => $result, image_ids => \@image_ids, image_types => \@image_types, saved_gcps_full => $saved_gcps_full, gcps_array => \@saved_gcps_array};
10226 sub drone_imagery_get_image_for_time_series : Path('/api/drone_imagery/get_image_for_time_series') : ActionClass('REST') { }
10227 sub drone_imagery_get_image_for_time_series_GET : Args(0) {
10228 my $self = shift;
10229 my $c = shift;
10230 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10231 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10232 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10233 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10234 my $field_trial_id = $c->req->param('field_trial_id');
10235 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10237 if (!$field_trial_id) {
10238 $c->stash->{rest} = {error => "No field trial id given!" };
10239 $c->detach();
10242 my $image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
10243 my $tgi_image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_tgi_drone_imagery', 'project_md_image')->cvterm_id();
10244 my $vari_image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_vari_drone_imagery', 'project_md_image')->cvterm_id();
10245 my $ndvi_image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_ndvi_drone_imagery', 'project_md_image')->cvterm_id();
10246 my $ndre_image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_ndre_drone_imagery', 'project_md_image')->cvterm_id();
10247 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
10248 bcs_schema=>$schema,
10249 trial_id_list=>[$field_trial_id],
10250 project_image_type_id_list => [$image_type_id, $tgi_image_type_id, $vari_image_type_id, $ndvi_image_type_id, $ndre_image_type_id]
10252 my ($result, $total_count) = $images_search->search();
10253 # print STDERR Dumper $result;
10255 my $calendar_funcs = CXGN::Calendar->new({});
10257 my %image_type_map = (
10258 "denoised_stitched_drone_imagery" => "",
10259 "calculate_tgi_drone_imagery" => " (TGI)",
10260 "calculate_vari_drone_imagery" => " (VARI)",
10261 "calculate_ndvi_drone_imagery" => " (NDVI)",
10262 "calculate_ndre_drone_imagery" => " (NDRE)"
10265 my %image_ids;
10266 my %seen_epoch_seconds;
10267 my %seen_image_types;
10268 my %time_lookup;
10269 foreach (@$result) {
10270 # print STDERR Dumper $_;
10271 if ($_->{drone_run_band_plot_polygons}) {
10272 my $image_type = $_->{drone_run_band_project_type}.$image_type_map{$_->{project_image_type_name}};
10273 my $drone_run_date = $calendar_funcs->display_start_date($_->{drone_run_date});
10274 my $drone_run_date_object = Time::Piece->strptime($drone_run_date, "%Y-%B-%d %H:%M:%S");
10275 my $epoch_seconds = $drone_run_date_object->epoch;
10276 $time_lookup{$epoch_seconds} = $drone_run_date;
10277 $seen_epoch_seconds{$epoch_seconds}++;
10278 $seen_image_types{$image_type}++;
10279 $image_ids{$epoch_seconds}->{$image_type} = {
10280 image_id => $_->{image_id},
10281 drone_run_band_project_type => $image_type,
10282 drone_run_project_id => $_->{drone_run_project_id},
10283 drone_run_project_name => $_->{drone_run_project_name},
10284 plot_polygons => $_->{drone_run_band_plot_polygons},
10285 date => $drone_run_date
10289 my @sorted_epoch_seconds = sort keys %seen_epoch_seconds;
10290 my @sorted_image_types = sort keys %seen_image_types;
10291 my @sorted_dates;
10292 foreach (@sorted_epoch_seconds) {
10293 push @sorted_dates, $time_lookup{$_};
10296 my $field_layout = CXGN::Trial->new({bcs_schema => $schema, trial_id => $field_trial_id})->get_layout->get_design;
10297 my %plot_layout;
10298 while (my ($k, $v) = each %$field_layout) {
10299 $plot_layout{$v->{plot_name}} = $v;
10302 $c->stash->{rest} = {
10303 success => 1,
10304 image_ids_hash => \%image_ids,
10305 sorted_times => \@sorted_epoch_seconds,
10306 sorted_image_types => \@sorted_image_types,
10307 sorted_dates => \@sorted_dates,
10308 field_layout => \%plot_layout
10312 sub drone_imagery_saving_gcp : Path('/api/drone_imagery/saving_gcp') : ActionClass('REST') { }
10313 sub drone_imagery_saving_gcp_POST : Args(0) {
10314 my $self = shift;
10315 my $c = shift;
10316 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10317 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10318 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10319 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10320 my $drone_run_project_id = $c->req->param('drone_run_project_id');
10321 my $gcp_name = $c->req->param('name');
10322 my $gcp_x_pos = $c->req->param('x_pos');
10323 my $gcp_y_pos = $c->req->param('y_pos');
10324 my $gcp_latitude = $c->req->param('latitude');
10325 my $gcp_longitude = $c->req->param('longitude');
10326 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10328 my $gcps_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_ground_control_points', 'project_property')->cvterm_id();
10329 my $saved_gcps_json = $schema->resultset("Project::Projectprop")->find({
10330 project_id => $drone_run_project_id,
10331 type_id => $gcps_type_id
10333 my $saved_gcps_full = {};
10334 if ($saved_gcps_json) {
10335 $saved_gcps_full = decode_json $saved_gcps_json->value();
10338 $saved_gcps_full->{$gcp_name} = {
10339 name => $gcp_name,
10340 x_pos => $gcp_x_pos,
10341 y_pos => $gcp_y_pos,
10342 latitude => $gcp_latitude,
10343 longitude => $gcp_longitude
10346 my $saved_gcps_update = $schema->resultset('Project::Projectprop')->update_or_create({
10347 type_id=>$gcps_type_id,
10348 project_id=>$drone_run_project_id,
10349 rank=>0,
10350 value=>encode_json $saved_gcps_full
10353 key=>'projectprop_c1'
10356 my @saved_gcps_array = sort values %$saved_gcps_full;
10358 $c->stash->{rest} = {success => 1, saved_gcps_full => $saved_gcps_full, gcps_array => \@saved_gcps_array};
10361 sub drone_imagery_remove_one_gcp : Path('/api/drone_imagery/remove_one_gcp') : ActionClass('REST') { }
10362 sub drone_imagery_remove_one_gcp_POST : Args(0) {
10363 my $self = shift;
10364 my $c = shift;
10365 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10366 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10367 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10368 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10369 my $drone_run_project_id = $c->req->param('drone_run_project_id');
10370 my $gcp_name = $c->req->param('name');
10371 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10373 my $gcps_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_ground_control_points', 'project_property')->cvterm_id();
10374 my $saved_gcps_json = $schema->resultset("Project::Projectprop")->find({
10375 project_id => $drone_run_project_id,
10376 type_id => $gcps_type_id
10378 my $saved_gcps_full = {};
10379 if ($saved_gcps_json) {
10380 $saved_gcps_full = decode_json $saved_gcps_json->value();
10383 delete $saved_gcps_full->{$gcp_name};
10385 my $saved_gcps_update = $schema->resultset('Project::Projectprop')->update_or_create({
10386 type_id=>$gcps_type_id,
10387 project_id=>$drone_run_project_id,
10388 rank=>0,
10389 value=>encode_json $saved_gcps_full
10392 key=>'projectprop_c1'
10395 my @saved_gcps_array = values %$saved_gcps_full;
10397 $c->stash->{rest} = {success => 1, saved_gcps_full => $saved_gcps_full, gcps_array => \@saved_gcps_array};
10400 sub drone_imagery_obsolete_image_change : Path('/api/drone_imagery/obsolete_image_change') : ActionClass('REST') { }
10401 sub drone_imagery_obsolete_image_change_GET : Args(0) {
10402 my $self = shift;
10403 my $c = shift;
10404 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10405 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10406 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10407 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10408 my $image_id = $c->req->param('image_id');
10409 my ($user_id, $user_name, $user_role) = _check_user_login($c, 'curator');
10411 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
10412 $image->delete(); #makes obsolete
10414 $c->stash->{rest} = {success => 1};
10417 sub drone_imagery_calculate_phenotypes : Path('/api/drone_imagery/calculate_phenotypes') : ActionClass('REST') { }
10418 sub drone_imagery_calculate_phenotypes_POST : Args(0) {
10419 my $self = shift;
10420 my $c = shift;
10421 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10422 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10423 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10424 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10425 my $drone_run_band_project_id = $c->req->param('drone_run_band_project_id');
10426 my $drone_run_band_project_type = $c->req->param('drone_run_band_project_type');
10427 my $phenotype_method = $c->req->param('method');
10428 my $time_cvterm_id = $c->req->param('time_cvterm_id');
10429 my $plot_polygons_type = $c->req->param('plot_polygons_type');
10430 my @allowed_composed_cvs = split ',', $c->config->{composable_cvs};
10431 my $composable_cvterm_delimiter = $c->config->{composable_cvterm_delimiter};
10432 my $composable_cvterm_format = $c->config->{composable_cvterm_format};
10433 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10435 my $return = _perform_phenotype_calculation($c, $schema, $metadata_schema, $phenome_schema, $drone_run_band_project_id, $drone_run_band_project_type, $phenotype_method, $time_cvterm_id, $plot_polygons_type, $user_id, $user_name, $user_role, \@allowed_composed_cvs, $composable_cvterm_delimiter, $composable_cvterm_format, undef, undef, 1);
10437 $c->stash->{rest} = $return;
10440 sub drone_imagery_generate_phenotypes : Path('/api/drone_imagery/generate_phenotypes') : ActionClass('REST') { }
10441 sub drone_imagery_generate_phenotypes_GET : Args(0) {
10442 my $self = shift;
10443 my $c = shift;
10444 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10445 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10446 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10447 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10448 my $drone_run_project_id = $c->req->param('drone_run_project_id');
10449 my $time_cvterm_id = $c->req->param('time_cvterm_id');
10450 my $phenotype_methods = $c->req->param('phenotype_types') ? decode_json $c->req->param('phenotype_types') : ['zonal'];
10451 my $standard_process_type = $c->req->param('standard_process_type');
10452 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10454 my @standard_processes = split ',', $standard_process_type;
10455 my $return;
10456 foreach my $standard_process_type (@standard_processes) {
10457 $return = _perform_phenotype_automated($c, $schema, $metadata_schema, $phenome_schema, $drone_run_project_id, $time_cvterm_id, $phenotype_methods, $standard_process_type, undef, 1, $user_id, $user_name, $user_role);
10460 $c->stash->{rest} = $return;
10463 sub _perform_phenotype_calculation {
10464 my $c = shift;
10465 my $schema = shift;
10466 my $metadata_schema = shift;
10467 my $phenome_schema = shift;
10468 my $drone_run_band_project_id = shift;
10469 my $drone_run_band_project_type = shift;
10470 my $phenotype_method = shift;
10471 my $time_cvterm_id = shift;
10472 my $plot_polygons_type = shift;
10473 my $user_id = shift;
10474 my $user_name = shift;
10475 my $user_role = shift;
10476 my $allowed_composed_cvs = shift;
10477 my $composable_cvterm_delimiter = shift;
10478 my $composable_cvterm_format = shift;
10479 my $do_not_run_materialized_view_refresh = shift;
10480 my $ignore_new_phenotype_values = shift;
10481 my $overwrite_phenotype_values = shift;
10483 print STDERR Dumper [$drone_run_band_project_id, $drone_run_band_project_type, $phenotype_method, $time_cvterm_id, $plot_polygons_type];
10485 my $non_zero_pixel_count_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Nonzero Pixel Count|G2F:0000014')->cvterm_id;
10486 my $total_pixel_sum_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Total Pixel Sum|G2F:0000015')->cvterm_id;
10487 my $mean_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Mean Pixel Value|G2F:0000016')->cvterm_id;
10488 my $harmonic_mean_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Harmonic Mean Pixel Value|G2F:0000017')->cvterm_id;
10489 my $median_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Median Pixel Value|G2F:0000018')->cvterm_id;
10490 my $pixel_variance_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Pixel Variance|G2F:0000019')->cvterm_id;
10491 my $pixel_standard_dev_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Pixel Standard Deviation|G2F:0000020')->cvterm_id;
10492 my $pixel_pstandard_dev_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Pixel Population Standard Deviation|G2F:0000021')->cvterm_id;
10493 my $minimum_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Minimum Pixel Value|G2F:0000022')->cvterm_id;
10494 my $maximum_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Maximum Pixel Value|G2F:0000023')->cvterm_id;
10495 my $minority_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Minority Pixel Value|G2F:0000024')->cvterm_id;
10496 my $minority_pixel_count_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Minority Pixel Count|G2F:0000025')->cvterm_id;
10497 my $majority_pixel_value_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Majority Pixel Value|G2F:0000026')->cvterm_id;
10498 my $majority_pixel_count_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Majority Pixel Count|G2F:0000027')->cvterm_id;
10499 my $pixel_group_count_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Pixel Group Count|G2F:0000028')->cvterm_id;
10501 my $drone_run_band_project_type_cvterm_id;
10502 if ($drone_run_band_project_type eq 'Black and White Image') {
10503 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Black and White Image|ISOL:0000003')->cvterm_id;
10505 elsif ($drone_run_band_project_type eq 'Blue (450-520nm)') {
10506 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Blue (450-520nm)|ISOL:0000004')->cvterm_id;
10508 elsif ($drone_run_band_project_type eq 'Green (515-600nm)') {
10509 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Green (515-600nm)|ISOL:0000005')->cvterm_id;
10511 elsif ($drone_run_band_project_type eq 'Red (600-690nm)') {
10512 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Red (600-690nm)|ISOL:0000006')->cvterm_id;
10514 elsif ($drone_run_band_project_type eq 'Red Edge (690-750nm)') {
10515 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Red Edge (690-750nm)|ISOL:0000007')->cvterm_id;
10517 elsif ($drone_run_band_project_type eq 'NIR (780-3000nm)') {
10518 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'NIR (780-3000nm)|ISOL:0000008')->cvterm_id;
10520 elsif ($drone_run_band_project_type eq 'MIR (3000-50000nm)') {
10521 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'MIR (3000-50000nm)|ISOL:0000009')->cvterm_id;
10523 elsif ($drone_run_band_project_type eq 'FIR (50000-1000000nm)') {
10524 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'FIR (50000-1000000nm)|ISOL:0000010')->cvterm_id;
10526 elsif ($drone_run_band_project_type eq 'Thermal IR (9000-14000nm)') {
10527 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Thermal IR (9000-14000nm)|ISOL:0000011')->cvterm_id;
10529 elsif ($drone_run_band_project_type eq 'Raster DSM') {
10530 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Raster DSM|ISOL:0000323')->cvterm_id;
10532 elsif ($drone_run_band_project_type eq 'RGB Color Image') {
10533 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'RGB Color Image|ISOL:0000002')->cvterm_id;
10535 elsif ($drone_run_band_project_type eq 'Merged 3 Bands BGR') {
10536 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Merged 3 Bands BGR|ISOL:0000012')->cvterm_id;
10538 elsif ($drone_run_band_project_type eq 'Merged 3 Bands NRN') {
10539 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Merged 3 Bands NRN|ISOL:0000013')->cvterm_id;
10541 elsif ($drone_run_band_project_type eq 'Merged 3 Bands NReN') {
10542 $drone_run_band_project_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Merged 3 Bands NReN|ISOL:0000014')->cvterm_id;
10545 if (!$drone_run_band_project_type_cvterm_id) {
10546 die "No drone run band project type term found: $drone_run_band_project_type\n";
10549 my $observation_unit_plot_polygon_types = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
10550 my %isol_terms_map;
10551 while (my($k, $v) = each %$observation_unit_plot_polygon_types) {
10552 $isol_terms_map{$v->{name}} = {
10553 ISOL_name => $v->{ISOL_name},
10554 corresponding_channel => $v->{corresponding_channel},
10555 channels => $v->{channels}
10558 my $drone_run_band_plot_polygons_preprocess_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, $isol_terms_map{$plot_polygons_type}->{ISOL_name})->cvterm_id;;
10559 if (!$drone_run_band_plot_polygons_preprocess_cvterm_id) {
10560 die "Could not get preprocess cvterm for $plot_polygons_type\n";
10563 my $image_band_selected = $isol_terms_map{$plot_polygons_type}->{corresponding_channel};
10564 if (!defined($image_band_selected) && $phenotype_method eq 'zonal') {
10565 return {error => "No corresponding image band for this type $plot_polygons_type!"};
10568 my $plot_polygons_images_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, $plot_polygons_type, 'project_md_image')->cvterm_id();
10569 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
10570 bcs_schema=>$schema,
10571 drone_run_band_project_id_list=>[$drone_run_band_project_id],
10572 project_image_type_id=>$plot_polygons_images_cvterm_id
10574 my ($result, $total_count) = $images_search->search();
10575 print STDERR Dumper $total_count;
10577 my @header_cols;
10578 my @stocks;
10579 if ($total_count == 0) {
10580 return {error => "No plot polygon images for this type $plot_polygons_type!"};
10581 } else {
10583 my $traits = SGN::Model::Cvterm->get_traits_from_component_categories($schema, $allowed_composed_cvs, $composable_cvterm_delimiter, $composable_cvterm_format, {
10584 object => [],
10585 attribute => [$drone_run_band_project_type_cvterm_id],
10586 method => [],
10587 unit => [],
10588 trait => [$non_zero_pixel_count_cvterm_id, $total_pixel_sum_cvterm_id, $mean_pixel_value_cvterm_id, $harmonic_mean_pixel_value_cvterm_id, $median_pixel_value_cvterm_id, $pixel_variance_cvterm_id, $pixel_standard_dev_cvterm_id, $pixel_pstandard_dev_cvterm_id, $minimum_pixel_value_cvterm_id, $maximum_pixel_value_cvterm_id, $minority_pixel_value_cvterm_id, $minority_pixel_count_cvterm_id, $majority_pixel_value_cvterm_id, $majority_pixel_count_cvterm_id, $pixel_group_count_cvterm_id],
10589 tod => [$drone_run_band_plot_polygons_preprocess_cvterm_id],
10590 toy => [$time_cvterm_id],
10591 gen => [],
10593 my $existing_traits = $traits->{existing_traits};
10594 my $new_traits = $traits->{new_traits};
10595 #print STDERR Dumper $new_traits;
10596 #print STDERR Dumper $existing_traits;
10597 my %new_trait_names;
10598 foreach (@$new_traits) {
10599 my $components = $_->[0];
10600 $new_trait_names{$_->[1]} = join ',', @$components;
10603 my $onto = CXGN::Onto->new( { schema => $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id) } );
10604 my $new_terms = $onto->store_composed_term(\%new_trait_names);
10606 my $non_zero_pixel_count_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$non_zero_pixel_count_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10607 my $total_pixel_sum_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$total_pixel_sum_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10608 my $mean_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$mean_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10609 my $harmonic_mean_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$harmonic_mean_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10610 my $median_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$median_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10611 my $pixel_variance_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$pixel_variance_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10612 my $pixel_standard_dev_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$pixel_standard_dev_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10613 my $pixel_pstandard_dev_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$pixel_pstandard_dev_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10614 my $minimum_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$minimum_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10615 my $maximum_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$maximum_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10616 my $minority_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$minority_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10617 my $minority_pixel_count_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$minority_pixel_count_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10618 my $majority_pixel_value_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$majority_pixel_value_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10619 my $majority_pixel_count_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$majority_pixel_count_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10620 my $pixel_group_count_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$pixel_group_count_cvterm_id, $drone_run_band_project_type_cvterm_id, $drone_run_band_plot_polygons_preprocess_cvterm_id, $time_cvterm_id]);
10622 my $non_zero_pixel_count_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $non_zero_pixel_count_composed_cvterm_id, 'extended');
10623 my $total_pixel_sum_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $total_pixel_sum_composed_cvterm_id, 'extended');
10624 my $mean_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $mean_pixel_value_composed_cvterm_id, 'extended');
10625 my $harmonic_mean_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $harmonic_mean_pixel_value_composed_cvterm_id, 'extended');
10626 my $median_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $median_pixel_value_composed_cvterm_id, 'extended');
10627 my $pixel_variance_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $pixel_variance_composed_cvterm_id, 'extended');
10628 my $pixel_standard_dev_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $pixel_standard_dev_composed_cvterm_id, 'extended');
10629 my $pixel_pstandard_dev_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $pixel_pstandard_dev_composed_cvterm_id, 'extended');
10630 my $minimum_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $minimum_pixel_value_composed_cvterm_id, 'extended');
10631 my $maximum_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $maximum_pixel_value_composed_cvterm_id, 'extended');
10632 my $majority_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $minority_pixel_value_composed_cvterm_id, 'extended');
10633 my $majority_pixel_count_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $minority_pixel_count_composed_cvterm_id, 'extended');
10634 my $minority_pixel_value_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $majority_pixel_value_composed_cvterm_id, 'extended');
10635 my $minority_pixel_count_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $majority_pixel_count_composed_cvterm_id, 'extended');
10636 my $pixel_group_count_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $pixel_group_count_composed_cvterm_id, 'extended');
10638 my $temp_images_subdir = '';
10639 my $temp_results_subdir = '';
10640 my $calculate_phenotypes_script = '';
10641 my $linking_table_type_id;
10642 my $calculate_phenotypes_extra_args = '';
10643 my $archive_file_type = '';
10644 if ($phenotype_method eq 'zonal') {
10645 $temp_images_subdir = 'drone_imagery_calc_phenotypes_zonal_stats';
10646 $temp_results_subdir = 'drone_imagery_calc_phenotypes_zonal_stats_results';
10647 $calculate_phenotypes_script = 'CalculatePhenotypeZonalStats.py';
10648 $calculate_phenotypes_extra_args = ' --image_band_index '.$image_band_selected.' --plot_polygon_type '.$plot_polygons_type. ' --margin_percent 5';
10649 $archive_file_type = 'zonal_statistics_image_phenotypes';
10650 } elsif ($phenotype_method eq 'sift') {
10651 $temp_images_subdir = 'drone_imagery_calc_phenotypes_sift';
10652 $temp_results_subdir = 'drone_imagery_calc_phenotypes_sift_results';
10653 $calculate_phenotypes_script = 'CalculatePhenotypeSift.py';
10654 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_phenotypes_sift_drone_imagery', 'project_md_image')->cvterm_id();
10655 } elsif ($phenotype_method eq 'orb') {
10656 $temp_images_subdir = 'drone_imagery_calc_phenotypes_orb';
10657 $temp_results_subdir = 'drone_imagery_calc_phenotypes_orb_results';
10658 $calculate_phenotypes_script = 'CalculatePhenotypeOrb.py';
10659 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_phenotypes_orb_drone_imagery', 'project_md_image')->cvterm_id();
10660 } elsif ($phenotype_method eq 'surf') {
10661 $temp_images_subdir = 'drone_imagery_calc_phenotypes_surf';
10662 $temp_results_subdir = 'drone_imagery_calc_phenotypes_surf_results';
10663 $calculate_phenotypes_script = 'CalculatePhenotypeSurf.py';
10664 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_phenotypes_surf_drone_imagery', 'project_md_image')->cvterm_id();
10665 } elsif ($phenotype_method eq 'fourier_transform') {
10666 $temp_images_subdir = 'drone_imagery_calc_phenotypes_fourier_transform';
10667 $temp_results_subdir = 'drone_imagery_calc_phenotypes_fourier_transform_results';
10668 $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'calculate_phenotypes_fourier_transform_drone_imagery', 'project_md_image')->cvterm_id();
10669 $calculate_phenotypes_script = 'CalculatePhenotypeFourierTransform.py';
10670 $calculate_phenotypes_extra_args = ' --image_band_index '.$image_band_selected.' --plot_polygon_type '.$plot_polygons_type. ' --margin_percent 5 --frequency_threshold 30 --frequency_threshold_method frequency';
10671 $archive_file_type = 'fourier_transform_image_phenotypes';
10674 my @image_paths;
10675 my @out_paths;
10676 my %stock_images;
10677 my %stock_info;
10678 foreach (@$result) {
10679 my $image_id = $_->{image_id};
10680 my $stock_id = $_->{stock_id};
10681 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
10682 my $image_url = $image->get_image_url("original");
10683 my $image_fullpath = $image->get_filename('original_converted', 'full');
10684 my $image_source_tag_small = $image->get_img_src_tag("tiny");
10686 push @{$stock_images{$stock_id}}, $image_fullpath;
10687 $stock_info{$stock_id} = {
10688 stock_id => $stock_id,
10689 stock_uniquename => $_->{stock_uniquename},
10690 stock_type_id => $_->{stock_type_id},
10691 image => '<a href="/image/view/'.$image_id.'" target="_blank">'.$image_source_tag_small.'</a>',
10692 image_id => $image_id
10696 my $dir = $c->tempfiles_subdir('/drone_imagery_calculate_phenotypes_input_file_dir');
10697 my $temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_calculate_phenotypes_input_file_dir/fileXXXX');
10699 open(my $F, ">", $temp_input_file) || die "Can't open file ".$temp_input_file;
10700 foreach my $stock_id (sort keys %stock_images) {
10701 my $images_string = join ',', @{$stock_images{$stock_id}};
10702 print $F "$stock_id\t$images_string\n";
10704 if ($phenotype_method ne 'zonal') {
10705 my $dir = $c->tempfiles_subdir('/'.$temp_images_subdir);
10706 my $archive_temp_image = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => $temp_images_subdir.'/imageXXXX');
10707 $archive_temp_image .= '.png';
10708 push @out_paths, $archive_temp_image;
10711 close($F);
10713 my $out_paths_string = join ',', @out_paths;
10715 if ($out_paths_string) {
10716 $out_paths_string = ' --outfile_paths '.$out_paths_string;
10719 $dir = $c->tempfiles_subdir('/'.$temp_results_subdir);
10720 my $archive_temp_results = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => $temp_results_subdir.'/imageXXXX');
10722 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/'.$calculate_phenotypes_script.' --image_paths_input_file \''.$temp_input_file.'\' '.$out_paths_string.' --results_outfile_path \''.$archive_temp_results.'\''.$calculate_phenotypes_extra_args;
10723 print STDERR Dumper $cmd;
10724 my $status = system("$cmd > /dev/null");
10726 my $time = DateTime->now();
10727 my $timestamp = $time->ymd()."_".$time->hms();
10729 my $csv = Text::CSV->new({ sep_char => ',' });
10730 open(my $fh, '<', $archive_temp_results)
10731 or die "Could not open file '$archive_temp_results' $!";
10733 print STDERR "Opened $archive_temp_results\n";
10734 my $header = <$fh>;
10735 if ($csv->parse($header)) {
10736 @header_cols = $csv->fields();
10739 my $line = 0;
10740 my %zonal_stat_phenotype_data;
10741 my %plots_seen;
10742 my @traits_seen;
10743 if ($phenotype_method eq 'zonal' || $phenotype_method eq 'fourier_transform') {
10744 if ($header_cols[0] ne 'stock_id' ||
10745 $header_cols[1] ne 'nonzero_pixel_count' ||
10746 $header_cols[2] ne 'total_pixel_sum' ||
10747 $header_cols[3] ne 'mean_pixel_value' ||
10748 $header_cols[4] ne 'harmonic_mean_value' ||
10749 $header_cols[5] ne 'median_pixel_value' ||
10750 $header_cols[6] ne 'variance_pixel_value' ||
10751 $header_cols[7] ne 'stdev_pixel_value' ||
10752 $header_cols[8] ne 'pstdev_pixel_value' ||
10753 $header_cols[9] ne 'min_pixel_value' ||
10754 $header_cols[10] ne 'max_pixel_value' ||
10755 $header_cols[11] ne 'minority_pixel_value' ||
10756 $header_cols[12] ne 'minority_pixel_count' ||
10757 $header_cols[13] ne 'majority_pixel_value' ||
10758 $header_cols[14] ne 'majority_pixel_count' ||
10759 $header_cols[15] ne 'pixel_variety_count'
10761 $c->stash->{rest} = { error => "Pheno results must have header: 'stock_id', 'nonzero_pixel_count', 'total_pixel_sum', 'mean_pixel_value', 'harmonic_mean_value', 'median_pixel_value', 'variance_pixel_value', 'stdev_pixel_value', 'pstdev_pixel_value', 'min_pixel_value', 'max_pixel_value', 'minority_pixel_value', 'minority_pixel_count', 'majority_pixel_value', 'majority_pixel_count', 'pixel_variety_count'" };
10762 return;
10765 @traits_seen = (
10766 $non_zero_pixel_count_composed_trait_name,
10767 $total_pixel_sum_composed_trait_name,
10768 $mean_pixel_value_composed_trait_name,
10769 $harmonic_mean_pixel_value_composed_trait_name,
10770 $median_pixel_value_composed_trait_name,
10771 $pixel_variance_composed_trait_name,
10772 $pixel_standard_dev_composed_trait_name,
10773 $pixel_pstandard_dev_composed_trait_name,
10774 $minimum_pixel_value_composed_trait_name,
10775 $maximum_pixel_value_composed_trait_name,
10776 $majority_pixel_value_composed_trait_name,
10777 $majority_pixel_count_composed_trait_name,
10778 $minority_pixel_value_composed_trait_name,
10779 $minority_pixel_count_composed_trait_name,
10780 $pixel_group_count_composed_trait_name
10783 while ( my $row = <$fh> ){
10784 my @columns;
10785 if ($csv->parse($row)) {
10786 @columns = $csv->fields();
10789 my $stock_id = $columns[0];
10790 my $stock_uniquename = $stock_info{$stock_id}->{stock_uniquename};
10791 my $image_id = $stock_info{$stock_id}->{image_id};
10793 #print STDERR Dumper \@columns;
10794 $stock_info{$stock_id}->{result} = \@columns;
10796 $plots_seen{$stock_uniquename} = 1;
10797 $zonal_stat_phenotype_data{$stock_uniquename}->{$non_zero_pixel_count_composed_trait_name} = [$columns[1], $timestamp, $user_name, '', $image_id];
10798 $zonal_stat_phenotype_data{$stock_uniquename}->{$total_pixel_sum_composed_trait_name} = [$columns[2], $timestamp, $user_name, '', $image_id];
10799 $zonal_stat_phenotype_data{$stock_uniquename}->{$mean_pixel_value_composed_trait_name} = [$columns[3], $timestamp, $user_name, '', $image_id];
10800 $zonal_stat_phenotype_data{$stock_uniquename}->{$harmonic_mean_pixel_value_composed_trait_name} = [$columns[4], $timestamp, $user_name, '', $image_id];
10801 $zonal_stat_phenotype_data{$stock_uniquename}->{$median_pixel_value_composed_trait_name} = [$columns[5], $timestamp, $user_name, '', $image_id];
10802 $zonal_stat_phenotype_data{$stock_uniquename}->{$pixel_variance_composed_trait_name} = [$columns[6], $timestamp, $user_name, '', $image_id];
10803 $zonal_stat_phenotype_data{$stock_uniquename}->{$pixel_standard_dev_composed_trait_name} = [$columns[7], $timestamp, $user_name, '', $image_id];
10804 $zonal_stat_phenotype_data{$stock_uniquename}->{$pixel_pstandard_dev_composed_trait_name} = [$columns[8], $timestamp, $user_name, '', $image_id];
10805 $zonal_stat_phenotype_data{$stock_uniquename}->{$minimum_pixel_value_composed_trait_name} = [$columns[9], $timestamp, $user_name, '', $image_id];
10806 $zonal_stat_phenotype_data{$stock_uniquename}->{$maximum_pixel_value_composed_trait_name} = [$columns[10], $timestamp, $user_name, '', $image_id];
10807 $zonal_stat_phenotype_data{$stock_uniquename}->{$minority_pixel_value_composed_trait_name} = [$columns[11], $timestamp, $user_name, '', $image_id];
10808 $zonal_stat_phenotype_data{$stock_uniquename}->{$minority_pixel_count_composed_trait_name} = [$columns[12], $timestamp, $user_name, '', $image_id];
10809 $zonal_stat_phenotype_data{$stock_uniquename}->{$majority_pixel_value_composed_trait_name} = [$columns[13], $timestamp, $user_name, '', $image_id];
10810 $zonal_stat_phenotype_data{$stock_uniquename}->{$majority_pixel_count_composed_trait_name} = [$columns[14], $timestamp, $user_name, '', $image_id];
10811 $zonal_stat_phenotype_data{$stock_uniquename}->{$pixel_group_count_composed_trait_name} = [$columns[15], $timestamp, $user_name, '', $image_id];
10813 $line++;
10815 @stocks = values %stock_info;
10818 close $fh;
10819 print STDERR "Read $line lines in results file\n";
10821 if ($line > 0) {
10822 my %phenotype_metadata = (
10823 'archived_file' => $archive_temp_results,
10824 'archived_file_type' => $archive_file_type,
10825 'operator' => $user_name,
10826 'date' => $timestamp
10828 my @plot_units_seen = keys %plots_seen;
10830 my $store_args = {
10831 basepath=>$c->config->{basepath},
10832 dbhost=>$c->config->{dbhost},
10833 dbname=>$c->config->{dbname},
10834 dbuser=>$c->config->{dbuser},
10835 dbpass=>$c->config->{dbpass},
10836 bcs_schema=>$schema,
10837 metadata_schema=>$metadata_schema,
10838 phenome_schema=>$phenome_schema,
10839 user_id=>$user_id,
10840 stock_list=>\@plot_units_seen,
10841 trait_list=>\@traits_seen,
10842 values_hash=>\%zonal_stat_phenotype_data,
10843 has_timestamps=>1,
10844 metadata_hash=>\%phenotype_metadata,
10845 composable_validation_check_name=>$c->config->{composable_validation_check_name},
10846 allow_repeat_measures=>$c->config->{allow_repeat_measures}
10849 if ($overwrite_phenotype_values) {
10850 $store_args->{overwrite_values} = $overwrite_phenotype_values;
10852 if ($ignore_new_phenotype_values) {
10853 $store_args->{ignore_new_values} = $ignore_new_phenotype_values;
10856 my $store_phenotypes = CXGN::Phenotypes::StorePhenotypes->new(
10857 $store_args
10859 my ($verified_warning, $verified_error) = $store_phenotypes->verify();
10860 my ($stored_phenotype_error, $stored_phenotype_success) = $store_phenotypes->store();
10862 if (!$do_not_run_materialized_view_refresh) {
10863 my $bs = CXGN::BreederSearch->new( { dbh=>$c->dbc->dbh, dbname=>$c->config->{dbname}, } );
10864 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'fullview', 'nonconcurrent', $c->config->{basepath});
10868 my $count = 0;
10869 foreach (@out_paths) {
10870 my $stock = $stocks[$count];
10872 my $image_fullpath;
10873 my $image_url;
10874 my $image_source_tag_small;
10875 my $image_id;
10877 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
10878 my $md5checksum = $image->calculate_md5sum($_);
10879 my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
10880 JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
10881 WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ?;";
10882 my $h = $schema->storage->dbh->prepare($q);
10883 $h->execute($md5checksum, $linking_table_type_id, $drone_run_band_project_id);
10884 my ($saved_image_id) = $h->fetchrow_array();
10886 if ($saved_image_id) {
10887 print STDERR Dumper "Image $_ has already been added to the database and will not be added again.";
10888 $image_id = $saved_image_id;
10889 $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
10890 $image_fullpath = $image->get_filename('original_converted', 'full');
10891 $image_url = $image->get_image_url('original');
10892 $image_source_tag_small = $image->get_img_src_tag("tiny");
10893 } else {
10894 $image->set_sp_person_id($user_id);
10895 my $ret = $image->process_image($_, 'project', $drone_run_band_project_id, $linking_table_type_id);
10896 $ret = $image->associate_stock($stock->{stock_id}, $user_name);
10897 $image_fullpath = $image->get_filename('original_converted', 'full');
10898 $image_url = $image->get_image_url('original');
10899 $image_source_tag_small = $image->get_img_src_tag("tiny");
10900 $image_id = $image->get_image_id;
10903 $stocks[$count]->{image} = '<a href="/image/view/'.$image_id.'" target="_blank">'.$image_source_tag_small.'</a>';
10904 $stocks[$count]->{image_path} = $image_fullpath;
10905 $stocks[$count]->{image_url} = $image_url;
10906 $count++;
10908 unlink($_);
10912 return {
10913 result_header => \@header_cols, results => \@stocks
10917 sub drone_imagery_compare_images : Path('/api/drone_imagery/compare_images') : ActionClass('REST') { }
10918 sub drone_imagery_compare_images_GET : Args(0) {
10919 my $self = shift;
10920 my $c = shift;
10921 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10922 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10923 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10924 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10925 my $stock_id_list = $c->req->param('stock_id') ? [$c->req->param('stock_id')] : [];
10926 my $comparison_type = $c->req->param('comparison_type');
10927 my $image_ids = $c->req->param('image_ids') ? decode_json($c->req->param('image_ids')) : [];
10928 my $drone_run_band_ids = $c->req->param('drone_run_band_ids') ? decode_json($c->req->param('drone_run_band_ids')) : [];
10929 my $drone_run_ids = $c->req->param('drone_run_ids') ? decode_json($c->req->param('drone_run_ids')) : [];
10930 my $plot_polygon_type_ids = $c->req->param('image_type_ids') ? decode_json($c->req->param('image_type_ids')) : [];
10931 my ($user_id, $user_name, $user_role) = _check_user_login($c);
10933 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
10934 bcs_schema=>$schema,
10935 project_image_type_id_list=>$plot_polygon_type_ids,
10936 drone_run_project_id_list=>$drone_run_ids,
10937 drone_run_band_project_id_list=>$drone_run_band_ids,
10938 stock_id_list=>$stock_id_list,
10939 image_id_list=>$image_ids
10941 my ($result, $total_count) = $images_search->search();
10942 #print STDERR Dumper $result;
10943 print STDERR Dumper $total_count;
10945 my %data_hash;
10946 my %unique_drone_run_band_project_names;
10947 my %unique_image_type_names;
10948 foreach (@$result) {
10949 my $image_id = $_->{image_id};
10950 my $project_image_type_name = $_->{project_image_type_name};
10951 my $drone_run_band_project_name = $_->{drone_run_band_project_name};
10952 $unique_drone_run_band_project_names{$drone_run_band_project_name}++;
10953 $unique_image_type_names{$project_image_type_name}++;
10954 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
10955 my $image_url = $image->get_image_url("original");
10956 my $image_fullpath = $image->get_filename('original_converted', 'full');
10957 push @{$data_hash{$drone_run_band_project_name}->{$project_image_type_name}->{image_fullpaths}}, $image_fullpath;
10959 print STDERR Dumper \%data_hash;
10960 my @unique_drone_run_band_project_names_sort = sort keys %unique_drone_run_band_project_names;
10961 my @unique_image_type_names_sort = sort keys %unique_image_type_names;
10962 my $images1 = $data_hash{$unique_drone_run_band_project_names_sort[0]}->{$unique_image_type_names_sort[0]}->{image_fullpaths};
10963 my $image1 = $images1->[0];
10964 my $images2 = $data_hash{$unique_drone_run_band_project_names_sort[0]}->{$unique_image_type_names_sort[1]}->{image_fullpaths};
10965 my $image2 = $images2->[0];
10966 if (!$image2) {
10967 $images2 = $data_hash{$unique_drone_run_band_project_names_sort[1]}->{$unique_image_type_names_sort[1]}->{image_fullpaths};
10968 $image2 = $images2->[0];
10970 if (!$image2) {
10971 $images2 = $data_hash{$unique_drone_run_band_project_names_sort[1]}->{$unique_image_type_names_sort[0]}->{image_fullpaths};
10972 $image2 = $images2->[0];
10975 my $dir = $c->tempfiles_subdir('/drone_imagery_compare_images_dir');
10976 my $archive_temp_output = $c->tempfile( TEMPLATE => 'drone_imagery_compare_images_dir/outputfileXXXX');
10977 my $archive_temp_output_file = $c->config->{basepath}."/".$archive_temp_output;
10979 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/CompareTwoImagesPixelValues.py --image_path1 \''.$image1.'\' --image_path2 \''.$image2.'\' --image_type1 \''.$unique_image_type_names_sort[0].'\' --image_type2 \''.$unique_image_type_names_sort[1].'\' --outfile_path \''.$archive_temp_output_file.'\' ';
10980 print STDERR Dumper $cmd;
10981 my $status = system("$cmd > /dev/null");
10983 $c->stash->{rest} = { success => 1, result => $c->config->{main_production_site_url}.$archive_temp_output.".png" };
10986 sub drone_imagery_train_keras_model : Path('/api/drone_imagery/train_keras_model') : ActionClass('REST') { }
10987 sub drone_imagery_train_keras_model_POST : Args(0) {
10988 my $self = shift;
10989 my $c = shift;
10990 print STDERR Dumper $c->req->params();
10991 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
10992 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
10993 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
10994 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
10995 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
10996 my @field_trial_ids = split ',', $c->req->param('field_trial_ids');
10997 my $trait_id = $c->req->param('trait_id');
10998 my @aux_trait_id = $c->req->param('aux_trait_id[]') ? $c->req->param('aux_trait_id[]') : ();
10999 my $model_type = $c->req->param('model_type');
11000 my $population_id = $c->req->param('population_id');
11001 my $protocol_id = $c->req->param('nd_protocol_id');
11002 my $use_parents_grm = $c->req->param('use_parents_grm') eq 'yes' ? 1 : 0;
11003 my $drone_run_ids = decode_json($c->req->param('drone_run_ids'));
11004 my $plot_polygon_type_ids = decode_json($c->req->param('plot_polygon_type_ids'));
11005 my ($user_id, $user_name, $user_role) = _check_user_login($c);
11007 my $project_image_type_id_list = CXGN::DroneImagery::ImageTypes::get_all_project_md_image_observation_unit_plot_polygon_types($schema);
11009 my $dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_dir');
11010 my $archive_temp_result_agg_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/resultaggXXXX');
11012 my @accession_ids;
11013 if ($population_id && $population_id ne 'null') {
11014 my $accession_manager = CXGN::BreedersToolbox::Accessions->new(schema=>$schema);
11015 my $population_members = $accession_manager->get_population_members($population_id);
11016 foreach (@$population_members) {
11017 push @accession_ids, $_->{stock_id};
11021 my @result_agg;
11022 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
11023 bcs_schema=>$schema,
11024 drone_run_project_id_list=>$drone_run_ids,
11025 project_image_type_id_list=>$plot_polygon_type_ids,
11026 accession_list=>\@accession_ids
11028 my ($result, $total_count) = $images_search->search();
11029 #print STDERR Dumper $result;
11030 print STDERR Dumper $total_count;
11032 my %data_hash;
11033 my %seen_day_times;
11034 my %seen_image_types;
11035 my %seen_drone_run_band_project_ids;
11036 my %seen_drone_run_project_ids;
11037 my %seen_field_trial_ids;
11038 my %seen_stock_ids;
11039 foreach (@$result) {
11040 my $image_id = $_->{image_id};
11041 my $stock_id = $_->{stock_id};
11042 my $field_trial_id = $_->{trial_id};
11043 my $project_image_type_id = $_->{project_image_type_id};
11044 my $drone_run_band_project_id = $_->{drone_run_band_project_id};
11045 my $drone_run_project_id = $_->{drone_run_project_id};
11046 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
11047 my $image_url = $image->get_image_url("original");
11048 my $image_fullpath = $image->get_filename('original_converted', 'full');
11049 my $time_days_cvterm = $_->{drone_run_related_time_cvterm_json}->{day};
11050 my $time_days = (split '\|', $time_days_cvterm)[0];
11051 my $days = (split ' ', $time_days)[1];
11052 $data_hash{$field_trial_id}->{$stock_id}->{$project_image_type_id}->{$days} = {
11053 image => $image_fullpath,
11054 drone_run_project_id => $drone_run_project_id
11056 $seen_day_times{$days}++;
11057 $seen_image_types{$project_image_type_id}++;
11058 $seen_drone_run_band_project_ids{$drone_run_band_project_id}++;
11059 $seen_drone_run_project_ids{$drone_run_project_id}++;
11060 $seen_field_trial_ids{$field_trial_id}++;
11061 $seen_stock_ids{$stock_id}++;
11063 print STDERR Dumper \%seen_day_times;
11064 undef $result;
11066 my $accession_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'accession', 'stock_type')->cvterm_id();
11067 my $plot_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot', 'stock_type')->cvterm_id();
11068 my $plot_of_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot_of', 'stock_relationship')->cvterm_id();
11069 my $female_parent_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'female_parent', 'stock_relationship')->cvterm_id();
11070 my $male_parent_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'male_parent', 'stock_relationship')->cvterm_id();
11072 my @seen_plots = keys %seen_stock_ids;
11073 print STDERR Dumper \@seen_plots;
11074 my $plot_list_string = join ',', @seen_plots;
11075 my $q = "SELECT plot.stock_id, accession.stock_id, female_parent.stock_id, male_parent.stock_id
11076 FROM stock AS plot
11077 JOIN stock_relationship AS plot_acc_rel ON(plot_acc_rel.subject_id=plot.stock_id AND plot_acc_rel.type_id=$plot_of_cvterm_id)
11078 JOIN stock AS accession ON(plot_acc_rel.object_id=accession.stock_id AND accession.type_id=$accession_cvterm_id)
11079 JOIN stock_relationship AS female_parent_rel ON(accession.stock_id=female_parent_rel.object_id AND female_parent_rel.type_id=$female_parent_cvterm_id)
11080 JOIN stock AS female_parent ON(female_parent_rel.subject_id = female_parent.stock_id AND female_parent.type_id=$accession_cvterm_id)
11081 JOIN stock_relationship AS male_parent_rel ON(accession.stock_id=male_parent_rel.object_id AND male_parent_rel.type_id=$male_parent_cvterm_id)
11082 JOIN stock AS male_parent ON(male_parent_rel.subject_id = male_parent.stock_id AND male_parent.type_id=$accession_cvterm_id)
11083 WHERE plot.type_id=$plot_cvterm_id AND plot.stock_id IN ($plot_list_string);";
11084 my $h = $schema->storage->dbh()->prepare($q);
11085 $h->execute();
11086 my %plot_pedigrees_found = ();
11087 my %accession_pedigrees_found = ();
11088 my %unique_accession_ids_genotypes = ();
11089 while (my ($plot_stock_id, $accession_stock_id, $female_parent_stock_id, $male_parent_stock_id) = $h->fetchrow_array()) {
11090 $unique_accession_ids_genotypes{$accession_stock_id}++;
11091 $plot_pedigrees_found{$plot_stock_id} = {
11092 female_stock_id => $female_parent_stock_id,
11093 male_stock_id => $male_parent_stock_id
11095 $accession_pedigrees_found{$accession_stock_id} = {
11096 female_stock_id => $female_parent_stock_id,
11097 male_stock_id => $male_parent_stock_id
11101 my %unique_genotype_accessions;
11102 if ($protocol_id) {
11103 my @accession_list = sort keys %unique_accession_ids_genotypes;
11104 my $geno = CXGN::Genotype::DownloadFactory->instantiate(
11105 'DosageMatrix', #can be either 'VCF' or 'DosageMatrix'
11107 bcs_schema=>$schema,
11108 people_schema=>$people_schema,
11109 cache_root_dir=>$c->config->{cache_file_path},
11110 accession_list=>\@accession_list,
11111 protocol_id_list=>[$protocol_id],
11112 compute_from_parents=>$use_parents_grm,
11113 return_only_first_genotypeprop_for_stock=>1,
11114 prevent_transpose=>1
11117 my $file_handle = $geno->download(
11118 $c->config->{cluster_shared_tempdir},
11119 $c->config->{backend},
11120 $c->config->{cluster_host},
11121 $c->config->{'web_cluster_queue'},
11122 $c->config->{basepath}
11124 open my $geno_fh, "<&", $file_handle or die "Can't open output file: $!";
11125 my $header = <$geno_fh>;
11126 while (my $row = <$geno_fh>) {
11127 chomp($row);
11128 if ($row) {
11129 my @line = split "\t", $row;
11130 my $stock_id = shift @line;
11131 my $out_line = join "\n", @line;
11132 if ($out_line) {
11133 my $geno_temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/genoinputfileXXXX');
11134 my $status = write_file($geno_temp_input_file, $out_line."\n");
11135 $unique_genotype_accessions{$stock_id} = $geno_temp_input_file;
11139 close($geno_fh);
11140 @accession_ids = keys %unique_genotype_accessions;
11143 my @trait_ids = ($trait_id);
11144 if (scalar(@aux_trait_id) > 0) {
11145 push @trait_ids, @aux_trait_id;
11148 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
11149 'MaterializedViewTable',
11151 bcs_schema=>$schema,
11152 data_level=>'plot',
11153 trait_list=>\@trait_ids,
11154 trial_list=>\@field_trial_ids,
11155 plot_list=>\@seen_plots,
11156 accession_list=>\@accession_ids,
11157 exclude_phenotype_outlier=>0,
11158 include_timestamp=>0
11161 my ($data, $unique_traits) = $phenotypes_search->search();
11163 my %phenotype_data_hash;
11164 my %aux_data_hash;
11165 foreach my $d (@$data) {
11166 foreach my $o (@{$d->{observations}}) {
11167 if ($o->{trait_id} == $trait_id) {
11168 $phenotype_data_hash{$d->{observationunit_stock_id}}->{trait_value} = {
11169 trait_name => $o->{trait_name},
11170 value => $o->{value}
11172 } else {
11173 $phenotype_data_hash{$d->{observationunit_stock_id}}->{aux_trait_value}->{$o->{trait_id}} = $o->{value};
11176 $aux_data_hash{$d->{trial_id}}->{$d->{observationunit_stock_id}} = $d;
11178 #print STDERR Dumper \%data_hash;
11179 undef $data;
11181 my $archive_temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/inputfileXXXX');
11182 my $archive_temp_input_aux_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/inputfileauxXXXX');
11183 my $archive_temp_output_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/outputfileXXXX');
11184 my $archive_temp_autoencoder_output_model_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/autoencodermodelfileXXXX').".hdf5";
11185 my $archive_temp_loss_history_file_string = $c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/losshistoryXXXX');
11186 my $archive_temp_loss_history_file = $c->config->{basepath}."/".$archive_temp_loss_history_file_string;
11188 my $keras_project_name = basename($c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/keras_tuner_XXXX'));
11189 my $archive_temp_output_model_file = $c->config->{cluster_shared_tempdir}.'/'.$keras_project_name.'.hdf5';
11190 my $keras_tuner_dir = $c->config->{cluster_shared_tempdir};
11191 my $keras_tuner_output_project_dir = $keras_tuner_dir.$keras_project_name;
11193 my %output_images;
11195 open(my $F_aux, ">", $archive_temp_input_aux_file) || die "Can't open file ".$archive_temp_input_aux_file;
11196 print $F_aux 'stock_id,value,trait_name,field_trial_id,accession_id,female_id,male_id,output_image_file,genotype_file';
11197 if (scalar(@aux_trait_id)>0) {
11198 my $aux_trait_counter = 0;
11199 foreach (@aux_trait_id) {
11200 print $F_aux ",aux_trait_$aux_trait_counter";
11201 $aux_trait_counter++;
11204 print $F_aux "\n";
11206 # LSTM model uses longitudinal time information, so input ordered by field_trial, then stock_id, then by image_type, then by chronological ascending time for each drone run
11207 if ($model_type eq 'KerasCNNLSTMDenseNet121ImageNetWeights') {
11208 foreach my $field_trial_id (sort keys %seen_field_trial_ids){
11209 foreach my $stock_id (sort keys %seen_stock_ids){
11210 foreach my $image_type (sort keys %seen_image_types) {
11211 my $d = $aux_data_hash{$field_trial_id}->{$stock_id};
11212 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
11213 my $trait_name = $phenotype_data_hash{$stock_id}->{trait_value}->{trait_name};
11214 my $female_parent_stock_id = $plot_pedigrees_found{$stock_id}->{female_stock_id} || 0;
11215 my $male_parent_stock_id = $plot_pedigrees_found{$stock_id}->{male_stock_id} || 0;
11216 my $germplasm_id = $d->{germplasm_stock_id};
11217 if (defined($value)) {
11218 my $archive_temp_output_image_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/outputimagefileXXXX');
11219 $archive_temp_output_image_file .= ".png";
11220 $output_images{$stock_id} = {
11221 image_file => $archive_temp_output_image_file,
11222 field_trial_id => $field_trial_id
11224 my $geno_file = $unique_genotype_accessions{$germplasm_id} || '';
11226 print $F_aux "$stock_id,";
11227 print $F_aux "$value,";
11228 print $F_aux "$trait_name,";
11229 print $F_aux "$field_trial_id,";
11230 print $F_aux "$germplasm_id,";
11231 print $F_aux "$female_parent_stock_id,";
11232 print $F_aux "$male_parent_stock_id,";
11233 print $F_aux "$archive_temp_output_image_file,";
11234 print $F_aux "$geno_file";
11235 if (scalar(@aux_trait_id)>0) {
11236 print $F_aux ',';
11237 my @aux_values;
11238 foreach my $aux_trait (@aux_trait_id) {
11239 my $aux_value = $phenotype_data_hash{$stock_id} ? $phenotype_data_hash{$stock_id}->{aux_trait_value}->{$aux_trait} : '';
11240 if (!$aux_value) {
11241 $aux_value = '';
11243 push @aux_values, $aux_value;
11245 my $aux_values_string = scalar(@aux_values)>0 ? join ',', @aux_values : '';
11246 print $F_aux $aux_values_string;
11248 print $F_aux "\n";
11254 #Non-LSTM models group image types for each stock into a single montage, so the input is ordered by field trial, then ascending chronological time, then by stock_id, and then by image_type.
11255 else {
11256 foreach my $field_trial_id (sort keys %seen_field_trial_ids){
11257 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
11258 foreach my $stock_id (sort keys %seen_stock_ids){
11259 my $d = $aux_data_hash{$field_trial_id}->{$stock_id};
11260 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
11261 my $trait_name = $phenotype_data_hash{$stock_id}->{trait_value}->{trait_name};
11262 my $female_parent_stock_id = $plot_pedigrees_found{$stock_id}->{female_stock_id} || 0;
11263 my $male_parent_stock_id = $plot_pedigrees_found{$stock_id}->{male_stock_id} || 0;
11264 my $germplasm_id = $d->{germplasm_stock_id};
11265 if (defined($value)) {
11266 my $archive_temp_output_image_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/outputimagefileXXXX');
11267 $archive_temp_output_image_file .= ".png";
11268 $output_images{$stock_id} = {
11269 image_file => $archive_temp_output_image_file,
11270 field_trial_id => $field_trial_id
11272 my $geno_file = $unique_genotype_accessions{$germplasm_id} || '';
11273 print STDERR Dumper $geno_file;
11275 print $F_aux "$stock_id,";
11276 print $F_aux "$value,";
11277 print $F_aux "$trait_name,";
11278 print $F_aux "$field_trial_id,";
11279 print $F_aux "$germplasm_id,";
11280 print $F_aux "$female_parent_stock_id,";
11281 print $F_aux "$male_parent_stock_id,";
11282 print $F_aux "$archive_temp_output_image_file,";
11283 print $F_aux "$geno_file";
11284 if (scalar(@aux_trait_id)>0) {
11285 print $F_aux ',';
11286 my @aux_values;
11287 foreach my $aux_trait (@aux_trait_id) {
11288 my $aux_value = $phenotype_data_hash{$stock_id} ? $phenotype_data_hash{$stock_id}->{aux_trait_value}->{$aux_trait} : '';
11289 if (!$aux_value) {
11290 $aux_value = '';
11292 push @aux_values, $aux_value;
11294 my $aux_values_string = scalar(@aux_values)>0 ? join ',', @aux_values : '';
11295 print $F_aux $aux_values_string;
11297 print $F_aux "\n";
11303 close($F_aux);
11305 open(my $F, ">", $archive_temp_input_file) || die "Can't open file ".$archive_temp_input_file;
11306 print $F "stock_id,image_path,image_type,day,drone_run_project_id,value\n";
11308 # LSTM model uses longitudinal time information, so input ordered by field_trial, then stock_id, then by image_type, then by chronological ascending time for each drone run
11309 if ($model_type eq 'KerasCNNLSTMDenseNet121ImageNetWeights') {
11310 foreach my $field_trial_id (sort keys %seen_field_trial_ids){
11311 foreach my $stock_id (sort keys %seen_stock_ids){
11312 foreach my $image_type (sort keys %seen_image_types) {
11313 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
11314 my $data = $data_hash{$field_trial_id}->{$stock_id}->{$image_type}->{$day_time};
11315 my $image_fullpath = $data->{image};
11316 my $drone_run_project_id = $data->{drone_run_project_id};
11317 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
11318 if (defined($value)) {
11319 print $F "$stock_id,";
11320 print $F "$image_fullpath,";
11321 print $F "$image_type,";
11322 print $F "$day_time,";
11323 print $F "$drone_run_project_id,";
11324 print $F "$value\n";
11331 #Non-LSTM models group image types for each stock into a single montage, so the input is ordered by field trial, then ascending chronological time, then by stock_id, and then by image_type.
11332 else {
11333 foreach my $field_trial_id (sort keys %seen_field_trial_ids) {
11334 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
11335 foreach my $stock_id (sort keys %seen_stock_ids){
11336 foreach my $image_type (sort keys %seen_image_types) {
11337 my $data = $data_hash{$field_trial_id}->{$stock_id}->{$image_type}->{$day_time};
11338 my $image_fullpath = $data->{image};
11339 my $drone_run_project_id = $data->{drone_run_project_id};
11340 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
11341 if (defined($value)) {
11342 print $F "$stock_id,";
11343 print $F "$image_fullpath,";
11344 print $F "$image_type,";
11345 print $F "$day_time,";
11346 print $F "$drone_run_project_id,";
11347 print $F "$value\n";
11354 close($F);
11356 undef %data_hash;
11357 undef %phenotype_data_hash;
11358 undef %aux_data_hash;
11360 my $log_file_path = '';
11361 if ($c->config->{error_log}) {
11362 $log_file_path = ' --log_file_path \''.$c->config->{error_log}.'\'';
11365 my $cmd = '';
11366 if ($model_type eq 'KerasTunerCNNSequentialSoftmaxCategorical') {
11367 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --output_random_search_result_project \''.$keras_tuner_output_project_dir.'\' --keras_model_type simple_1_tuner --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11369 elsif ($model_type eq 'SimpleKerasTunerCNNSequentialSoftmaxCategorical') {
11370 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --output_random_search_result_project \''.$keras_tuner_output_project_dir.'\' --keras_model_type simple_tuner --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11372 # elsif ($model_type eq 'KerasTunerCNNInceptionResNetV2') {
11373 # $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --output_random_search_result_project \''.$keras_tuner_output_project_dir.'\' --keras_model_type inceptionresnetv2application_tuner --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11375 elsif ($model_type eq 'KerasCNNInceptionResNetV2ImageNetWeights') {
11376 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --keras_model_type inceptionresnetv2application --keras_model_weights imagenet --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11378 elsif ($model_type eq 'KerasCNNInceptionResNetV2') {
11379 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --keras_model_type inceptionresnetv2 --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11381 elsif ($model_type eq 'KerasCNNLSTMDenseNet121ImageNetWeights') {
11382 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --keras_model_type densenet121_lstm_imagenet --keras_model_weights imagenet --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11384 elsif ($model_type eq 'KerasCNNDenseNet121ImageNetWeights') {
11385 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --keras_model_type densenet121application --keras_model_weights imagenet --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11387 elsif ($model_type eq 'KerasCNNSequentialSoftmaxCategorical') {
11388 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --keras_model_type simple_1 --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11390 elsif ($model_type eq 'KerasCNNMLPExample') {
11391 $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/KerasCNNSequentialSoftmaxCategorical.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_aux_data_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --output_model_file_path \''.$archive_temp_output_model_file.'\' '.$log_file_path.' --keras_model_type mlp_cnn_example --output_loss_history \''.$archive_temp_loss_history_file.'\' --output_autoencoder_model_file_path \''.$archive_temp_autoencoder_output_model_file.'\' ';
11393 else {
11394 $c->stash->{rest} = {error => "$model_type not supported!"};
11395 $c->detach();
11397 print STDERR Dumper $cmd;
11398 my $status = system("$cmd > /dev/null");
11400 my $csv = Text::CSV->new({ sep_char => ',' });
11401 open(my $fh, '<', $archive_temp_output_file)
11402 or die "Could not open file '$archive_temp_output_file' $!";
11404 while ( my $row = <$fh> ){
11405 my @columns;
11406 if ($csv->parse($row)) {
11407 @columns = $csv->fields();
11409 my $line = '';
11410 foreach (@columns) {
11411 if ($_ eq ' ') {
11412 $line .= '&nbsp;';
11414 else {
11415 $line .= $_;
11418 push @result_agg, $line;
11420 close($fh);
11421 #print STDERR Dumper \@result_agg;
11423 open($F, ">", $archive_temp_result_agg_file) || die "Can't open file ".$archive_temp_result_agg_file;
11424 foreach my $data (@result_agg){
11425 print $F $data;
11426 print $F "\n";
11428 close($F);
11430 my @loss_history;
11431 open(my $fh3, '<', $archive_temp_loss_history_file)
11432 or die "Could not open file '$archive_temp_loss_history_file' $!";
11434 while ( my $row = <$fh3> ){
11435 my @columns;
11436 if ($csv->parse($row)) {
11437 @columns = $csv->fields();
11439 push @loss_history, $columns[0];
11441 close($fh3);
11443 print STDERR "Train loss PLOT $archive_temp_loss_history_file \n";
11444 my $rmatrix = R::YapRI::Data::Matrix->new({
11445 name => 'matrix1',
11446 coln => 1,
11447 rown => scalar(@loss_history),
11448 colnames => ["loss"],
11449 data => \@loss_history
11452 my $rbase = R::YapRI::Base->new();
11453 my $r_block = $rbase->create_block('r_block');
11454 $rmatrix->send_rbase($rbase, 'r_block');
11455 $r_block->add_command('dataframe.matrix1 <- data.frame(matrix1)');
11456 $r_block->add_command('dataframe.matrix1$loss <- as.numeric(dataframe.matrix1$loss)');
11457 $r_block->add_command('png(filename=\''.$archive_temp_loss_history_file.'\')');
11458 $r_block->add_command('plot(seq(1,length(dataframe.matrix1$loss)), dataframe.matrix1$loss)');
11459 $r_block->add_command('dev.off()');
11460 $r_block->run_block();
11462 my @saved_trained_image_urls;
11463 if ($c->req->param('save_model') == 1) {
11464 my $model_name = $c->req->param('model_name');
11465 my $model_description = $c->req->param('model_description');
11467 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_keras_trained', 'project_md_image')->cvterm_id();
11469 # my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
11470 # JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
11471 # JOIN phenome.stock_image AS stock_image ON(md_image.image_id = stock_image.image_id)
11472 # WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ? AND stock_image.stock_id = ?;";
11473 # my $h = $schema->storage->dbh->prepare($q);
11475 foreach my $stock_id (keys %output_images){
11476 my $image_file = $output_images{$stock_id}->{image_file};
11477 my $field_trial_id = $output_images{$stock_id}->{field_trial_id};
11478 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
11479 # my $md5checksum = $image->calculate_md5sum($image_file);
11480 # $h->execute($md5checksum, $linking_table_type_id, $field_trial_id, $stock_id);
11481 # my ($saved_image_id) = $h->fetchrow_array();
11483 my $output_image_id;
11484 my $output_image_url;
11485 my $output_image_fullpath;
11486 # if ($saved_image_id) {
11487 # print STDERR Dumper "Image $image_file has already been added to the database and will not be added again.";
11488 # $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
11489 # $output_image_fullpath = $image->get_filename('original_converted', 'full');
11490 # $output_image_url = $image->get_image_url('original');
11491 # $output_image_id = $image->get_image_id();
11492 # } else {
11493 $image->set_sp_person_id($user_id);
11494 my $ret = $image->process_image($image_file, 'project', $field_trial_id, $linking_table_type_id);
11495 my $stock_associate = $image->associate_stock($stock_id, $user_name);
11496 $output_image_fullpath = $image->get_filename('original_converted', 'full');
11497 $output_image_url = $image->get_image_url('original');
11498 $output_image_id = $image->get_image_id();
11500 push @saved_trained_image_urls, $output_image_url;
11503 _perform_save_trained_keras_cnn_model($c, $schema, $metadata_schema, $phenome_schema, \@field_trial_ids, $archive_temp_output_model_file, $archive_temp_autoencoder_output_model_file, $archive_temp_input_file, $archive_temp_input_aux_file, $model_name, $model_description, $drone_run_ids, $plot_polygon_type_ids, $trait_id, $model_type, \@aux_trait_id, $protocol_id, $use_parents_grm, $user_id, $user_name, $user_role);
11506 $c->stash->{rest} = { success => 1, results => \@result_agg, model_input_file => $archive_temp_input_file, model_input_aux_file => $archive_temp_input_aux_file, model_temp_file => $archive_temp_output_model_file, model_autoencoder_temp_file => $archive_temp_autoencoder_output_model_file, trait_id => $trait_id, loss_history => \@loss_history, loss_history_file => $archive_temp_loss_history_file_string, saved_trained_image_urls => \@saved_trained_image_urls };
11509 sub drone_imagery_save_keras_model : Path('/api/drone_imagery/save_keras_model') : ActionClass('REST') { }
11510 sub drone_imagery_save_keras_model_GET : Args(0) {
11511 my $self = shift;
11512 my $c = shift;
11513 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
11514 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
11515 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
11516 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
11517 my @field_trial_ids = split ',', $c->req->param('field_trial_ids');
11518 my $model_file = $c->req->param('model_file');
11519 my $archive_temp_autoencoder_output_model_file = $c->req->param('model_autoencoder_file');
11520 my $model_input_file = $c->req->param('model_input_file');
11521 my $model_input_aux_file = $c->req->param('model_input_aux_file');
11522 my $model_name = $c->req->param('model_name');
11523 my $model_description = $c->req->param('model_description');
11524 my $trait_id = $c->req->param('trait_id');
11525 my @aux_trait_id = $c->req->param('aux_trait_id[]') ? $c->req->param('aux_trait_id[]') : ();
11526 my $protocol_id = $c->req->param('protocol_id');
11527 my $use_parents_grm = $c->req->param('use_parents_grm');
11528 my $model_type = $c->req->param('model_type');
11529 my $drone_run_ids = decode_json($c->req->param('drone_run_ids'));
11530 my $plot_polygon_type_ids = decode_json($c->req->param('plot_polygon_type_ids'));
11531 my ($user_id, $user_name, $user_role) = _check_user_login($c);
11533 _perform_save_trained_keras_cnn_model($c, $schema, $metadata_schema, $phenome_schema, \@field_trial_ids, $model_file, $model_input_file, $archive_temp_autoencoder_output_model_file, $model_input_aux_file, $model_name, $model_description, $drone_run_ids, $plot_polygon_type_ids, $trait_id, $model_type, \@aux_trait_id, $protocol_id, $use_parents_grm, $user_id, $user_name, $user_role);
11536 sub _perform_save_trained_keras_cnn_model {
11537 my $c = shift;
11538 my $schema = shift;
11539 my $metadata_schema = shift;
11540 my $phenome_schema = shift;
11541 my $field_trial_ids = shift;
11542 my $model_file = shift;
11543 my $archive_temp_autoencoder_output_model_file = shift;
11544 my $model_input_file = shift;
11545 my $model_input_aux_file = shift;
11546 my $model_name = shift;
11547 my $model_description = shift;
11548 my $drone_run_ids = shift;
11549 my $plot_polygon_type_ids = shift;
11550 my $trait_id = shift;
11551 my $model_type = shift;
11552 my $aux_trait_ids = shift;
11553 my $geno_protocol_id = shift;
11554 my $use_parents_grm = shift;
11555 my $user_id = shift;
11556 my $user_name = shift;
11557 my $user_role = shift;
11558 my @field_trial_ids = @$field_trial_ids;
11559 my $trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $trait_id, 'extended');
11561 my $keras_cnn_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'trained_keras_cnn_model', 'protocol_type')->cvterm_id();
11562 my $keras_cnn_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_experiment', 'experiment_type')->cvterm_id();
11564 my $m = CXGN::AnalysisModel::SaveModel->new({
11565 bcs_schema=>$schema,
11566 metadata_schema=>$metadata_schema,
11567 phenome_schema=>$phenome_schema,
11568 archive_path=>$c->config->{archive_path},
11569 model_name=>$model_name,
11570 model_description=>$model_description,
11571 model_language=>'Python',
11572 model_type_cvterm_id=>$keras_cnn_cvterm_id,
11573 model_properties=>{variable_name => $trait_name, variable_id => $trait_id, aux_trait_ids => $aux_trait_ids, model_type=>$model_type, image_type=>'standard_4_montage', nd_protocol_id => $geno_protocol_id, use_parents_grm => $use_parents_grm},
11574 application_name=>'KerasCNNModels',
11575 application_version=>'V1.01',
11576 is_public=>1,
11577 user_id=>$user_id,
11578 user_role=>$user_role
11580 my $saved_model = $m->save_model();
11581 my $saved_model_id = $saved_model->{nd_protocol_id};
11583 my $analysis_model = CXGN::AnalysisModel::GetModel->new({
11584 bcs_schema=>$schema,
11585 metadata_schema=>$metadata_schema,
11586 phenome_schema=>$phenome_schema,
11587 nd_protocol_id=>$saved_model_id
11589 $analysis_model->store_analysis_model_files({
11590 # project_id => $saved_analysis_id,
11591 archived_model_file_type=>'trained_keras_cnn_model',
11592 model_file=>$model_file,
11593 archived_training_data_file_type=>'trained_keras_cnn_model_input_data_file',
11594 archived_training_data_file=>$model_input_file,
11595 archived_auxiliary_files=>[
11596 {auxiliary_model_file => $archive_temp_autoencoder_output_model_file, auxiliary_model_file_archive_type => 'trained_keras_cnn_autoencoder_model'},
11597 {auxiliary_model_file => $model_input_aux_file, auxiliary_model_file_archive_type => 'trained_keras_cnn_model_input_aux_data_file'}
11599 archive_path=>$c->config->{archive_path},
11600 user_id=>$user_id,
11601 user_role=>$user_role
11604 $c->stash->{rest} = $saved_model;
11607 sub drone_imagery_predict_keras_model : Path('/api/drone_imagery/predict_keras_model') : ActionClass('REST') { }
11608 sub drone_imagery_predict_keras_model_POST : Args(0) {
11609 my $self = shift;
11610 my $c = shift;
11611 print STDERR Dumper $c->req->params();
11612 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
11613 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
11614 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
11615 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
11616 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
11617 my @field_trial_ids = split ',', $c->req->param('field_trial_ids');
11618 my $model_id = $c->req->param('model_id');
11619 my $model_prediction_type = $c->req->param('model_prediction_type');
11620 my $population_id = $c->req->param('population_id');
11621 my $drone_run_ids = decode_json($c->req->param('drone_run_ids'));
11622 my $plot_polygon_type_ids = decode_json($c->req->param('plot_polygon_type_ids'));
11623 my @aux_trait_ids = $c->req->param('aux_trait_ids[]') ? $c->req->param('aux_trait_ids[]') : ();
11624 my ($user_id, $user_name, $user_role) = _check_user_login($c);
11626 my @allowed_composed_cvs = split ',', $c->config->{composable_cvs};
11627 my $composable_cvterm_delimiter = $c->config->{composable_cvterm_delimiter};
11628 my $composable_cvterm_format = $c->config->{composable_cvterm_format};
11630 my $return = _perform_keras_cnn_predict($c, $schema, $metadata_schema, $people_schema, $phenome_schema, \@field_trial_ids, $model_id, $drone_run_ids, $plot_polygon_type_ids, $model_prediction_type, $population_id, \@allowed_composed_cvs, $composable_cvterm_format, $composable_cvterm_delimiter, \@aux_trait_ids, $user_id, $user_name, $user_role);
11632 $c->stash->{rest} = $return;
11635 sub _perform_keras_cnn_predict {
11636 my $c = shift;
11637 my $schema = shift;
11638 my $metadata_schema = shift;
11639 my $people_schema = shift;
11640 my $phenome_schema = shift;
11641 my $field_trial_ids = shift;
11642 my $model_id = shift;
11643 my $drone_run_ids = shift;
11644 my $plot_polygon_type_ids = shift;
11645 my $model_prediction_type = shift;
11646 my $population_id = shift;
11647 my $allowed_composed_cvs = shift;
11648 my $composable_cvterm_format = shift;
11649 my $composable_cvterm_delimiter = shift;
11650 my $aux_trait_ids = shift;
11651 my $user_id = shift;
11652 my $user_name = shift;
11653 my $user_role = shift;
11654 my @field_trial_ids = @$field_trial_ids;
11656 my $keras_cnn_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'trained_keras_cnn_model', 'protocol_type')->cvterm_id();
11657 my $model_properties_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_properties', 'protocol_property')->cvterm_id();
11658 my $keras_cnn_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_experiment', 'experiment_type')->cvterm_id();
11660 my $plot_polygon_rgb_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_rgb_imagery', 'project_md_image')->cvterm_id();
11661 my $plot_polygon_green_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_rgb_imagery_channel_2', 'project_md_image')->cvterm_id();
11662 my $plot_polygon_red_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_rgb_imagery_channel_3', 'project_md_image')->cvterm_id();
11663 my $plot_polygon_red_threshold_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_rgb_background_removed_threshold_imagery_channel_3', 'project_md_image')->cvterm_id();
11665 if (scalar(@$plot_polygon_type_ids) == 1) {
11666 #To match standard_4 image types of micasense
11667 $plot_polygon_type_ids = [$plot_polygon_rgb_cvterm_id, $plot_polygon_green_cvterm_id, $plot_polygon_red_cvterm_id, $plot_polygon_red_threshold_cvterm_id];
11670 my @accession_ids;
11671 if ($population_id && $population_id ne 'null') {
11672 my $accession_manager = CXGN::BreedersToolbox::Accessions->new(schema=>$schema);
11673 my $population_members = $accession_manager->get_population_members($population_id);
11674 foreach (@$population_members) {
11675 push @accession_ids, $_->{stock_id};
11679 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
11680 bcs_schema=>$schema,
11681 drone_run_project_id_list=>$drone_run_ids,
11682 project_image_type_id_list=>$plot_polygon_type_ids,
11683 accession_list=>\@accession_ids
11685 my ($result, $total_count) = $images_search->search();
11687 my %data_hash;
11688 my %seen_day_times;
11689 my %seen_image_types;
11690 my %seen_drone_run_band_project_ids;
11691 my %seen_drone_run_project_ids;
11692 my %seen_field_trial_ids;
11693 my %seen_stock_ids;
11694 foreach (@$result) {
11695 my $image_id = $_->{image_id};
11696 my $stock_id = $_->{stock_id};
11697 my $field_trial_id = $_->{trial_id};
11698 my $project_image_type_id = $_->{project_image_type_id};
11699 my $drone_run_band_project_id = $_->{drone_run_band_project_id};
11700 my $drone_run_project_id = $_->{drone_run_project_id};
11701 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
11702 my $image_url = $image->get_image_url("original");
11703 my $image_fullpath = $image->get_filename('original_converted', 'full');
11704 my $time_days_cvterm = $_->{drone_run_related_time_cvterm_json}->{day};
11705 my $time_days = (split '\|', $time_days_cvterm)[0];
11706 my $days = (split ' ', $time_days)[1];
11707 $data_hash{$field_trial_id}->{$stock_id}->{$project_image_type_id}->{$days} = {
11708 image => $image_fullpath,
11709 drone_run_project_id => $drone_run_project_id
11711 $seen_day_times{$days}++;
11712 $seen_image_types{$project_image_type_id}++;
11713 $seen_drone_run_band_project_ids{$drone_run_band_project_id}++;
11714 $seen_drone_run_project_ids{$drone_run_project_id}++;
11715 $seen_field_trial_ids{$field_trial_id}++;
11716 $seen_stock_ids{$stock_id}++;
11718 print STDERR Dumper \%seen_day_times;
11719 undef $result;
11720 my @seen_plots = keys %seen_stock_ids;
11722 my $plot_of_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot_of', 'stock_relationship')->cvterm_id();
11723 my $plot_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot', 'stock_type')->cvterm_id();
11724 my $replicate_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'replicate', 'stock_property')->cvterm_id;
11725 my $block_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'block', 'stock_property')->cvterm_id();
11726 my $plot_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot number', 'stock_property')->cvterm_id();
11727 my $row_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'row_number', 'stock_property')->cvterm_id();
11728 my $col_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'col_number', 'stock_property')->cvterm_id();
11730 my $stock_ids_sql = join ',', @seen_plots;
11731 my $accession_ids_sql = '';
11732 if (scalar(@accession_ids)>0) {
11733 my $accession_ids_sql_string = join ',', @accession_ids;
11734 $accession_ids_sql = " AND germplasm.stock_id IN ($accession_ids_sql_string)";
11736 my $stock_metadata_q = "SELECT stock.stock_id, stock.uniquename, germplasm.uniquename, germplasm.stock_id, plot_number.value, rep.value, block_number.value, col_number.value, row_number.value
11737 FROM stock
11738 JOIN stock_relationship ON(stock.stock_id=stock_relationship.subject_id AND stock_relationship.type_id=$plot_of_cvterm_id)
11739 JOIN stock AS germplasm ON(stock_relationship.object_id=germplasm.stock_id)
11740 LEFT JOIN stockprop AS plot_number ON(stock.stock_id=plot_number.stock_id AND plot_number.type_id=$plot_number_cvterm_id)
11741 LEFT JOIN stockprop AS rep ON(stock.stock_id=rep.stock_id AND rep.type_id=$replicate_cvterm_id)
11742 LEFT JOIN stockprop AS block_number ON(stock.stock_id=block_number.stock_id AND block_number.type_id=$block_number_cvterm_id)
11743 LEFT JOIN stockprop AS col_number ON(stock.stock_id=col_number.stock_id AND col_number.type_id=$col_number_cvterm_id)
11744 LEFT JOIN stockprop AS row_number ON(stock.stock_id=row_number.stock_id AND row_number.type_id=$row_number_cvterm_id)
11745 WHERE stock.type_id=$plot_cvterm_id AND stock.stock_id IN ($stock_ids_sql) $accession_ids_sql";
11746 my $stock_metadata_h = $schema->storage->dbh()->prepare($stock_metadata_q);
11747 $stock_metadata_h->execute();
11748 my %stock_info;
11749 while (my ($stock_id, $stock_uniquename, $germplasm_uniquename, $germplasm_stock_id, $plot_number, $rep, $block, $col, $row) = $stock_metadata_h->fetchrow_array()) {
11750 $stock_info{$stock_id} = {
11751 uniquename => $stock_uniquename,
11752 germplasm_uniquename => $germplasm_uniquename,
11753 germplasm_stock_id => $germplasm_stock_id,
11754 plot_number => $plot_number,
11755 replicate => $rep,
11756 block_number => $block,
11757 row_number => $row,
11758 col_number => $col
11762 my $accession_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'accession', 'stock_type')->cvterm_id();
11763 my $female_parent_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'female_parent', 'stock_relationship')->cvterm_id();
11764 my $male_parent_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'male_parent', 'stock_relationship')->cvterm_id();
11766 my $plot_list_string = join ',', @seen_plots;
11767 my $q = "SELECT plot.stock_id, accession.stock_id, female_parent.stock_id, male_parent.stock_id
11768 FROM stock AS plot
11769 JOIN stock_relationship AS plot_acc_rel ON(plot_acc_rel.subject_id=plot.stock_id AND plot_acc_rel.type_id=$plot_of_cvterm_id)
11770 JOIN stock AS accession ON(plot_acc_rel.object_id=accession.stock_id AND accession.type_id=$accession_cvterm_id)
11771 JOIN stock_relationship AS female_parent_rel ON(accession.stock_id=female_parent_rel.object_id AND female_parent_rel.type_id=$female_parent_cvterm_id)
11772 JOIN stock AS female_parent ON(female_parent_rel.subject_id = female_parent.stock_id AND female_parent.type_id=$accession_cvterm_id)
11773 JOIN stock_relationship AS male_parent_rel ON(accession.stock_id=male_parent_rel.object_id AND male_parent_rel.type_id=$male_parent_cvterm_id)
11774 JOIN stock AS male_parent ON(male_parent_rel.subject_id = male_parent.stock_id AND male_parent.type_id=$accession_cvterm_id)
11775 WHERE plot.type_id=$plot_cvterm_id AND plot.stock_id IN ($plot_list_string);";
11776 my $h = $schema->storage->dbh()->prepare($q);
11777 $h->execute();
11778 my %plot_pedigrees_found = ();
11779 my %unique_accession_ids_genotypes;
11780 while (my ($plot_stock_id, $accession_stock_id, $female_parent_stock_id, $male_parent_stock_id) = $h->fetchrow_array()) {
11781 $unique_accession_ids_genotypes{$accession_stock_id}++;
11782 $plot_pedigrees_found{$plot_stock_id} = {
11783 female_stock_id => $female_parent_stock_id,
11784 male_stock_id => $male_parent_stock_id
11788 my $m = CXGN::AnalysisModel::GetModel->new({
11789 bcs_schema=>$schema,
11790 metadata_schema=>$metadata_schema,
11791 phenome_schema=>$phenome_schema,
11792 nd_protocol_id=>$model_id
11794 my $saved_model_object = $m->get_model();
11795 print STDERR Dumper $saved_model_object;
11796 my $trait_id = $saved_model_object->{model_properties}->{variable_id};
11797 my $trained_trait_name = $saved_model_object->{model_properties}->{variable_name};
11798 my $aux_trait_ids_previous = $saved_model_object->{model_properties}->{aux_trait_ids};
11799 my $model_type = $saved_model_object->{model_properties}->{model_type};
11800 my $nd_protocol_id = $saved_model_object->{model_properties}->{nd_protocol_id};
11801 my $use_parents_grm = $saved_model_object->{model_properties}->{use_parents_grm};
11802 my $trained_image_type = $saved_model_object->{model_properties}->{image_type};
11803 my $model_file = $saved_model_object->{model_files}->{trained_keras_cnn_model};
11804 my $training_autoencoder_model_file = $saved_model_object->{model_files}->{trained_keras_cnn_autoencoder_model};
11805 my $training_input_data_file = $saved_model_object->{model_files}->{trained_keras_cnn_model_input_data_file};
11806 my $training_input_aux_data_file = $saved_model_object->{model_files}->{trained_keras_cnn_model_input_aux_data_file};
11808 my $dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_dir');
11810 my %unique_genotype_accessions;
11811 if ($nd_protocol_id) {
11812 my @accession_list = sort keys %unique_accession_ids_genotypes;
11813 my $geno = CXGN::Genotype::DownloadFactory->instantiate(
11814 'DosageMatrix', #can be either 'VCF' or 'DosageMatrix'
11816 bcs_schema=>$schema,
11817 people_schema=>$people_schema,
11818 cache_root_dir=>$c->config->{cache_file_path},
11819 accession_list=>\@accession_list,
11820 protocol_id_list=>[$nd_protocol_id],
11821 compute_from_parents=>$use_parents_grm,
11822 return_only_first_genotypeprop_for_stock=>1,
11823 prevent_transpose=>1
11826 my $file_handle = $geno->download(
11827 $c->config->{cluster_shared_tempdir},
11828 $c->config->{backend},
11829 $c->config->{cluster_host},
11830 $c->config->{'web_cluster_queue'},
11831 $c->config->{basepath}
11833 open my $geno_fh, "<&", $file_handle or die "Can't open output file: $!";
11834 my $header = <$geno_fh>;
11835 while (my $row = <$geno_fh>) {
11836 chomp($row);
11837 if ($row) {
11838 my @line = split "\t", $row;
11839 my $stock_id = shift @line;
11840 my $out_line = join "\n", @line;
11841 if ($out_line) {
11842 my $geno_temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_dir/genoinputfileXXXX');
11843 my $status = write_file($geno_temp_input_file, $out_line."\n");
11844 $unique_genotype_accessions{$stock_id} = $geno_temp_input_file;
11848 close($geno_fh);
11849 @accession_ids = keys %unique_genotype_accessions;
11852 my @trait_ids = ($trait_id);
11853 if (scalar(@$aux_trait_ids) > 0) {
11854 push @trait_ids, @$aux_trait_ids;
11857 my $phenotypes_search = CXGN::Phenotypes::SearchFactory->instantiate(
11858 'MaterializedViewTable',
11860 bcs_schema=>$schema,
11861 data_level=>'plot',
11862 trait_list=>\@trait_ids,
11863 trial_list=>\@field_trial_ids,
11864 plot_list=>\@seen_plots,
11865 accession_list=>\@accession_ids,
11866 exclude_phenotype_outlier=>0,
11867 include_timestamp=>0
11870 my ($data, $unique_traits) = $phenotypes_search->search();
11872 my %phenotype_data_hash;
11873 my %aux_data_hash;
11874 foreach my $d (@$data) {
11875 foreach my $o (@{$d->{observations}}) {
11876 if ($o->{trait_id} == $trait_id) {
11877 $phenotype_data_hash{$d->{observationunit_stock_id}}->{trait_value} = {
11878 trait_name => $o->{trait_name},
11879 value => $o->{value}
11881 } else {
11882 $phenotype_data_hash{$d->{observationunit_stock_id}}->{aux_trait_value}->{$o->{trait_id}} = $o->{value};
11885 $aux_data_hash{$d->{trial_id}}->{$d->{observationunit_stock_id}} = $d;
11887 undef $data;
11889 $dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_predict_dir');
11890 my $archive_temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/inputfileXXXX');
11891 my $archive_temp_input_aux_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/inputfileXXXX');
11892 my $archive_temp_output_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/outputfileXXXX');
11893 my $archive_temp_output_evaluation_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/outputevaluationfileXXXX');
11894 my $archive_temp_output_activation_file = $c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/outputactivationfileXXXX');
11895 my $archive_temp_output_corr_plot = $c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/corrplotXXXX').".png";
11896 my $archive_temp_output_corr_plot_file = $c->config->{basepath}."/".$archive_temp_output_corr_plot;
11897 $archive_temp_output_activation_file .= ".pdf";
11898 my $archive_temp_output_activation_file_path = $c->config->{basepath}."/".$archive_temp_output_activation_file;
11900 my %predicted_stock_ids;
11901 my %output_images;
11903 open(my $F_aux, ">", $archive_temp_input_aux_file) || die "Can't open file ".$archive_temp_input_aux_file;
11904 print $F_aux 'stock_id,value,trait_name,field_trial_id,accession_id,female_id,male_id,output_image_file,genotype_file';
11905 if (scalar(@$aux_trait_ids)>0) {
11906 my $aux_trait_counter = 0;
11907 foreach (@$aux_trait_ids) {
11908 print $F_aux ",aux_trait_$aux_trait_counter";
11909 $aux_trait_counter++;
11912 print $F_aux "\n";
11914 # LSTM model uses longitudinal time information, so input ordered by field_trial, then stock_id, then by image_type, then by chronological ascending time for each drone run
11915 if ($model_type eq 'KerasCNNLSTMDenseNet121ImageNetWeights') {
11916 foreach my $field_trial_id (sort keys %seen_field_trial_ids){
11917 foreach my $stock_id (sort keys %seen_stock_ids){
11918 foreach my $image_type (sort keys %seen_image_types) {
11919 my $d = $aux_data_hash{$field_trial_id}->{$stock_id};
11920 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
11921 my $trait_name = $phenotype_data_hash{$stock_id}->{trait_value}->{trait_name};
11922 my $female_parent_stock_id = $plot_pedigrees_found{$stock_id}->{female_stock_id} || 0;
11923 my $male_parent_stock_id = $plot_pedigrees_found{$stock_id}->{male_stock_id} || 0;
11924 my $germplasm_id = $d->{germplasm_stock_id};
11925 if (defined($value)) {
11926 my $archive_temp_output_image_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/outputimagefileXXXX');
11927 $archive_temp_output_image_file .= ".png";
11928 $output_images{$stock_id} = {
11929 image_file => $archive_temp_output_image_file,
11930 field_trial_id => $field_trial_id
11932 $predicted_stock_ids{$stock_id}++;
11933 my $geno_file = $unique_genotype_accessions{$germplasm_id} || '';
11935 print $F_aux "$stock_id,";
11936 print $F_aux "$value,";
11937 print $F_aux "$trait_name,";
11938 print $F_aux "$field_trial_id,";
11939 print $F_aux "$germplasm_id,";
11940 print $F_aux "$female_parent_stock_id,";
11941 print $F_aux "$male_parent_stock_id,";
11942 print $F_aux "$archive_temp_output_image_file,";
11943 print $F_aux "$geno_file";
11944 if (scalar(@$aux_trait_ids)>0) {
11945 print $F_aux ',';
11946 my @aux_values;
11947 foreach my $aux_trait (@$aux_trait_ids) {
11948 my $aux_value = $phenotype_data_hash{$stock_id} ? $phenotype_data_hash{$stock_id}->{aux_trait_value}->{$aux_trait} : '';
11949 if (!$aux_value) {
11950 $aux_value = '';
11952 push @aux_values, $aux_value;
11954 my $aux_values_string = scalar(@aux_values)>0 ? join ',', @aux_values : '';
11955 print $F_aux $aux_values_string;
11957 print $F_aux "\n";
11963 #Non-LSTM models group image types for each stock into a single montage, so the input is ordered by field trial, then ascending chronological time, then by stock_id, and then by image_type.
11964 else {
11965 foreach my $field_trial_id (sort keys %seen_field_trial_ids){
11966 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
11967 foreach my $stock_id (sort keys %seen_stock_ids){
11968 my $d = $aux_data_hash{$field_trial_id}->{$stock_id};
11969 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
11970 my $trait_name = $phenotype_data_hash{$stock_id}->{trait_value}->{trait_name};
11971 my $female_parent_stock_id = $plot_pedigrees_found{$stock_id}->{female_stock_id} || 0;
11972 my $male_parent_stock_id = $plot_pedigrees_found{$stock_id}->{male_stock_id} || 0;
11973 my $germplasm_id = $d->{germplasm_stock_id};
11974 if (defined($value)) {
11975 my $archive_temp_output_image_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_predict_dir/outputimagefileXXXX');
11976 $archive_temp_output_image_file .= ".png";
11977 $output_images{$stock_id} = {
11978 image_file => $archive_temp_output_image_file,
11979 field_trial_id => $field_trial_id
11981 $predicted_stock_ids{$stock_id}++;
11982 my $geno_file = $unique_genotype_accessions{$germplasm_id} || '';
11984 print $F_aux "$stock_id,";
11985 print $F_aux "$value,";
11986 print $F_aux "$trait_name,";
11987 print $F_aux "$field_trial_id,";
11988 print $F_aux "$d->{germplasm_stock_id},";
11989 print $F_aux "$female_parent_stock_id,";
11990 print $F_aux "$male_parent_stock_id,";
11991 print $F_aux "$archive_temp_output_image_file,";
11992 print $F_aux "$geno_file";
11993 if (scalar(@$aux_trait_ids)>0) {
11994 print $F_aux ',';
11995 my @aux_values;
11996 foreach my $aux_trait (@$aux_trait_ids) {
11997 my $aux_value = $phenotype_data_hash{$stock_id} ? $phenotype_data_hash{$stock_id}->{aux_trait_value}->{$aux_trait} : '';
11998 if (!$aux_value) {
11999 $aux_value = '';
12001 push @aux_values, $aux_value;
12003 my $aux_values_string = scalar(@aux_values)>0 ? join ',', @aux_values : '';
12004 print $F_aux $aux_values_string;
12006 print $F_aux "\n";
12012 close($F_aux);
12014 open(my $F, ">", $archive_temp_input_file) || die "Can't open file ".$archive_temp_input_file;
12015 print $F "stock_id,image_path,image_type,day,drone_run_project_id,value\n";
12017 # LSTM model uses longitudinal time information, so input ordered by field_trial, then stock_id, then by image_type, then by chronological ascending time for each drone run
12018 if ($model_type eq 'KerasCNNLSTMDenseNet121ImageNetWeights') {
12019 foreach my $field_trial_id (sort keys %seen_field_trial_ids){
12020 foreach my $stock_id (sort keys %seen_stock_ids){
12021 foreach my $image_type (sort keys %seen_image_types) {
12022 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
12023 my $data = $data_hash{$field_trial_id}->{$stock_id}->{$image_type}->{$day_time};
12024 my $image_fullpath = $data->{image};
12025 my $drone_run_project_id = $data->{drone_run_project_id};
12026 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
12027 if (defined($value)) {
12028 print $F "$stock_id,";
12029 print $F "$image_fullpath,";
12030 print $F "$image_type,";
12031 print $F "$day_time,";
12032 print $F "$drone_run_project_id,";
12033 print $F "$value\n";
12040 #Non-LSTM models group image types for each stock into a single montage, so the input is ordered by field trial, then ascending chronological time, then by stock_id, and then by image_type.
12041 else {
12042 foreach my $field_trial_id (sort keys %seen_field_trial_ids) {
12043 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
12044 foreach my $stock_id (sort keys %seen_stock_ids){
12045 foreach my $image_type (sort keys %seen_image_types) {
12046 my $data = $data_hash{$field_trial_id}->{$stock_id}->{$image_type}->{$day_time};
12047 my $image_fullpath = $data->{image};
12048 my $drone_run_project_id = $data->{drone_run_project_id};
12049 my $value = $phenotype_data_hash{$stock_id}->{trait_value}->{value};
12050 if (defined($value)) {
12051 print $F "$stock_id,";
12052 print $F "$image_fullpath,";
12053 print $F "$image_type,";
12054 print $F "$day_time,";
12055 print $F "$drone_run_project_id,";
12056 print $F "$value\n";
12063 close($F);
12065 undef %data_hash;
12066 undef %aux_data_hash;
12068 print STDERR "Predicting $trained_trait_name from Keras CNN $model_type\n";
12070 my $log_file_path = '';
12071 if ($c->config->{error_log}) {
12072 $log_file_path = ' --log_file_path \''.$c->config->{error_log}.'\'';
12075 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/PredictKerasCNN.py --input_image_label_file \''.$archive_temp_input_file.'\' --input_image_aux_file \''.$archive_temp_input_aux_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --input_model_file_path \''.$model_file.'\' --input_autoencoder_model_file_path \''.$training_autoencoder_model_file.'\' --keras_model_type_name \''.$model_type.'\' --training_data_input_file \''.$training_input_data_file.'\' --training_aux_data_input_file \''.$training_input_aux_data_file.'\' --outfile_evaluation_path \''.$archive_temp_output_evaluation_file.'\' --outfile_activation_path \''.$archive_temp_output_activation_file_path.'\' '.$log_file_path;
12076 print STDERR Dumper $cmd;
12077 my $status = system("$cmd > /dev/null");
12079 my @saved_trained_image_urls;
12080 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_keras_trained', 'project_md_image')->cvterm_id();
12081 foreach my $stock_id (keys %output_images){
12082 my $image_file = $output_images{$stock_id}->{image_file};
12083 my $field_trial_id = $output_images{$stock_id}->{field_trial_id};
12084 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
12085 # my $md5checksum = $image->calculate_md5sum($image_file);
12086 # my $q = "SELECT md_image.image_id FROM metadata.md_image AS md_image
12087 # JOIN phenome.project_md_image AS project_md_image ON(project_md_image.image_id = md_image.image_id)
12088 # JOIN phenome.stock_image AS stock_image ON(md_image.image_id = stock_image.image_id)
12089 # WHERE md_image.obsolete = 'f' AND md_image.md5sum = ? AND project_md_image.type_id = ? AND project_md_image.project_id = ? AND stock_image.stock_id = ?;";
12090 # my $h = $schema->storage->dbh->prepare($q);
12091 # $h->execute($md5checksum, $linking_table_type_id, $field_trial_id, $stock_id);
12092 # my ($saved_image_id) = $h->fetchrow_array();
12094 my $output_image_id;
12095 my $output_image_url;
12096 my $output_image_fullpath;
12097 # if ($saved_image_id) {
12098 # print STDERR Dumper "Image $image_file has already been added to the database and will not be added again.";
12099 # $image = SGN::Image->new( $schema->storage->dbh, $saved_image_id, $c );
12100 # $output_image_fullpath = $image->get_filename('original_converted', 'full');
12101 # $output_image_url = $image->get_image_url('original');
12102 # $output_image_id = $image->get_image_id();
12103 # } else {
12104 $image->set_sp_person_id($user_id);
12105 my $ret = $image->process_image($image_file, 'project', $field_trial_id, $linking_table_type_id);
12106 my $stock_associate = $image->associate_stock($stock_id, $user_name);
12107 $output_image_fullpath = $image->get_filename('original_converted', 'full');
12108 $output_image_url = $image->get_image_url('original');
12109 $output_image_id = $image->get_image_id();
12111 $output_images{$stock_id}->{image_id} = $output_image_id;
12112 push @saved_trained_image_urls, $output_image_url;
12115 my @result_agg;
12116 my @data_matrix;
12117 my $data_matrix_rows = 0;
12118 my @data_matrix_colnames = ('stock_id', 'germplasm_stock_id', 'replicate', 'block_number', 'row_number', 'col_number', 'growing_degree_days', 'previous_value', 'prediction');
12119 my @simple_data_matrix;
12121 my @predictions;
12122 my $csv = Text::CSV->new({ sep_char => ',' });
12123 open(my $fh, '<', $archive_temp_output_file)
12124 or die "Could not open file '$archive_temp_output_file' $!";
12126 print STDERR "Opened $archive_temp_output_file\n";
12127 while ( my $row = <$fh> ){
12128 my @columns;
12129 if ($csv->parse($row)) {
12130 @columns = $csv->fields();
12132 my $prediction = shift @columns;
12133 push @predictions, $prediction;
12135 close($fh);
12136 #print STDERR Dumper \@predictions;
12138 my $time = DateTime->now();
12139 my $timestamp = $time->ymd()."_".$time->hms();
12141 my $keras_predict_image_type_id;
12142 my $keras_predict_model_type_id;
12143 if ($trained_image_type eq 'standard_4_montage') {
12144 $keras_predict_image_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Standard 4 Image Montage|ISOL:0000324')->cvterm_id;
12146 if ($model_type eq 'KerasTunerCNNSequentialSoftmaxCategorical') {
12147 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasTunerCNNSequentialSoftmaxCategorical|ISOL:0000326')->cvterm_id;
12149 if ($model_type eq 'SimpleKerasTunerCNNSequentialSoftmaxCategorical') {
12150 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted SimpleKerasTunerCNNSequentialSoftmaxCategorical|ISOL:0000327')->cvterm_id;
12152 if ($model_type eq 'KerasCNNInceptionResNetV2ImageNetWeights') {
12153 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasCNNInceptionResNetV2ImageNetWeights|ISOL:0000328')->cvterm_id;
12155 if ($model_type eq 'KerasCNNInceptionResNetV2') {
12156 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasCNNInceptionResNetV2|ISOL:0000329')->cvterm_id;
12158 if ($model_type eq 'KerasCNNLSTMDenseNet121ImageNetWeights') {
12159 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasCNNLSTMDenseNet121ImageNetWeights|ISOL:0000330')->cvterm_id;
12161 if ($model_type eq 'KerasCNNDenseNet121ImageNetWeights') {
12162 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasCNNDenseNet121ImageNetWeights|ISOL:0000331')->cvterm_id;
12164 if ($model_type eq 'KerasCNNSequentialSoftmaxCategorical') {
12165 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasCNNSequentialSoftmaxCategorical|ISOL:0000332')->cvterm_id;
12167 if ($model_type eq 'KerasCNNMLPExample') {
12168 $keras_predict_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Predicted KerasCNNMLPExample|ISOL:0000333')->cvterm_id;
12171 my $trained_trait_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, $trained_trait_name)->cvterm_id;
12173 my $traits = SGN::Model::Cvterm->get_traits_from_component_categories($schema, $allowed_composed_cvs, $composable_cvterm_delimiter, $composable_cvterm_format, {
12174 object => [],
12175 attribute => [$keras_predict_image_type_id],
12176 method => [],
12177 unit => [],
12178 trait => [$trained_trait_cvterm_id],
12179 tod => [$keras_predict_model_type_id],
12180 toy => [],
12181 gen => [],
12183 my $existing_traits = $traits->{existing_traits};
12184 my $new_traits = $traits->{new_traits};
12185 # print STDERR Dumper $new_traits;
12186 # print STDERR Dumper $existing_traits;
12187 my %new_trait_names;
12188 foreach (@$new_traits) {
12189 my $components = $_->[0];
12190 $new_trait_names{$_->[1]} = join ',', @$components;
12193 my $onto = CXGN::Onto->new( { schema => $schema } );
12194 my $new_terms = $onto->store_composed_term(\%new_trait_names);
12196 my $keras_predict_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$trained_trait_cvterm_id, $keras_predict_image_type_id, $keras_predict_model_type_id]);
12197 my $keras_predict_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $keras_predict_composed_cvterm_id, 'extended');
12199 my %keras_features_phenotype_data;
12200 my $iter = 0;
12201 my %seen_stock_names;
12202 #print STDERR Dumper \%phenotype_data_hash;
12203 foreach my $sorted_stock_id (sort keys %predicted_stock_ids) {
12204 my $prediction = $predictions[$iter];
12205 my $stock_uniquename = $stock_info{$sorted_stock_id}->{uniquename};
12206 my $previous_value = $phenotype_data_hash{$sorted_stock_id} ? $phenotype_data_hash{$sorted_stock_id}->{trait_value}->{value} : '';
12207 my $image_id = $output_images{$sorted_stock_id}->{image_id};
12209 $keras_features_phenotype_data{$stock_uniquename}->{$keras_predict_composed_trait_name} = [$prediction, $timestamp, $user_name, '', $image_id];
12210 $seen_stock_names{$stock_uniquename}++;
12212 if ($previous_value){
12213 push @data_matrix, ($sorted_stock_id, $stock_info{$sorted_stock_id}->{germplasm_stock_id}, $stock_info{$sorted_stock_id}->{replicate}, $stock_info{$sorted_stock_id}->{block_number}, $stock_info{$sorted_stock_id}->{row_number}, $stock_info{$sorted_stock_id}->{col_number}, $stock_info{$sorted_stock_id}->{drone_run_related_time_cvterm_json}->{gdd_average_temp}, $previous_value, $prediction);
12214 push @simple_data_matrix, ($previous_value, $prediction);
12215 $data_matrix_rows++;
12217 push @result_agg, [$stock_uniquename, $sorted_stock_id, $prediction, $previous_value];
12218 $iter++;
12221 my @traits_seen = (
12222 $keras_predict_composed_trait_name
12225 print STDERR "Read $iter lines in results file\n";
12227 if ($iter > 0) {
12228 my %phenotype_metadata = (
12229 'archived_file' => $archive_temp_output_file,
12230 'archived_file_type' => 'image_keras_prediction_output',
12231 'operator' => $user_name,
12232 'date' => $timestamp
12234 my @plot_units_seen = keys %seen_stock_names;
12236 my $store_phenotypes = CXGN::Phenotypes::StorePhenotypes->new({
12237 basepath=>$c->config->{basepath},
12238 dbhost=>$c->config->{dbhost},
12239 dbname=>$c->config->{dbname},
12240 dbuser=>$c->config->{dbuser},
12241 dbpass=>$c->config->{dbpass},
12242 bcs_schema=>$schema,
12243 metadata_schema=>$metadata_schema,
12244 phenome_schema=>$phenome_schema,
12245 user_id=>$user_id,
12246 stock_list=>\@plot_units_seen,
12247 trait_list=>\@traits_seen,
12248 values_hash=>\%keras_features_phenotype_data,
12249 has_timestamps=>1,
12250 metadata_hash=>\%phenotype_metadata,
12251 ignore_new_values=>undef,
12252 overwrite_values=>1,
12253 composable_validation_check_name=>$c->config->{composable_validation_check_name},
12254 allow_repeat_measures=>$c->config->{allow_repeat_measures}
12256 my ($verified_warning, $verified_error) = $store_phenotypes->verify();
12257 my ($stored_phenotype_error, $stored_phenotype_success) = $store_phenotypes->store();
12259 my $bs = CXGN::BreederSearch->new( { dbh=>$c->dbc->dbh, dbname=>$c->config->{dbname}, } );
12260 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'fullview', 'nonconcurrent', $c->config->{basepath});
12263 undef %data_hash;
12264 undef %phenotype_data_hash;
12266 print STDERR "CNN Prediction Correlation\n";
12267 my @model_results;
12268 my @simple_data_matrix_colnames = ("previous_value", "prediction");
12269 print STDERR Dumper \@simple_data_matrix;
12270 my $rmatrix = R::YapRI::Data::Matrix->new({
12271 name => 'matrix1',
12272 coln => scalar(@simple_data_matrix_colnames),
12273 rown => $data_matrix_rows,
12274 colnames => \@simple_data_matrix_colnames,
12275 data => \@simple_data_matrix
12278 print STDERR "CORR PLOT $archive_temp_output_corr_plot_file \n";
12279 my $rbase = R::YapRI::Base->new();
12280 my $r_block = $rbase->create_block('r_block');
12281 $rmatrix->send_rbase($rbase, 'r_block');
12282 $r_block->add_command('dataframe.matrix1 <- data.frame(matrix1)');
12283 $r_block->add_command('dataframe.matrix1$previous_value <- as.numeric(dataframe.matrix1$previous_value)');
12284 $r_block->add_command('dataframe.matrix1$prediction <- as.numeric(dataframe.matrix1$prediction)');
12285 $r_block->add_command('mixed.lmer.matrix <- matrix(NA,nrow = 1, ncol = 1)');
12286 $r_block->add_command('mixed.lmer.matrix[1,1] <- cor(dataframe.matrix1$previous_value, dataframe.matrix1$prediction)');
12288 $r_block->add_command('png(filename=\''.$archive_temp_output_corr_plot_file.'\')');
12289 $r_block->add_command('plot(dataframe.matrix1$previous_value, dataframe.matrix1$prediction)');
12290 $r_block->add_command('dev.off()');
12291 $r_block->run_block();
12292 my $result_matrix = R::YapRI::Data::Matrix->read_rbase($rbase,'r_block','mixed.lmer.matrix');
12293 print STDERR Dumper $result_matrix;
12294 push @model_results, $result_matrix->{data}->[0];
12296 my @data_matrix_clean;
12297 foreach (@data_matrix) {
12298 if ($_) {
12299 push @data_matrix_clean, $_ + 0;
12301 else {
12302 push @data_matrix_clean, 'NA';
12305 #print STDERR Dumper \@data_matrix_clean;
12307 if ($model_prediction_type eq 'cnn_prediction_mixed_model') {
12308 print STDERR "CNN Prediction Mixed Model\n";
12310 my $rmatrix = R::YapRI::Data::Matrix->new({
12311 name => 'matrix1',
12312 coln => scalar(@data_matrix_colnames),
12313 rown => $data_matrix_rows,
12314 colnames => \@data_matrix_colnames,
12315 data => \@data_matrix_clean
12318 my $rbase = R::YapRI::Base->new();
12319 my $r_block = $rbase->create_block('r_block');
12320 $rmatrix->send_rbase($rbase, 'r_block');
12321 $r_block->add_command('library(lme4)');
12322 $r_block->add_command('dataframe.matrix1 <- data.frame(matrix1)');
12323 $r_block->add_command('dataframe.matrix1$previous_value <- as.numeric(dataframe.matrix1$previous_value)');
12324 $r_block->add_command('dataframe.matrix1$prediction <- as.numeric(dataframe.matrix1$prediction)');
12325 $r_block->add_command('mixed.lmer <- lmer(previous_value ~ prediction + replicate + (1|germplasm_stock_id), data = dataframe.matrix1, na.action = na.omit )');
12326 # $r_block->add_command('mixed.lmer.summary <- summary(mixed.lmer)');
12327 $r_block->add_command('mixed.lmer.matrix <- matrix(NA,nrow = 1, ncol = 2)');
12328 $r_block->add_command('mixed.lmer.matrix[1,1] <- cor(predict(mixed.lmer), dataframe.matrix1$previous_value)');
12330 $r_block->add_command('mixed.lmer <- lmer(prediction ~ replicate + (1|germplasm_stock_id), data = dataframe.matrix1 )');
12331 # $r_block->add_command('mixed.lmer.summary <- summary(mixed.lmer)');
12332 $r_block->add_command('mixed.lmer.matrix[1,2] <- cor(predict(mixed.lmer), dataframe.matrix1$previous_value)');
12333 $r_block->run_block();
12334 my $result_matrix = R::YapRI::Data::Matrix->read_rbase($rbase,'r_block','mixed.lmer.matrix');
12335 print STDERR Dumper $result_matrix;
12336 push @model_results, $result_matrix->{data}->[0];
12337 push @model_results, $result_matrix->{data}->[1];
12340 my @evaluation_results;
12341 open(my $fh_eval, '<', $archive_temp_output_evaluation_file)
12342 or die "Could not open file '$archive_temp_output_evaluation_file' $!";
12344 while ( my $row = <$fh_eval> ){
12345 my @columns;
12346 if ($csv->parse($row)) {
12347 @columns = $csv->fields();
12349 my $line = '';
12350 foreach (@columns) {
12351 if ($_ eq ' ') {
12352 $line .= '&nbsp;';
12354 else {
12355 $line .= $_;
12358 push @evaluation_results, $line;
12360 close($fh_eval);
12362 return { success => 1, results => \@result_agg, evaluation_results => \@evaluation_results, activation_output => $archive_temp_output_activation_file, corr_plot => $archive_temp_output_corr_plot, trained_trait_name => $trained_trait_name, mixed_model_results => \@model_results };
12365 sub drone_imagery_autoencoder_keras_vi_model : Path('/api/drone_imagery/perform_autoencoder_vi') : ActionClass('REST') { }
12366 sub drone_imagery_autoencoder_keras_vi_model_POST : Args(0) {
12367 my $self = shift;
12368 my $c = shift;
12369 print STDERR Dumper $c->req->params();
12370 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
12371 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
12372 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
12373 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
12374 my $people_schema = $c->dbic_schema("CXGN::People::Schema", undef, $sp_person_id);
12375 my @training_field_trial_ids = split ',', $c->req->param('training_field_trial_ids');
12376 my @field_trial_ids = split ',', $c->req->param('field_trial_ids');
12377 my $autoencoder_model_type = $c->req->param('autoencoder_model_type');
12378 my $time_cvterm_id = $c->req->param('time_cvterm_id');
12379 my $training_drone_run_ids = decode_json($c->req->param('training_drone_run_ids'));
12380 my $drone_run_ids = decode_json($c->req->param('drone_run_ids'));
12381 my $training_plot_polygon_type_ids = decode_json($c->req->param('training_plot_polygon_type_ids'));
12382 my $plot_polygon_type_ids = decode_json($c->req->param('plot_polygon_type_ids'));
12383 my ($user_id, $user_name, $user_role) = _check_user_login($c);
12385 if (scalar(@$drone_run_ids) > 1) {
12386 $c->stash->{rest} = {error => "Please select only one drone run to predict on!"};
12387 $c->detach();
12390 my @allowed_composed_cvs = split ',', $c->config->{composable_cvs};
12391 my $composable_cvterm_delimiter = $c->config->{composable_cvterm_delimiter};
12392 my $composable_cvterm_format = $c->config->{composable_cvterm_format};
12394 my $return = _perform_autoencoder_keras_cnn_vi($c, $schema, $metadata_schema, $people_schema, $phenome_schema, \@training_field_trial_ids, \@field_trial_ids, $training_drone_run_ids, $drone_run_ids, $training_plot_polygon_type_ids, $plot_polygon_type_ids, $autoencoder_model_type, \@allowed_composed_cvs, $composable_cvterm_format, $composable_cvterm_delimiter, $time_cvterm_id, $user_id, $user_name, $user_role);
12396 $c->stash->{rest} = $return;
12399 sub _perform_autoencoder_keras_cnn_vi {
12400 my $c = shift;
12401 my $schema = shift;
12402 my $metadata_schema = shift;
12403 my $people_schema = shift;
12404 my $phenome_schema = shift;
12405 my $training_field_trial_ids = shift;
12406 my $field_trial_ids = shift;
12407 my $training_drone_run_ids = shift;
12408 my $drone_run_ids = shift;
12409 my $training_plot_polygon_type_ids = shift;
12410 my $plot_polygon_type_ids = shift;
12411 my $autoencoder_model_type = shift;
12412 my $allowed_composed_cvs = shift;
12413 my $composable_cvterm_format = shift;
12414 my $composable_cvterm_delimiter = shift;
12415 my $time_cvterm_id = shift;
12416 my $user_id = shift;
12417 my $user_name = shift;
12418 my $user_role = shift;
12419 my @field_trial_ids = @$field_trial_ids;
12421 my $keras_cnn_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'trained_keras_cnn_model', 'protocol_type')->cvterm_id();
12422 my $keras_cnn_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_experiment', 'experiment_type')->cvterm_id();
12424 my $training_images_search = CXGN::DroneImagery::ImagesSearch->new({
12425 bcs_schema=>$schema,
12426 drone_run_project_id_list=>$training_drone_run_ids,
12427 project_image_type_id_list=>$training_plot_polygon_type_ids
12429 my ($training_result, $training_total_count) = $training_images_search->search();
12431 if ($training_total_count == 0) {
12432 return {error => "No plot-polygon images for training!"};
12435 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
12436 bcs_schema=>$schema,
12437 drone_run_project_id_list=>$drone_run_ids,
12438 project_image_type_id_list=>$plot_polygon_type_ids
12440 my ($result, $total_count) = $images_search->search();
12442 if ($total_count == 0) {
12443 return {error => "No plot-polygon images for predicting!"};
12446 my %training_data_hash;
12447 my %training_seen_day_times;
12448 my %training_seen_image_types;
12449 my %training_seen_drone_run_band_project_ids;
12450 my %training_seen_drone_run_project_ids;
12451 my %training_seen_field_trial_ids;
12452 my %training_seen_stock_ids;
12453 foreach (@$training_result) {
12454 my $image_id = $_->{image_id};
12455 my $stock_id = $_->{stock_id};
12456 my $field_trial_id = $_->{trial_id};
12457 my $project_image_type_id = $_->{project_image_type_id};
12458 my $drone_run_band_project_id = $_->{drone_run_band_project_id};
12459 my $drone_run_project_id = $_->{drone_run_project_id};
12460 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
12461 my $image_url = $image->get_image_url("original");
12462 my $image_fullpath = $image->get_filename('original_converted', 'full');
12463 my $time_days_cvterm = $_->{drone_run_related_time_cvterm_json}->{day};
12464 my $time_days = (split '\|', $time_days_cvterm)[0];
12465 my $days = (split ' ', $time_days)[1];
12466 push @{$training_data_hash{$field_trial_id}->{$drone_run_project_id}->{$stock_id}->{$project_image_type_id}->{$days}}, {
12467 image => $image_fullpath,
12468 drone_run_project_id => $drone_run_project_id
12470 $training_seen_day_times{$days}++;
12471 $training_seen_image_types{$project_image_type_id}++;
12472 $training_seen_drone_run_band_project_ids{$drone_run_band_project_id}++;
12473 $training_seen_drone_run_project_ids{$drone_run_project_id}++;
12474 $training_seen_field_trial_ids{$field_trial_id}++;
12475 $training_seen_stock_ids{$stock_id}++;
12477 print STDERR Dumper \%training_seen_day_times;
12478 undef $training_result;
12479 my @training_seen_plots = keys %training_seen_stock_ids;
12481 my %data_hash;
12482 my %seen_day_times;
12483 my %seen_image_types;
12484 my %seen_drone_run_band_project_ids;
12485 my %seen_drone_run_project_ids;
12486 my %seen_field_trial_ids;
12487 my %seen_stock_ids;
12488 foreach (@$result) {
12489 my $image_id = $_->{image_id};
12490 my $stock_id = $_->{stock_id};
12491 my $field_trial_id = $_->{trial_id};
12492 my $project_image_type_id = $_->{project_image_type_id};
12493 my $drone_run_band_project_id = $_->{drone_run_band_project_id};
12494 my $drone_run_project_id = $_->{drone_run_project_id};
12495 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
12496 my $image_url = $image->get_image_url("original");
12497 my $image_fullpath = $image->get_filename('original_converted', 'full');
12498 my $time_days_cvterm = $_->{drone_run_related_time_cvterm_json}->{day};
12499 my $time_days = (split '\|', $time_days_cvterm)[0];
12500 my $days = (split ' ', $time_days)[1];
12501 push @{$data_hash{$field_trial_id}->{$drone_run_project_id}->{$stock_id}->{$project_image_type_id}->{$days}}, {
12502 image => $image_fullpath,
12503 drone_run_project_id => $drone_run_project_id
12505 $seen_day_times{$days}++;
12506 $seen_image_types{$project_image_type_id}++;
12507 $seen_drone_run_band_project_ids{$drone_run_band_project_id}++;
12508 $seen_drone_run_project_ids{$drone_run_project_id}++;
12509 $seen_field_trial_ids{$field_trial_id}++;
12510 $seen_stock_ids{$stock_id}++;
12512 print STDERR Dumper \%seen_day_times;
12513 undef $result;
12514 my @seen_plots = keys %seen_stock_ids;
12516 my $plot_of_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot_of', 'stock_relationship')->cvterm_id();
12517 my $plot_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot', 'stock_type')->cvterm_id();
12518 my $replicate_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'replicate', 'stock_property')->cvterm_id;
12519 my $block_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'block', 'stock_property')->cvterm_id();
12520 my $plot_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot number', 'stock_property')->cvterm_id();
12521 my $row_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'row_number', 'stock_property')->cvterm_id();
12522 my $col_number_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'col_number', 'stock_property')->cvterm_id();
12524 my $stock_ids_sql = join ',', @seen_plots;
12525 my %seen_accession_names;
12526 my $stock_metadata_q = "SELECT stock.stock_id, stock.uniquename, germplasm.uniquename, germplasm.stock_id, plot_number.value, rep.value, block_number.value, col_number.value, row_number.value
12527 FROM stock
12528 JOIN stock_relationship ON(stock.stock_id=stock_relationship.subject_id AND stock_relationship.type_id=$plot_of_cvterm_id)
12529 JOIN stock AS germplasm ON(stock_relationship.object_id=germplasm.stock_id)
12530 LEFT JOIN stockprop AS plot_number ON(stock.stock_id=plot_number.stock_id AND plot_number.type_id=$plot_number_cvterm_id)
12531 LEFT JOIN stockprop AS rep ON(stock.stock_id=rep.stock_id AND rep.type_id=$replicate_cvterm_id)
12532 LEFT JOIN stockprop AS block_number ON(stock.stock_id=block_number.stock_id AND block_number.type_id=$block_number_cvterm_id)
12533 LEFT JOIN stockprop AS col_number ON(stock.stock_id=col_number.stock_id AND col_number.type_id=$col_number_cvterm_id)
12534 LEFT JOIN stockprop AS row_number ON(stock.stock_id=row_number.stock_id AND row_number.type_id=$row_number_cvterm_id)
12535 WHERE stock.type_id=$plot_cvterm_id AND stock.stock_id IN ($stock_ids_sql) ";
12536 my $stock_metadata_h = $schema->storage->dbh()->prepare($stock_metadata_q);
12537 $stock_metadata_h->execute();
12538 my %stock_info;
12539 while (my ($stock_id, $stock_uniquename, $germplasm_uniquename, $germplasm_stock_id, $plot_number, $rep, $block, $col, $row) = $stock_metadata_h->fetchrow_array()) {
12540 $stock_info{$stock_id} = {
12541 stock_uniquename => $stock_uniquename,
12542 germplasm_uniquename => $germplasm_uniquename,
12543 germplasm_stock_id => $germplasm_stock_id,
12544 plot_number => $plot_number,
12545 replicate => $rep,
12546 block_number => $block,
12547 row_number => $row,
12548 col_number => $col
12550 $seen_accession_names{$germplasm_uniquename}++;
12552 my @unique_accession_names = keys %seen_accession_names;
12554 my $dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_autoencoder_dir');
12555 my $archive_training_temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_autoencoder_dir/inputtrainingfileXXXX');
12556 my $archive_temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_autoencoder_dir/inputfileXXXX');
12557 my $archive_temp_output_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_autoencoder_dir/outputfileXXXX');
12558 my $archive_temp_output_images_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_autoencoder_dir/outputfileXXXX');
12560 my %predicted_stock_ids;
12561 my %output_images;
12563 my @autoencoder_vi_image_type_ids = (
12564 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_red_imagery', 'project_md_image')->cvterm_id(),
12565 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_red_edge_imagery', 'project_md_image')->cvterm_id(),
12566 SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_nir_imagery', 'project_md_image')->cvterm_id()
12569 open(my $Fi, ">", $archive_training_temp_input_file) || die "Can't open file ".$archive_training_temp_input_file;
12570 print $Fi "stock_id\tred_image_string\tred_edge_image_string\tnir_image_string\n";
12572 foreach my $field_trial_id (sort keys %training_seen_field_trial_ids) {
12573 foreach my $drone_run_project_id (sort keys %training_seen_drone_run_project_ids) {
12574 foreach my $stock_id (sort keys %training_seen_stock_ids) {
12575 print $Fi "$stock_id";
12576 foreach my $image_type (@autoencoder_vi_image_type_ids) {
12577 my @imgs;
12578 foreach my $day_time (sort { $a <=> $b } keys %training_seen_day_times) {
12579 my $images = $training_data_hash{$field_trial_id}->{$drone_run_project_id}->{$stock_id}->{$image_type}->{$day_time};
12580 foreach (@$images) {
12581 push @imgs, $_->{image};
12584 my $img_string = join ',', @imgs;
12585 print $Fi "\t$img_string";
12587 print $Fi "\n";
12591 close($Fi);
12593 open(my $F, ">", $archive_temp_input_file) || die "Can't open file ".$archive_temp_input_file;
12594 print $F "stock_id\tred_image_string\tred_edge_image_string\tnir_image_string\n";
12596 foreach my $field_trial_id (sort keys %seen_field_trial_ids) {
12597 foreach my $drone_run_project_id (sort keys %seen_drone_run_project_ids) {
12598 foreach my $stock_id (sort keys %seen_stock_ids) {
12599 print $F "$stock_id";
12600 foreach my $image_type (@autoencoder_vi_image_type_ids) {
12601 my @imgs;
12602 foreach my $day_time (sort { $a <=> $b } keys %seen_day_times) {
12603 my $images = $data_hash{$field_trial_id}->{$drone_run_project_id}->{$stock_id}->{$image_type}->{$day_time};
12604 foreach (@$images) {
12605 push @imgs, $_->{image};
12608 my $img_string = join ',', @imgs;
12609 print $F "\t$img_string";
12611 print $F "\n";
12615 close($F);
12617 open(my $F2, ">", $archive_temp_output_images_file) || die "Can't open file ".$archive_temp_output_images_file;
12618 print $F2 "stock_id\tred_image_encoded\tred_edge_image_encoded\tnir_image_encoded\n";
12620 foreach my $field_trial_id (sort keys %seen_field_trial_ids) {
12621 foreach my $stock_id (sort keys %seen_stock_ids) {
12622 my $archive_temp_output_ndvi_image_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_autoencoder_dir/outputimagefileXXXX');
12623 $archive_temp_output_ndvi_image_file .= ".png";
12624 my $archive_temp_output_ndre_image_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_autoencoder_dir/outputimagefileXXXX');
12625 $archive_temp_output_ndre_image_file .= ".png";
12627 my @autoencoded_image_files = ($archive_temp_output_ndvi_image_file, $archive_temp_output_ndre_image_file);
12628 $output_images{$stock_id} = \@autoencoded_image_files;
12629 my $img_string = join "\t", @autoencoded_image_files;
12630 print $F2 "$stock_id\t$img_string\n";
12633 close($F2);
12635 undef %data_hash;
12637 my $log_file_path = '';
12638 if ($c->config->{error_log}) {
12639 $log_file_path = ' --log_file_path \''.$c->config->{error_log}.'\'';
12642 my $cmd = $c->config->{python_executable}.' '.$c->config->{rootpath}.'/DroneImageScripts/ImageProcess/CalculatePhenotypeAutoEncoderVegetationIndices.py --input_training_image_file \''.$archive_training_temp_input_file.'\' --input_image_file \''.$archive_temp_input_file.'\' --output_encoded_images_file \''.$archive_temp_output_images_file.'\' --outfile_path \''.$archive_temp_output_file.'\' --autoencoder_model_type \''.$autoencoder_model_type.'\' '.$log_file_path;
12643 print STDERR Dumper $cmd;
12644 my $status = system("$cmd > /dev/null");
12646 my @saved_trained_image_urls;
12647 my %output_image_ids;
12648 my $linking_table_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'observation_unit_polygon_keras_autoencoder_decoded', 'project_md_image')->cvterm_id();
12649 foreach my $stock_id (keys %output_images) {
12650 my $autoencoded_images = $output_images{$stock_id};
12651 foreach my $image_file (@$autoencoded_images) {
12652 my $image = SGN::Image->new( $schema->storage->dbh, undef, $c );
12653 $image->set_sp_person_id($user_id);
12654 my $ret = $image->process_image($image_file, 'project', $drone_run_ids->[0], $linking_table_type_id);
12655 my $stock_associate = $image->associate_stock($stock_id, $user_name);
12656 my $output_image_fullpath = $image->get_filename('original_converted', 'full');
12657 my $output_image_url = $image->get_image_url('original');
12658 my $output_image_id = $image->get_image_id();
12659 push @saved_trained_image_urls, $output_image_url;
12660 push @{$output_image_ids{$stock_id}}, $output_image_id;
12664 my $ndvi_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'NDVI Vegetative Index Image|ISOL:0000131')->cvterm_id;
12665 my $ndre_cvterm_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'NDRE Vegetative Index Image|ISOL:0000132')->cvterm_id;
12667 my $keras_autoencoder_model_type_id;
12668 if ($autoencoder_model_type eq 'keras_autoencoder_64_32_filters_16_latent') {
12669 $keras_autoencoder_model_type_id = SGN::Model::Cvterm->get_cvterm_row_from_trait_name($schema, 'Keras Autoencoder 64_32_Conv_16_Latent|ISOL:0000336')->cvterm_id;
12672 my $traits = SGN::Model::Cvterm->get_traits_from_component_categories($schema, $allowed_composed_cvs, $composable_cvterm_delimiter, $composable_cvterm_format, {
12673 object => [],
12674 attribute => [],
12675 method => [],
12676 unit => [],
12677 trait => [$ndvi_cvterm_id, $ndre_cvterm_id],
12678 tod => [$keras_autoencoder_model_type_id],
12679 toy => [$time_cvterm_id],
12680 gen => [],
12682 my $existing_traits = $traits->{existing_traits};
12683 my $new_traits = $traits->{new_traits};
12684 #print STDERR Dumper $new_traits;
12685 #print STDERR Dumper $existing_traits;
12686 my %new_trait_names;
12687 foreach (@$new_traits) {
12688 my $components = $_->[0];
12689 $new_trait_names{$_->[1]} = join ',', @$components;
12692 my $onto = CXGN::Onto->new( { schema => $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id) } );
12693 my $new_terms = $onto->store_composed_term(\%new_trait_names);
12695 my $autoencoder_ndvi_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$ndvi_cvterm_id, $keras_autoencoder_model_type_id, $time_cvterm_id]);
12696 my $autoencoder_ndre_composed_cvterm_id = SGN::Model::Cvterm->get_trait_from_exact_components($schema, [$ndre_cvterm_id, $keras_autoencoder_model_type_id, $time_cvterm_id]);
12698 my $autoencoder_ndvi_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $autoencoder_ndvi_composed_cvterm_id, 'extended');
12699 my $autoencoder_ndre_composed_trait_name = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $autoencoder_ndre_composed_cvterm_id, 'extended');
12701 my $time = DateTime->now();
12702 my $timestamp = $time->ymd()."_".$time->hms();
12704 my $csv = Text::CSV->new({ sep_char => ',' });
12705 open(my $fh, '<', $archive_temp_output_file)
12706 or die "Could not open file '$archive_temp_output_file' $!";
12708 print STDERR "Opened $archive_temp_output_file\n";
12709 my $line = 0;
12710 my %autoencoder_vi_phenotype_data;
12711 my %plots_seen;
12713 my @traits_seen = (
12714 $autoencoder_ndvi_composed_trait_name,
12715 $autoencoder_ndre_composed_trait_name
12718 my $header = <$fh>;
12719 while ( my $row = <$fh> ){
12720 my @columns;
12721 if ($csv->parse($row)) {
12722 @columns = $csv->fields();
12725 my $stock_id = $columns[0];
12726 my $stock_uniquename = $stock_info{$stock_id}->{stock_uniquename};
12727 my $output_images = $output_image_ids{$stock_id};
12729 #print STDERR Dumper \@columns;
12730 $stock_info{$stock_id}->{result} = \@columns;
12732 $plots_seen{$stock_uniquename} = 1;
12733 $autoencoder_vi_phenotype_data{$stock_uniquename}->{$autoencoder_ndvi_composed_trait_name} = [$columns[1], $timestamp, $user_name, '', $output_images->[0]];
12734 $autoencoder_vi_phenotype_data{$stock_uniquename}->{$autoencoder_ndre_composed_trait_name} = [$columns[2], $timestamp, $user_name, '', $output_images->[1]];
12736 $line++;
12738 my @stocks = values %stock_info;
12740 close($fh);
12741 print STDERR "Read $line lines in results file\n";
12742 # print STDERR Dumper \%autoencoder_vi_phenotype_data;
12744 if ($line > 0) {
12745 my %phenotype_metadata = (
12746 'archived_file' => $archive_temp_output_file,
12747 'archived_file_type' => 'keras_autoencoder_vegetation_indices',
12748 'operator' => $user_name,
12749 'date' => $timestamp
12751 my @plot_units_seen = keys %plots_seen;
12753 my $store_args = {
12754 basepath=>$c->config->{basepath},
12755 dbhost=>$c->config->{dbhost},
12756 dbname=>$c->config->{dbname},
12757 dbuser=>$c->config->{dbuser},
12758 dbpass=>$c->config->{dbpass},
12759 bcs_schema=>$schema,
12760 metadata_schema=>$metadata_schema,
12761 phenome_schema=>$phenome_schema,
12762 user_id=>$user_id,
12763 stock_list=>\@plot_units_seen,
12764 trait_list=>\@traits_seen,
12765 values_hash=>\%autoencoder_vi_phenotype_data,
12766 has_timestamps=>1,
12767 metadata_hash=>\%phenotype_metadata,
12768 overwrite_values=>1,
12769 #ignore_new_values=>1,
12770 composable_validation_check_name=>$c->config->{composable_validation_check_name},
12771 allow_repeat_measures=>$c->config->{allow_repeat_measures}
12774 my $store_phenotypes = CXGN::Phenotypes::StorePhenotypes->new(
12775 $store_args
12777 my ($verified_warning, $verified_error) = $store_phenotypes->verify();
12778 my ($stored_phenotype_error, $stored_phenotype_success) = $store_phenotypes->store();
12780 my $bs = CXGN::BreederSearch->new( { dbh=>$c->dbc->dbh, dbname=>$c->config->{dbname}, } );
12781 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'fullview', 'nonconcurrent', $c->config->{basepath});
12784 return { success => 1 };
12787 sub drone_imagery_delete_drone_run : Path('/api/drone_imagery/delete_drone_run') : ActionClass('REST') { }
12788 sub drone_imagery_delete_drone_run_GET : Args(0) {
12789 my $self = shift;
12790 my $c = shift;
12791 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
12792 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
12793 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
12794 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
12795 my $drone_run_project_id = $c->req->param('drone_run_project_id');
12796 my ($user_id, $user_name, $user_role) = _check_user_login($c, 'curator');
12797 print STDERR "DELETING DRONE RUN\n";
12799 my $images_search = CXGN::DroneImagery::ImagesSearch->new({
12800 bcs_schema=>$schema,
12801 drone_run_project_id_list=>[$drone_run_project_id],
12803 my ($result, $total_count) = $images_search->search();
12804 print STDERR Dumper $total_count;
12806 my %drone_run_band_project_ids;
12807 my %image_ids;
12808 foreach (@$result) {
12809 $drone_run_band_project_ids{$_->{drone_run_band_project_id}}++;
12810 $image_ids{$_->{image_id}}++;
12812 my @drone_run_band_ids = keys %drone_run_band_project_ids;
12813 my @drone_run_image_ids = keys %image_ids;
12815 foreach (keys %image_ids) {
12816 my $image = SGN::Image->new( $schema->storage->dbh, $_, $c );
12817 $image->delete(); #Sets to obsolete
12820 my $drone_run_band_project_ids_sql = join ",", @drone_run_band_ids;
12821 my $drone_run_band_image_ids_sql = join ",", @drone_run_image_ids;
12822 my $q1 = "DELETE FROM phenome.project_md_image WHERE project_id IN ($drone_run_band_project_ids_sql);";
12823 my $q2 = "DELETE FROM project WHERE project_id IN ($drone_run_band_project_ids_sql);";
12824 my $q3 = "DELETE FROM project WHERE project_id = $drone_run_project_id;";
12825 my $q4 = "DELETE FROM phenome.stock_image WHERE image_id IN (SELECT image_id FROM phenome.project_md_image WHERE project_id IN ($drone_run_band_project_ids_sql));";
12826 print STDERR $q4."\n";
12827 print STDERR $q1."\n";
12828 print STDERR $q2."\n";
12829 print STDERR $q3."\n";
12830 my $h4 = $schema->storage->dbh()->prepare($q4);
12831 $h4->execute();
12832 my $h1 = $schema->storage->dbh()->prepare($q1);
12833 $h1->execute();
12834 my $h2 = $schema->storage->dbh()->prepare($q2);
12835 $h2->execute();
12836 my $h3 = $schema->storage->dbh()->prepare($q3);
12837 $h3->execute();
12839 my $q5 = "
12840 DROP TABLE IF EXISTS temp_drone_image_pheno_deletion;
12841 CREATE TEMP TABLE temp_drone_image_pheno_deletion AS
12842 (SELECT phenotype.phenotype_id, md_image.image_id
12843 FROM phenotype
12844 JOIN nd_experiment_phenotype using(phenotype_id)
12845 JOIN nd_experiment using(nd_experiment_id)
12846 JOIN phenome.nd_experiment_md_images AS md_image using(nd_experiment_id)
12847 WHERE md_image.image_id IN ($drone_run_band_image_ids_sql) );
12848 DELETE FROM phenotype WHERE phenotype_id IN (SELECT phenotype_id FROM temp_drone_image_pheno_deletion);
12849 DROP TABLE IF EXISTS temp_drone_image_pheno_deletion;
12851 my $h5 = $schema->storage->dbh()->prepare($q5);
12852 $h5->execute();
12854 $c->stash->{rest} = {success => 1};
12857 sub drone_imagery_get_image_types : Path('/api/drone_imagery/get_image_types') : ActionClass('REST') { }
12858 sub drone_imagery_get_image_types_GET : Args(0) {
12859 my $self = shift;
12860 my $c = shift;
12861 $c->response->headers->header( "Access-Control-Allow-Origin" => '*' );
12862 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
12863 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
12864 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
12865 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
12866 my ($user_id, $user_name, $user_role) = _check_user_login($c);
12868 my $image_types = CXGN::DroneImagery::ImageTypes::get_all_drone_run_band_image_types()->{array_ref};
12870 $c->stash->{rest} = {success => 1, image_types => $image_types};
12873 sub drone_imagery_growing_degree_days : Path('/api/drone_imagery/growing_degree_days') : ActionClass('REST') { }
12874 sub drone_imagery_growing_degree_days_GET : Args(0) {
12875 my $self = shift;
12876 my $c = shift;
12877 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
12878 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
12879 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
12880 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
12881 my $field_trial_id = $c->req->param('field_trial_id');
12882 my $drone_run_project_id = $c->req->param('drone_run_project_id');
12883 my $formula = $c->req->param('formula');
12884 my $gdd_base_temperature = $c->req->param('gdd_base_temperature');
12885 my ($user_id, $user_name, $user_role) = _check_user_login($c);
12887 my $gdd_result = _perform_gdd_calculation_and_drone_run_time_saving($c, $schema, $field_trial_id, $drone_run_project_id, $c->config->{noaa_ncdc_access_token}, $gdd_base_temperature, $formula);
12888 print STDERR Dumper $gdd_result;
12890 $c->stash->{rest} = {success => 1};
12893 sub drone_imagery_precipitation_sum : Path('/api/drone_imagery/precipitation_sum') : ActionClass('REST') { }
12894 sub drone_imagery_precipitation_sum_GET : Args(0) {
12895 my $self = shift;
12896 my $c = shift;
12897 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
12898 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
12899 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
12900 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
12901 my $field_trial_id = $c->req->param('field_trial_id');
12902 my $drone_run_project_id = $c->req->param('drone_run_project_id');
12903 my $formula = $c->req->param('formula');
12904 my ($user_id, $user_name, $user_role) = _check_user_login($c);
12906 my $precipitation_result = _perform_precipitation_sum_calculation_and_drone_run_time_saving($c, $schema, $field_trial_id, $drone_run_project_id, $c->config->{noaa_ncdc_access_token}, $formula);
12907 print STDERR Dumper $precipitation_result;
12909 $c->stash->{rest} = {success => 1};
12912 sub _perform_gdd_calculation_and_drone_run_time_saving {
12913 my $c = shift;
12914 my $schema = shift;
12915 my $field_trial_id = shift;
12916 my $drone_run_project_id = shift;
12917 my $noaa_ncdc_access_token = shift;
12918 my $gdd_base_temperature = shift;
12919 my $formula = shift;
12921 my $field_trial = CXGN::Trial->new({
12922 bcs_schema => $schema,
12923 trial_id => $field_trial_id
12925 my $planting_date = $field_trial->get_planting_date();
12926 my $noaa_station_id = $field_trial->get_location_noaa_station_id();
12928 my $drone_run_project = CXGN::Trial->new({
12929 bcs_schema => $schema,
12930 trial_id => $drone_run_project_id
12932 my $project_start_date = $drone_run_project->get_project_start_date();
12933 my $drone_run_bands = $drone_run_project->get_associated_image_band_projects();
12935 my $planting_date_time_object = Time::Piece->strptime($planting_date, "%Y-%B-%d");
12936 my $planting_date_datetime = $planting_date_time_object->strftime("%Y-%m-%d");
12937 my $project_start_date_time_object = Time::Piece->strptime($project_start_date, "%Y-%B-%d %H:%M:%S");
12938 my $project_start_date_datetime = $project_start_date_time_object->strftime("%Y-%m-%d");
12940 my $gdd = CXGN::NOAANCDC->new({
12941 bcs_schema => $schema,
12942 start_date => $planting_date_datetime, #YYYY-MM-DD
12943 end_date => $project_start_date_datetime, #YYYY-MM-DD
12944 noaa_station_id => $noaa_station_id,
12945 noaa_ncdc_access_token => $noaa_ncdc_access_token
12947 my $gdd_result;
12948 my %related_cvterms;
12949 if ($formula eq 'average_daily_temp_sum') {
12950 $gdd_result = $gdd->get_temperature_averaged_gdd($gdd_base_temperature);
12951 # if (exists($gdd_result->{error})) {
12952 # $c->stash->{rest} = {error => $gdd_result->{error}};
12953 # $c->detach();
12955 $gdd_result = $gdd_result->{gdd};
12956 $related_cvterms{gdd_average_temp} = $gdd_result;
12958 $drone_run_project->set_temperature_averaged_gdd($gdd_result);
12960 foreach (@$drone_run_bands) {
12961 my $drone_run_band = CXGN::Trial->new({bcs_schema => $schema, trial_id => $_->[0]});
12962 $drone_run_band->set_temperature_averaged_gdd($gdd_result);
12966 my $time_diff = $project_start_date_time_object - $planting_date_time_object;
12967 my $time_diff_weeks = $time_diff->weeks;
12968 my $time_diff_days = $time_diff->days;
12969 my $rounded_time_diff_weeks = round($time_diff_weeks);
12971 my $week_term_string = "week $rounded_time_diff_weeks";
12972 my $q = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
12973 my $h = $schema->storage->dbh()->prepare($q);
12974 $h->execute($week_term_string, 'cxgn_time_ontology');
12975 my ($week_cvterm_id) = $h->fetchrow_array();
12977 if (!$week_cvterm_id) {
12978 my $new_week_term = $schema->resultset("Cv::Cvterm")->create_with({
12979 name => $week_term_string,
12980 cv => 'cxgn_time_ontology'
12982 $week_cvterm_id = $new_week_term->cvterm_id();
12985 my $day_term_string = "day $time_diff_days";
12986 $h->execute($day_term_string, 'cxgn_time_ontology');
12987 my ($day_cvterm_id) = $h->fetchrow_array();
12989 if (!$day_cvterm_id) {
12990 my $new_day_term = $schema->resultset("Cv::Cvterm")->create_with({
12991 name => $day_term_string,
12992 cv => 'cxgn_time_ontology'
12994 $day_cvterm_id = $new_day_term->cvterm_id();
12997 my $week_term = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $week_cvterm_id, 'extended');
12998 my $day_term = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $day_cvterm_id, 'extended');
13000 $related_cvterms{week} = $week_term;
13001 $related_cvterms{day} = $day_term;
13002 my $related_cvterms_result = encode_json \%related_cvterms;
13004 $drone_run_project->set_related_time_cvterms_json($related_cvterms_result);
13006 foreach (@$drone_run_bands) {
13007 my $drone_run_band = CXGN::Trial->new({bcs_schema => $schema, trial_id => $_->[0]});
13008 $drone_run_band->set_related_time_cvterms_json($related_cvterms_result);
13011 return \%related_cvterms;
13014 sub _perform_precipitation_sum_calculation_and_drone_run_time_saving {
13015 my $c = shift;
13016 my $schema = shift;
13017 my $field_trial_id = shift;
13018 my $drone_run_project_id = shift;
13019 my $noaa_ncdc_access_token = shift;
13020 my $formula = shift;
13022 my $field_trial = CXGN::Trial->new({
13023 bcs_schema => $schema,
13024 trial_id => $field_trial_id
13026 my $planting_date = $field_trial->get_planting_date();
13027 my $noaa_station_id = $field_trial->get_location_noaa_station_id();
13029 my $drone_run_project = CXGN::Trial->new({
13030 bcs_schema => $schema,
13031 trial_id => $drone_run_project_id
13033 my $project_start_date = $drone_run_project->get_project_start_date();
13034 my $drone_run_bands = $drone_run_project->get_associated_image_band_projects();
13035 my $related_cvterms = $drone_run_project->get_related_time_cvterms_json() ? decode_json $drone_run_project->get_related_time_cvterms_json() : {};
13037 my $planting_date_time_object = Time::Piece->strptime($planting_date, "%Y-%B-%d");
13038 my $planting_date_datetime = $planting_date_time_object->strftime("%Y-%m-%d");
13039 my $project_start_date_time_object = Time::Piece->strptime($project_start_date, "%Y-%B-%d %H:%M:%S");
13040 my $project_start_date_datetime = $project_start_date_time_object->strftime("%Y-%m-%d");
13042 my $noaa = CXGN::NOAANCDC->new({
13043 bcs_schema => $schema,
13044 start_date => $planting_date_datetime, #YYYY-MM-DD
13045 end_date => $project_start_date_datetime, #YYYY-MM-DD
13046 noaa_station_id => $noaa_station_id,
13047 noaa_ncdc_access_token => $noaa_ncdc_access_token
13049 my $precipitation_result;
13050 if ($formula eq 'average_daily_precipitation_sum') {
13051 $precipitation_result = $noaa->get_averaged_precipitation();
13052 $related_cvterms->{precipitation_averaged_sum} = $precipitation_result;
13054 $drone_run_project->set_precipitation_averaged_sum_gdd($precipitation_result);
13056 foreach (@$drone_run_bands) {
13057 my $drone_run_band = CXGN::Trial->new({bcs_schema => $schema, trial_id => $_->[0]});
13058 $drone_run_band->set_precipitation_averaged_sum_gdd($precipitation_result);
13062 my $time_diff = $project_start_date_time_object - $planting_date_time_object;
13063 my $time_diff_weeks = $time_diff->weeks;
13064 my $time_diff_days = $time_diff->days;
13065 my $rounded_time_diff_weeks = round($time_diff_weeks);
13067 my $week_term_string = "week $rounded_time_diff_weeks";
13068 my $q = "SELECT t.cvterm_id FROM cvterm as t JOIN cv ON(t.cv_id=cv.cv_id) WHERE t.name=? and cv.name=?;";
13069 my $h = $schema->storage->dbh()->prepare($q);
13070 $h->execute($week_term_string, 'cxgn_time_ontology');
13071 my ($week_cvterm_id) = $h->fetchrow_array();
13073 if (!$week_cvterm_id) {
13074 my $new_week_term = $schema->resultset("Cv::Cvterm")->create_with({
13075 name => $week_term_string,
13076 cv => 'cxgn_time_ontology'
13078 $week_cvterm_id = $new_week_term->cvterm_id();
13081 my $day_term_string = "day $time_diff_days";
13082 $h->execute($day_term_string, 'cxgn_time_ontology');
13083 my ($day_cvterm_id) = $h->fetchrow_array();
13085 if (!$day_cvterm_id) {
13086 my $new_day_term = $schema->resultset("Cv::Cvterm")->create_with({
13087 name => $day_term_string,
13088 cv => 'cxgn_time_ontology'
13090 $day_cvterm_id = $new_day_term->cvterm_id();
13093 my $week_term = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $week_cvterm_id, 'extended');
13094 my $day_term = SGN::Model::Cvterm::get_trait_from_cvterm_id($schema, $day_cvterm_id, 'extended');
13096 $related_cvterms->{week} = $week_term;
13097 $related_cvterms->{day} = $day_term;
13098 my $related_cvterms_result = encode_json $related_cvterms;
13100 $drone_run_project->set_related_time_cvterms_json($related_cvterms_result);
13102 foreach (@$drone_run_bands) {
13103 my $drone_run_band = CXGN::Trial->new({bcs_schema => $schema, trial_id => $_->[0]});
13104 $drone_run_band->set_related_time_cvterms_json($related_cvterms_result);
13107 return $related_cvterms;
13110 sub drone_imagery_retrain_mask_rcnn : Path('/api/drone_imagery/retrain_mask_rcnn') : ActionClass('REST') { }
13111 sub drone_imagery_retrain_mask_rcnn_GET : Args(0) {
13112 my $self = shift;
13113 my $c = shift;
13114 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
13115 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
13116 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
13117 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
13118 my ($user_id, $user_name, $user_role) = _check_user_login($c);
13119 my $model_name = $c->req->param('model_name');
13120 my $model_description = $c->req->param('model_description');
13121 my $model_type = $c->req->param('model_type');
13123 my $time = DateTime->now();
13124 my $timestamp = $time->ymd()."_".$time->hms();
13126 my $manual_plot_polygon_template_partial = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons_partial', 'project_property')->cvterm_id();
13127 my $q = "SELECT value FROM projectprop WHERE type_id=$manual_plot_polygon_template_partial;";
13128 my $h = $schema->storage->dbh->prepare($q);
13129 $h->execute();
13131 my @result;
13132 my %unique_image_ids;
13133 while (my ($value) = $h->fetchrow_array()) {
13134 if ($value) {
13135 my $partial_templates = decode_json $value;
13136 foreach my $t (@$partial_templates) {
13137 my $image_id = $t->{image_id};
13138 my $polygon = $t->{polygon};
13139 my $stock_polygon = $t->{stock_polygon};
13140 my $template_name = $t->{template_name};
13141 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
13142 my $image_url = $image->get_image_url("original");
13143 my $image_fullpath = $image->get_filename('original_converted', 'full');
13144 my @size = imgsize($image_fullpath);
13146 push @{$unique_image_ids{$image_id}->{p}}, {
13147 polygon => $polygon,
13148 template_name => $template_name
13150 $unique_image_ids{$image_id}->{width} = $size[0];
13151 $unique_image_ids{$image_id}->{height} = $size[1];
13152 $unique_image_ids{$image_id}->{image_fullpath} = $image_fullpath;
13153 $unique_image_ids{$image_id}->{image_url} = $image_url;
13157 # print STDERR Dumper \%unique_image_ids;
13159 my $drone_run_band_plot_polygons_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
13160 my $denoised_stitched_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
13161 my $drone_run_band_polygons_q = "SELECT project.project_id, image_type.image_id, polygons.value
13162 FROM project
13163 JOIN projectprop AS polygons ON (project.project_id=polygons.project_id AND polygons.type_id=$drone_run_band_plot_polygons_type_id)
13164 JOIN phenome.project_md_image AS image_type ON(project.project_id=image_type.project_id AND image_type.type_id=$denoised_stitched_type_id)
13165 JOIN metadata.md_image AS image ON(image_type.image_id=image.image_id)
13166 WHERE image.obsolete = 'f';";
13167 my $drone_run_band_polygons_h = $schema->storage->dbh->prepare($drone_run_band_polygons_q);
13168 $drone_run_band_polygons_h->execute();
13169 while (my ($project_id, $image_id, $polygon_json) = $drone_run_band_polygons_h->fetchrow_array()) {
13170 my $polygons = decode_json $polygon_json;
13171 # print STDERR Dumper $polygons;
13172 # print STDERR Dumper $image_id;
13174 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
13175 my $image_url = $image->get_image_url("original");
13176 my $image_fullpath = $image->get_filename('original_converted', 'full');
13177 my @size = imgsize($image_fullpath);
13179 push @{$unique_image_ids{$image_id}->{p}}, {
13180 polygon => $polygons,
13181 template_name => $project_id
13184 $unique_image_ids{$image_id}->{width} = $size[0];
13185 $unique_image_ids{$image_id}->{height} = $size[1];
13186 $unique_image_ids{$image_id}->{image_fullpath} = $image_fullpath;
13187 $unique_image_ids{$image_id}->{image_url} = $image_url;
13189 # print STDERR Dumper \%unique_image_ids;
13191 my $dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_maskrcnn_input_annotations_dir');
13192 my $output_dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_maskrcnn_dir');
13193 my $temp_output_model_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_maskrcnn_dir/outputmodelfileXXXX').".h5";
13194 my $temp_output_dir = $c->config->{basepath}."/".$output_dir;
13195 my $temp_input_dir = $c->config->{basepath}."/".$dir;
13196 print STDERR Dumper $temp_input_dir;
13198 my $temp_model_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_maskrcnn_dir/annotationfileXXXX');
13199 open(my $F_model, ">", $temp_model_input_file) || die "Can't open file ".$temp_model_input_file;
13200 print $F_model "<annotations>\n";
13202 while (my ($image_id, $p) = each %unique_image_ids) {
13203 my $file_path = $p->{image_fullpath};
13204 my $width = $p->{width};
13205 my $height = $p->{height};
13206 my $temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_maskrcnn_input_annotations_dir/inputannotationfileXXXX');
13207 # print STDERR Dumper $archive_temp_input_file;
13209 open(my $F_img, ">", $temp_input_file) || die "Can't open file ".$temp_input_file;
13210 print $F_img "<annotation>\n";
13211 print $F_img "\t<image_id>$image_id</image_id>\n";
13212 print $F_img "\t<image_path>$file_path</image_path>\n";
13213 print $F_img "\t<size>\n";
13214 print $F_img "\t\t<width>$width</width>\n";
13215 print $F_img "\t\t<height>$height</height>\n";
13216 print $F_img "\t</size>\n";
13218 print $F_model "<annotation>\n";
13219 print $F_model "\t<image_id>$image_id</image_id>\n";
13220 print $F_model "\t<image_path>$file_path</image_path>\n";
13221 print $F_model "\t<size>\n";
13222 print $F_model "\t\t<width>$width</width>\n";
13223 print $F_model "\t\t<height>$height</height>\n";
13224 print $F_model "\t</size>\n";
13226 foreach my $poly (@{$p->{p}}) {
13227 foreach my $po (values %{$poly->{polygon}}) {
13228 my $xmin = 1000000;
13229 my $ymin = 1000000;
13230 my $xmax = 0;
13231 my $ymax = 0;
13232 foreach my $ob (@$po) {
13233 if ($ob->{x} < $xmin) {
13234 $xmin = round($ob->{x});
13236 if ($ob->{y} < $ymin) {
13237 $ymin = round($ob->{y});
13239 if ($ob->{x} > $xmax) {
13240 $xmax = round($ob->{x});
13242 if ($ob->{y} > $ymax) {
13243 $ymax = round($ob->{y});
13246 print $F_img "\t<object>\n";
13247 print $F_img "\t\t<name>".$poly->{template_name}."</name>\n";
13248 print $F_img "\t\t<bndbox>\n";
13249 print $F_img "\t\t\t<xmin>$xmin</xmin>\n";
13250 print $F_img "\t\t\t<ymin>$ymin</ymin>\n";
13251 print $F_img "\t\t\t<xmax>$xmax</xmax>\n";
13252 print $F_img "\t\t\t<ymax>$ymax</ymax>\n";
13253 print $F_img "\t\t</bndbox>\n";
13254 print $F_img "\t</object>\n";
13256 print $F_model "\t<object>\n";
13257 print $F_model "\t\t<name>".$poly->{template_name}."</name>\n";
13258 print $F_model "\t\t<bndbox>\n";
13259 print $F_model "\t\t\t<xmin>$xmin</xmin>\n";
13260 print $F_model "\t\t\t<ymin>$ymin</ymin>\n";
13261 print $F_model "\t\t\t<xmax>$xmax</xmax>\n";
13262 print $F_model "\t\t\t<ymax>$ymax</ymax>\n";
13263 print $F_model "\t\t</bndbox>\n";
13264 print $F_model "\t</object>\n";
13267 print $F_img "</annotation>\n";
13269 print $F_model "</annotation>\n";
13270 close($F_img);
13272 print $F_model "</annotations>\n";
13273 close($F_model);
13275 my $log_file_path = '';
13276 if ($c->config->{error_log}) {
13277 $log_file_path = ' --log_file_path \''.$c->config->{error_log}.'\'';
13279 my $cmd = $c->config->{python_executable_maskrcnn_env}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/MaskRCNNBoundingBoxTrain.py --input_annotations_dir \''.$temp_input_dir.'\' --output_model_path \''.$temp_output_model_file.'\' --output_model_dir \''.$temp_output_dir.'\' '.$log_file_path;
13280 print STDERR Dumper $cmd;
13281 my $status = system("$cmd > /dev/null");
13283 my $keras_mask_r_cnn_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'trained_keras_mask_r_cnn_model', 'protocol_type')->cvterm_id();
13284 my $keras_cnn_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_experiment', 'experiment_type')->cvterm_id();
13286 my $m = CXGN::AnalysisModel::SaveModel->new({
13287 bcs_schema=>$schema,
13288 metadata_schema=>$metadata_schema,
13289 phenome_schema=>$phenome_schema,
13290 archive_path=>$c->config->{archive_path},
13291 model_name=>$model_name,
13292 model_description=>$model_description,
13293 model_language=>'Python',
13294 model_type_cvterm_id=>$keras_mask_r_cnn_cvterm_id,
13295 model_properties=>{model_type=>$model_type, image_type=>'all_annotated_plot_images'},
13296 application_name=>'MaskRCNNModel',
13297 application_version=>'V1.1',
13298 is_public=>1,
13299 user_id=>$user_id,
13300 user_role=>$user_role
13302 my $saved_model = $m->save_model();
13303 my $saved_model_id = $saved_model->{nd_protocol_id};
13305 my $analysis_model = CXGN::AnalysisModel::GetModel->new({
13306 bcs_schema=>$schema,
13307 metadata_schema=>$metadata_schema,
13308 phenome_schema=>$phenome_schema,
13309 nd_protocol_id=>$saved_model_id
13311 $analysis_model->store_analysis_model_files({
13312 # project_id => $saved_analysis_id,
13313 archived_model_file_type=>'trained_keras_mask_r_cnn_model',
13314 model_file=>$temp_output_model_file,
13315 archived_training_data_file_type=>'trained_keras_mask_r_cnn_model_input_data_file',
13316 archived_training_data_file=>$temp_model_input_file,
13317 # archived_auxiliary_files=>[
13318 # {auxiliary_model_file => $archive_temp_autoencoder_output_model_file, auxiliary_model_file_archive_type => 'trained_keras_cnn_autoencoder_model'},
13319 # {auxiliary_model_file => $model_input_aux_file, auxiliary_model_file_archive_type => 'trained_keras_cnn_model_input_aux_data_file'}
13320 # ],
13321 archive_path=>$c->config->{archive_path},
13322 user_id=>$user_id,
13323 user_role=>$user_role
13326 $c->stash->{rest} = {success => 1};
13329 sub drone_imagery_predict_mask_rcnn : Path('/api/drone_imagery/predict_mask_rcnn') : ActionClass('REST') { }
13330 sub drone_imagery_predict_mask_rcnn_GET : Args(0) {
13331 my $self = shift;
13332 my $c = shift;
13333 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
13334 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
13335 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
13336 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
13337 my ($user_id, $user_name, $user_role) = _check_user_login($c);
13338 my $model_id = $c->req->param('model_id');
13339 my $image_id = $c->req->param('image_id');
13341 my $time = DateTime->now();
13342 my $timestamp = $time->ymd();
13344 my $keras_mask_r_cnn_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'trained_keras_mask_r_cnn_model', 'protocol_type')->cvterm_id();
13345 my $model_properties_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_properties', 'protocol_property')->cvterm_id();
13346 my $keras_cnn_experiment_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'analysis_model_experiment', 'experiment_type')->cvterm_id();
13348 my $m = CXGN::AnalysisModel::GetModel->new({
13349 bcs_schema=>$schema,
13350 metadata_schema=>$metadata_schema,
13351 phenome_schema=>$phenome_schema,
13352 nd_protocol_id=>$model_id
13354 my $saved_model_object = $m->get_model();
13355 print STDERR Dumper $saved_model_object;
13356 my $model_type = $saved_model_object->{model_properties}->{model_type};
13357 my $trained_image_type = $saved_model_object->{model_properties}->{image_type};
13358 my $model_file = $saved_model_object->{model_files}->{trained_keras_mask_r_cnn_model};
13359 my $training_input_data_file = $saved_model_object->{model_files}->{trained_keras_mask_r_cnn_model_input_data_file};
13361 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
13362 my $image_url = $image->get_image_url("original");
13363 my $image_fullpath = $image->get_filename('original_converted', 'full');
13364 my @size = imgsize($image_fullpath);
13365 my $width = $size[0];
13366 my $height = $size[1];
13368 my $output_dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_maskrcnn_predict_dir');
13369 my $dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_maskrcnn_predict_input_annotations_dir');
13370 my $model_dir = $c->tempfiles_subdir('/drone_imagery_keras_cnn_maskrcnn_predict_input_model_dir');
13371 my $temp_input_dir = $c->config->{basepath}."/".$dir;
13372 my $temp_model_dir = $c->config->{basepath}."/".$model_dir;
13373 print STDERR Dumper $temp_input_dir;
13375 my $archive_temp_output_results_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_maskrcnn_predict_dir/outputfileXXXX');
13376 my $archive_temp_output_activation_file = $c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_maskrcnn_predict_input_model_dir/outputactivationfileXXXX');
13377 $archive_temp_output_activation_file .= ".pdf";
13378 my $archive_temp_output_activation_file_path = $c->config->{basepath}."/".$archive_temp_output_activation_file;
13380 my $temp_input_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_keras_cnn_maskrcnn_predict_input_annotations_dir/inputannotationfileXXXX');
13381 # print STDERR Dumper $archive_temp_input_file;
13383 open(my $F_img, ">", $temp_input_file) || die "Can't open file ".$temp_input_file;
13384 print $F_img "<annotation>\n";
13385 print $F_img "\t<image_id>$image_id</image_id>\n";
13386 print $F_img "\t<image_path>$image_fullpath</image_path>\n";
13387 print $F_img "\t<size>\n";
13388 print $F_img "\t\t<width>$width</width>\n";
13389 print $F_img "\t\t<height>$height</height>\n";
13390 print $F_img "\t</size>\n";
13391 print $F_img "</annotation>\n";
13392 close($F_img);
13394 my $log_file_path = '';
13395 if ($c->config->{error_log}) {
13396 $log_file_path = ' --log_file_path \''.$c->config->{error_log}.'\'';
13398 my $cmd = $c->config->{python_executable_maskrcnn_env}.' '.$c->config->{rootpath}.'/DroneImageScripts/CNN/MaskRCNNBoundingBoxPredict.py --input_annotations_dir \''.$temp_input_dir.'\' --model_path \''.$model_file.'\' --model_dir \''.$temp_model_dir.'\' --outfile_annotated \''.$archive_temp_output_activation_file_path.'\' --results_outfile \''.$archive_temp_output_results_file.'\' '.$log_file_path;
13399 print STDERR Dumper $cmd;
13400 my $status = system("$cmd /dev/null");
13402 my @bounding_boxes;
13403 my $csv = Text::CSV->new({ sep_char => ',' });
13404 open(my $fh, '<', $archive_temp_output_results_file) or die "Could not open file '$archive_temp_output_results_file' $!";
13405 print STDERR "Opened $archive_temp_output_results_file\n";
13406 while ( my $row = <$fh> ){
13407 my @columns;
13408 if ($csv->parse($row)) {
13409 @columns = $csv->fields();
13411 print STDERR Dumper \@columns;
13412 push @bounding_boxes, \@columns;
13414 close($fh);
13416 $c->stash->{rest} = {success => 1, activation_output => $archive_temp_output_activation_file, bounding_boxes => \@bounding_boxes};
13419 sub drone_imagery_export_drone_runs : Path('/api/drone_imagery/export_drone_runs') : ActionClass('REST') { }
13420 sub drone_imagery_export_drone_runs_GET : Args(0) {
13421 my $self = shift;
13422 my $c = shift;
13423 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
13424 my $schema = $c->dbic_schema("Bio::Chado::Schema", undef, $sp_person_id);
13425 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $sp_person_id);
13426 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $sp_person_id);
13427 my $drone_run_project_ids = decode_json $c->req->param('drone_run_project_ids');
13428 my $field_trial_id = $c->req->param('field_trial_id');
13429 my ($user_id, $user_name, $user_role) = _check_user_login($c);
13431 my $plot_polygon_template_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_plot_polygons', 'project_property')->cvterm_id();
13432 my $drone_run_drone_run_band_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_on_drone_run', 'project_relationship')->cvterm_id();
13433 my $original_denoised_image_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'denoised_stitched_drone_imagery', 'project_md_image')->cvterm_id();
13434 my $imaging_vehicle_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'imaging_event_vehicle', 'stock_type')->cvterm_id();
13435 my $imaging_vehicle_properties_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'imaging_event_vehicle_json', 'stock_property')->cvterm_id();
13436 my $drone_run_experiment_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_experiment', 'experiment_type')->cvterm_id();
13437 my $drone_run_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_project_type', 'project_property')->cvterm_id();
13438 my $drone_run_camera_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_camera_type', 'project_property')->cvterm_id();
13439 my $project_start_date_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'project_start_date', 'project_property')->cvterm_id();
13440 my $drone_run_base_date_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_base_date', 'project_property')->cvterm_id();
13441 my $drone_run_rig_desc_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_camera_rig_description', 'project_property')->cvterm_id();
13442 my $project_relationship_type_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_on_field_trial', 'project_relationship')->cvterm_id();
13443 my $drone_run_band_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'drone_run_band_project_type', 'project_property')->cvterm_id();
13444 my $calendar_funcs = CXGN::Calendar->new({});
13446 my %spectral_lookup = (
13447 "Blue (450-520nm)" => "blue",
13448 "Green (515-600nm)" => "green",
13449 "Red (600-690nm)" => "red",
13450 "Red Edge (690-750nm)" => "rededge",
13451 "NIR (780-3000nm)" => "nir",
13452 "MIR (3000-50000nm)" => "mir",
13453 "FIR (50000-1000000nm)" => "fir",
13454 "Thermal IR (9000-14000nm)" => "thir",
13455 "RGB Color Image" => "rgb",
13456 "Black and White Image" => "bw"
13459 my %sensor_map = (
13460 "micasense_5" => "MicaSense 5 Channel Camera",
13461 "ccd_color" => "CCD Color Camera",
13462 "cmos_color" => "CMOS Color Camera"
13465 my %drone_run_csv_info;
13466 foreach my $drone_run_project_id (@$drone_run_project_ids) {
13467 my $q = "SELECT plot_polygons.value, drone_run.project_id, drone_run.name, drone_run.description, drone_run_band.project_id, drone_run_band.name, drone_run_band.description, project_image.image_id, project_image_type.name, stock.uniquename, stock.stock_id, imaging_event_type.value, camera.value, imaging_event_date.value, base_date.value, camera_rig.value, field_trial.name, field_trial.project_id, drone_run_band_type.value
13468 FROM project AS drone_run_band
13469 JOIN project_relationship ON(project_relationship.subject_project_id = drone_run_band.project_id AND project_relationship.type_id = $drone_run_drone_run_band_type_id)
13470 JOIN project AS drone_run ON(project_relationship.object_project_id = drone_run.project_id)
13471 JOIN projectprop AS plot_polygons ON(drone_run_band.project_id = plot_polygons.project_id AND plot_polygons.type_id=$plot_polygon_template_type_id)
13472 JOIN projectprop AS drone_run_band_type ON(drone_run_band.project_id = drone_run_band_type.project_id AND drone_run_band_type.type_id=$drone_run_band_type_cvterm_id)
13473 JOIN phenome.project_md_image AS project_image ON(drone_run_band.project_id = project_image.project_id AND project_image.type_id=$original_denoised_image_type_id)
13474 JOIN metadata.md_image AS md_image ON(md_image.image_id = project_image.image_id)
13475 JOIN cvterm AS project_image_type ON(project_image.type_id = project_image_type.cvterm_id)
13476 JOIN nd_experiment_project ON(nd_experiment_project.project_id = drone_run.project_id)
13477 JOIN nd_experiment ON(nd_experiment_project.nd_experiment_id = nd_experiment.nd_experiment_id AND nd_experiment.type_id=$drone_run_experiment_type_id)
13478 JOIN nd_experiment_stock ON(nd_experiment.nd_experiment_id = nd_experiment_stock.nd_experiment_id)
13479 JOIN stock ON(nd_experiment_stock.stock_id=stock.stock_id AND stock.type_id=$imaging_vehicle_cvterm_id)
13480 JOIN projectprop AS imaging_event_type ON(imaging_event_type.project_id = drone_run.project_id AND imaging_event_type.type_id=$drone_run_type_cvterm_id)
13481 JOIN projectprop AS camera ON(camera.project_id = drone_run.project_id AND camera.type_id=$drone_run_camera_type_cvterm_id)
13482 JOIN projectprop AS imaging_event_date ON(imaging_event_date.project_id = drone_run.project_id AND imaging_event_date.type_id=$project_start_date_type_id)
13483 LEFT JOIN projectprop AS base_date ON(base_date.project_id = drone_run.project_id AND base_date.type_id=$drone_run_base_date_type_id)
13484 LEFT JOIN projectprop AS camera_rig ON(camera_rig.project_id = drone_run.project_id AND camera_rig.type_id=$drone_run_rig_desc_type_id)
13485 JOIN project_relationship AS field_trial_rel ON(field_trial_rel.subject_project_id = drone_run.project_id AND field_trial_rel.type_id = $project_relationship_type_id)
13486 JOIN project AS field_trial ON(field_trial_rel.object_project_id = field_trial.project_id)
13487 WHERE drone_run.project_id = ? AND md_image.obsolete='f'
13488 ORDER BY drone_run_band.project_id;";
13490 my $h = $schema->storage->dbh()->prepare($q);
13491 $h->execute($drone_run_project_id);
13492 while (my ($plot_polygons_value, $drone_run_project_id, $drone_run_project_name, $drone_run_description, $drone_run_band_project_id, $drone_run_band_project_name, $drone_run_band_description, $image_id, $project_image_type, $imaging_vehicle_name, $imaging_vehicle_id, $imaging_event_type, $camera, $imaging_event_calendar, $base_date_calendar, $camera_rig, $field_trial_name, $field_trial_id, $drone_run_band_type) = $h->fetchrow_array()) {
13493 my $imaging_event_date = $imaging_event_calendar ? $calendar_funcs->display_start_date($imaging_event_calendar) : '';
13494 my $imaging_event_base_date = $base_date_calendar ? $calendar_funcs->display_start_date($base_date_calendar) : '';
13495 $drone_run_csv_info{$drone_run_project_id}->{plot_polygons_value} = $plot_polygons_value;
13496 $drone_run_csv_info{$drone_run_project_id}->{imaging_event_date} = $imaging_event_date;
13497 $drone_run_csv_info{$drone_run_project_id}->{imaging_event_base_date} = $imaging_event_base_date;
13498 $drone_run_csv_info{$drone_run_project_id}->{drone_run_name} = $drone_run_project_name;
13499 $drone_run_csv_info{$drone_run_project_id}->{drone_run_description} = $drone_run_description;
13500 $drone_run_csv_info{$drone_run_project_id}->{imaging_vehicle_name} = $imaging_vehicle_name;
13501 $drone_run_csv_info{$drone_run_project_id}->{imaging_vehicle_id} = $imaging_vehicle_id;
13502 $drone_run_csv_info{$drone_run_project_id}->{imaging_event_type} = $imaging_event_type;
13503 $drone_run_csv_info{$drone_run_project_id}->{camera} = $sensor_map{$camera};
13504 $drone_run_csv_info{$drone_run_project_id}->{camera_rig} = $camera_rig;
13505 $drone_run_csv_info{$drone_run_project_id}->{field_trial_name} = $field_trial_name;
13506 $drone_run_csv_info{$drone_run_project_id}->{field_trial_id} = $field_trial_id;
13507 my $spec = $spectral_lookup{$drone_run_band_type};
13508 if ($spec) {
13509 push @{$drone_run_csv_info{$drone_run_project_id}->{drone_run_bands}}, {
13510 drone_run_band_project_id => $drone_run_band_project_id,
13511 drone_run_band_project_name => $drone_run_band_project_name,
13512 drone_run_band_description => $drone_run_band_description,
13513 image_id => $image_id,
13514 project_image_type => $project_image_type,
13515 drone_run_band_type => $drone_run_band_type,
13516 drone_run_band_type_short => $spec,
13521 # print STDERR Dumper \%drone_run_csv_info;
13523 my $images_zip = Archive::Zip->new();
13524 # my $dir_images_member = $images_zip->addDirectory( 'orthoimage_files/' );
13526 my $output_image_zipfile_dir = $c->tempfiles_subdir('/drone_imagery_export_image_zipfile_dir');
13527 my $imaging_events_file = $c->tempfile( TEMPLATE => 'drone_imagery_export_image_zipfile_dir/imagingeventsXXXX');
13528 $imaging_events_file .= ".xls";
13529 my $imaging_events_file_path = $c->config->{basepath}."/".$imaging_events_file;
13531 my @imaging_events_spreadsheet_rows;
13532 my @images_file_names_return;
13533 my $workbook = Spreadsheet::WriteExcel->new($imaging_events_file_path);
13534 my $worksheet = $workbook->add_worksheet();
13535 my $header_row = ['Imaging Event Name','Type','Description','Date','Vehicle Name','Vehicle Battery Set','Sensor','Field Trial Name','GeoJSON Filename','Image Filenames','Coordinate System','Base Date','Camera Rig'];
13536 $worksheet->write_row(0, 0, $header_row);
13537 push @imaging_events_spreadsheet_rows, $header_row;
13538 my $line_number = 1;
13540 my %geojson_hash;
13541 foreach my $drone_run_project_id (sort keys %drone_run_csv_info) {
13542 my $drone_run_info = $drone_run_csv_info{$drone_run_project_id};
13544 my $plot_polygons_value = decode_json $drone_run_info->{plot_polygons_value};
13545 my $field_trial_id = $drone_run_info->{field_trial_id};
13546 my $field_trial_name = $drone_run_info->{field_trial_name};
13547 my $drone_run_name = $drone_run_info->{drone_run_name};
13548 my $imaging_event_date = $drone_run_info->{imaging_event_date};
13549 my $imaging_event_base_date = $drone_run_info->{imaging_event_base_date} || '';
13550 my $drone_run_description = $drone_run_info->{drone_run_description};
13551 my $imaging_vehicle_name = $drone_run_info->{imaging_vehicle_name};
13552 my $imaging_event_type = $drone_run_info->{imaging_event_type};
13553 my $camera = $drone_run_info->{camera};
13554 my $camera_rig = $drone_run_info->{camera_rig} || '';
13555 my $drone_run_bands = $drone_run_info->{drone_run_bands};
13556 my @image_filenames;
13557 foreach my $band (@$drone_run_bands) {
13558 my $spec = $band->{drone_run_band_type_short};
13559 my $image_id = $band->{image_id};
13560 my $image = SGN::Image->new( $schema->storage->dbh, $image_id, $c );
13561 my $image_fullpath = $image->get_filename('original_converted', 'full');
13562 print STDERR Dumper $image_fullpath;
13563 my $image_name = $image_id."__".$spec.".JPG";
13564 my $file_member = $images_zip->addFile( $image_fullpath, $image_name );
13565 push @images_file_names_return, $image_name;
13566 push @image_filenames, $image_name;
13569 my $trial = CXGN::Trial->new({ bcs_schema => $schema, trial_id => $field_trial_id });
13570 my $trial_layout = $trial->get_layout()->get_design();
13571 # print STDERR Dumper $trial_layout;
13572 # print STDERR Dumper $plot_polygons_value;
13574 my %plot_name_lookup;
13575 while (my ($plot_number, $plot_info) = each %$trial_layout) {
13576 $plot_name_lookup{$plot_info->{plot_name}} = $plot_number;
13579 foreach my $stock_name (keys %$plot_polygons_value) {
13580 my $polygon = $plot_polygons_value->{$stock_name};
13581 my @coords;
13582 foreach my $point (@$polygon) {
13583 my $x = $point->{x};
13584 my $y = $point->{y};
13585 push @coords, [$x, $y];
13587 $geojson_hash{$drone_run_project_id}->{$plot_name_lookup{$stock_name}} = \@coords;
13589 my $geojson_filename = $drone_run_project_id.".geojson";
13591 my $orthoimage_filenames = join ',', @image_filenames;
13592 $drone_run_info->{orthoimage_files} = $orthoimage_filenames;
13593 $drone_run_info->{geojson_file} = $geojson_filename;
13595 my $imaging_event_row = [$drone_run_name, $imaging_event_type, $drone_run_description, $imaging_event_date, $imaging_vehicle_name, '', $camera, $field_trial_name, $geojson_filename, $orthoimage_filenames, "Pixels", $imaging_event_base_date, $camera_rig];
13596 $worksheet->write_row($line_number, 0, $imaging_event_row);
13597 push @imaging_events_spreadsheet_rows, $imaging_event_row;
13598 $line_number++;
13600 $workbook->close();
13602 my $orthoimage_zipfile = $c->tempfile( TEMPLATE => 'drone_imagery_export_image_zipfile_dir/orthoimagezipfileXXXX');
13603 $orthoimage_zipfile .= ".zip";
13604 my $orthoimage_zipfile_file_path = $c->config->{basepath}."/".$orthoimage_zipfile;
13606 unless ( $images_zip->writeToFileNamed($orthoimage_zipfile_file_path) == AZ_OK ) {
13607 $c->stash->{rest} = {error => "Images zipfile could not be saved!"};
13608 $c->detach;
13611 my $geojson_zip = Archive::Zip->new();
13612 # my $dir_geojson_member = $geojson_zip->addDirectory( 'geojson_files/' );
13614 my $output_geojson_zipfile_dir = $c->tempfiles_subdir('/drone_imagery_export_image_geojson_dir');
13616 my @geojson_file_names_return;
13617 foreach my $drone_run_project_id (sort keys %geojson_hash) {
13618 my $plot_geo = $geojson_hash{$drone_run_project_id};
13620 my @features_geojson;
13621 while (my($plot_number, $coords) = each %$plot_geo) {
13622 my $first_coord = $coords->[0];
13623 push @$coords, $first_coord;
13624 my %feature_geojson = (
13625 type => "Feature",
13626 field_trial_name => $drone_run_csv_info{$drone_run_project_id}->{field_trial_name},
13627 properties => {
13628 ID => $plot_number
13630 geometry => {
13631 type => "Polygon",
13632 coordinates => [$coords]
13635 push @features_geojson, \%feature_geojson;
13638 my %geojson = (
13639 type => "FeatureCollection",
13640 features => \@features_geojson
13642 my $geojson_string = encode_json \%geojson;
13644 my $geojson_file = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'drone_imagery_export_image_geojson_dir/geojsonXXXX');
13646 open(my $fh_geojson, '>', $geojson_file) or die "Could not open file '$geojson_file' $!";
13647 print STDERR "Opened $geojson_file\n";
13648 print $fh_geojson $geojson_string;
13649 close($fh_geojson);
13651 my $geojson_filename_save = $drone_run_csv_info{$drone_run_project_id}->{geojson_file};
13652 my $file_member = $geojson_zip->addFile( $geojson_file, $geojson_filename_save );
13653 push @geojson_file_names_return, $geojson_filename_save;
13656 my $geojson_zipfile = $c->tempfile( TEMPLATE => 'drone_imagery_export_image_zipfile_dir/geojsonzipfileXXXX');
13657 $geojson_zipfile .= ".zip";
13658 my $geojson_zipfile_file_path = $c->config->{basepath}."/".$geojson_zipfile;
13660 unless ( $geojson_zip->writeToFileNamed($geojson_zipfile_file_path) == AZ_OK ) {
13661 $c->stash->{rest} = {error => "GeoJSON zipfile could not be saved!"};
13662 $c->detach;
13665 my $trial = CXGN::Trial->new({ bcs_schema => $schema, trial_id => $field_trial_id });
13666 my $trial_layout = $trial->get_layout()->get_design();
13667 my $planting_date = $trial->get_planting_date();
13668 my $trial_desc = $trial->get_description();
13669 my $trial_year = $trial->get_year();
13670 my $trial_location = $trial->get_location();
13671 my $location_id = $trial_location->[0];
13672 my $location = CXGN::Location->new( { bcs_schema => $schema, nd_geolocation_id => $location_id } );
13674 $c->stash->{rest} = {
13675 success => 1,
13676 orthoimage_zipfile => $orthoimage_zipfile,
13677 geojson_zipfile => $geojson_zipfile,
13678 imaging_events_spreadsheet => $imaging_events_file,
13679 field_trial_id => $field_trial_id,
13680 planting_date => $planting_date,
13681 trial_layout => $trial_layout,
13682 drone_run_csv_info => \%drone_run_csv_info,
13683 imaging_events_spreadsheet_rows => \@imaging_events_spreadsheet_rows,
13684 images_file_names_return => \@images_file_names_return,
13685 geojson_file_names_return => \@geojson_file_names_return
13689 sub _check_user_login {
13690 my $c = shift;
13691 my $role_check = shift;
13692 my $user_id;
13693 my $user_name;
13694 my $user_role;
13695 my $session_id = $c->req->param("sgn_session_id");
13697 if ($session_id){
13698 my $dbh = $c->dbc->dbh;
13699 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
13700 if (!$user_info[0]){
13701 $c->stash->{rest} = {error=>'You must be logged in to do this!'};
13702 $c->detach();
13704 $user_id = $user_info[0];
13705 $user_role = $user_info[1];
13706 my $p = CXGN::People::Person->new($dbh, $user_id);
13707 $user_name = $p->get_username;
13708 } else{
13709 if (!$c->user){
13710 $c->stash->{rest} = {error=>'You must be logged in to do this!'};
13711 $c->detach();
13713 $user_id = $c->user()->get_object()->get_sp_person_id();
13714 $user_name = $c->user()->get_object()->get_username();
13715 $user_role = $c->user->get_object->get_user_type();
13717 if ($role_check && $user_role ne $role_check) {
13718 $c->stash->{rest} = {error=>'You must have permission to do this! Please contact us!'};
13719 $c->detach();
13721 return ($user_id, $user_name, $user_role);