Merge branch 'master' into topic/transformation_tool
[sgn.git] / bin / load_images.pl
blobac1951e107b1f14c82e0b689afaf01519f203713
1 #!/usr/bin/perl
3 =head1 NAME
5 load_images.pl
7 =head1 SYNOPSYS
9 load_images.pl -D [ sandbox | cxgn | trial ] -H hostname -i dirname -r chado table name [script will load image ids into ChadoTableprop ]
11 =head1 DESCRIPTION
13 Loads images into the SGN database, using the SGN::Image framework.
14 Then link the loaded image with the user-supplied chado objects (e.g. stock, nd_experiment)
17 Requires the following parameters:
19 =over 8
21 =item -D
23 a database parameter, which can either be "cxgn", "sandbox", or "trial". "cxgn" and "sandbox" will cause the script to connect to the respective databases; "trial" will connect to sandbox, but not perform any of the database modifications.
25 =item -H
27 host name
29 =item -m
31 map file. If provided links between stock names - image file name , is read from a mapping file.
32 Row labels are expected to be unique file names, column header for the associated stocks is 'name'
34 =item -i
36 a dirname that contains image filenames or subdirectories named after database accessions, containing one or more images (see option -d) .
38 =item -u
40 use name - from sgn_people.sp_person.
42 =item -b
44 the dir where the database stores the images (the concatenated values from image_path and image_dir from sgn_local.conf or sgn.conf)
46 =item -d
48 files are stored in sub directories named after database accessions
50 =item -e
52 image file extension . Defaults to 'jpg'
55 =item -t
57 trial mode . Nothing will be stored.
60 =back
62 The script will generate an error file, named like the filename supplied, with the extension .err.
64 =head1 AUTHOR(S)
66 Naama Menda (nm249@cornell.edu) October 2010.
67 Tweaks and move to sgn/bin: Lukas Mueller (lam87@cornell.edu) December 2023.
69 =cut
71 use strict;
73 use CXGN::Metadata::Schema;
74 use CXGN::Metadata::Metadbdata;
75 use CXGN::DB::InsertDBH;
76 use CXGN::Image;
77 use Bio::Chado::Schema;
78 use CXGN::People::Person;
79 use Carp qw /croak/;
80 use Data::Dumper qw / Dumper /;
82 use File::Basename;
83 use SGN::Context;
84 use Getopt::Std;
86 use CXGN::Tools::File::Spreadsheet;
87 use File::Glob qw | bsd_glob |;
89 our ($opt_H, $opt_D, $opt_t, $opt_i, $opt_u, $opt_r, $opt_d, $opt_e, $opt_m, $opt_b);
90 getopts('H:D:u:i:e:f:tdr:m:b:');
92 my $dbhost = $opt_H;
93 my $dbname = $opt_D;
94 my $dirname = $opt_i;
95 my $sp_person=$opt_u;
96 my $db_image_dir = $opt_b;
97 my $chado_table = $opt_r;
98 my $ext = $opt_e || 'jpg';
100 if (!$dbhost && !$dbname) {
101 print "dbhost = $dbhost , dbname = $dbname\n";
102 print "opt_t = $opt_t, opt_u = $opt_u, opt_r = $chado_table, opt_i = $dirname\n";
103 usage();
106 if (!$dirname) { print "dirname = $dirname\n" ; usage(); }
108 my $dbh = CXGN::DB::InsertDBH->new( { dbhost=>$dbhost,
109 dbname=>$dbname,
110 } );
112 my $schema= Bio::Chado::Schema->connect( sub { $dbh->get_actual_dbh() } , { on_connect_do => ['SET search_path TO public;'] }
116 print STDERR "Generate metadata_id... ";
117 my $metadata_schema = CXGN::Metadata::Schema->connect("dbi:Pg:database=$dbname;host=".$dbh->dbhost(), "postgres", $dbh->dbpass(), {on_connect_do => "SET search_path TO 'metadata', 'public'", });
119 my $sp_person_id= CXGN::People::Person->get_person_by_username($dbh, $sp_person);
120 my %name2id = ();
123 #my $ch = SGN::Context->new();
124 print "PLEASE VERIFY:\n";
125 print "Using dbhost: $dbhost. DB name: $dbname. \n";
126 print "Path to image is: $db_image_dir\n";
127 print "CONTINUE? ";
128 my $a = (<STDIN>);
129 if ($a !~ /[yY]/) { exit(); }
131 my %image_hash = (); # used to retrieve images that are already loaded
132 my %connections = (); # keep track of object -- image connections that have already been made.
134 print STDERR "Caching stock table...\n";
135 my $object_rs = $schema->resultset("Stock::Stock")->search( { } ) ;
136 while (my $object = $object_rs->next ) {
137 my $id = $object->stock_id;
138 my $name = $object->uniquename;
139 $name2id{lc($name)} = $id;
142 # cache image chado object - image links to prevent reloading of the
143 # same data
145 print "Caching image $chado_table links...\n";
147 my $q = "SELECT * FROM phenome.stock_image";
148 my $sth = $dbh->prepare($q);
149 $sth->execute();
150 while ( my $hashref = $sth->fetchrow_hashref() ) {
151 my $image_id = $hashref->{image_id};
152 my $chado_table_id = $hashref->{stock_id}; ##### table specific
154 print STDERR "\n\nCHADO TABLE ID = $chado_table_id\n\n";
156 my $i = CXGN::Image->new(dbh=>$dbh, image_id=>$image_id, image_dir=>$db_image_dir); # SGN::Image...$ch
157 my $original_filename = $i->get_original_filename();
158 $image_hash{$original_filename} = $i; # this doesn't have the file extension
159 $connections{$image_id."-".$chado_table_id}++;
162 #open (ERR, ">load_bcs_images.err") || die "Can't open error file\n";
164 my @files;
165 if (! $opt_d) {
166 @files = bsd_glob "$dirname/*.$ext";
168 else {
169 @files = bsd_glob "$dirname/*" if $opt_d ;
172 print STDERR "DIRS = ".(join("\n", @files))."\n";
174 my @sub_files;
176 my $new_image_count = 0;
178 my $metadata = CXGN::Metadata::Metadbdata->new($metadata_schema, $sp_person);
179 my $metadata_id = $metadata->store()->get_metadata_id();
181 #read from spreadsheet:
182 my $map_file = $opt_m; #
183 my %name_map;
185 if ($opt_m) {
186 my $s = CXGN::Tools::File::Spreadsheet->new($map_file); #
187 my @rows = $s->row_labels(); #
188 foreach my $file_name (@rows) { #
189 my $stock_name = $s->value_at($file_name, 'name'); #
190 $name_map{$file_name} = $stock_name;
194 print STDERR "Starting to process ".scalar(@files)." images...\n";
196 foreach my $file (@files) {
197 eval {
198 chomp($file);
199 @sub_files = ($file);
200 @sub_files = bsd_glob "$file/*"; # if $opt_d;
202 print STDERR "FILES FOR $file: ".Dumper(\@sub_files)."\n";
204 my $object = basename($file, ".$ext" );
206 # if (!$plot) { die "File $file has no object name in it!"; }
207 my $stock = $schema->resultset("Stock::Stock")->find( {
208 stock_id => $name2id{ lc($object) } } );
209 foreach my $filename (@sub_files) {
211 chomp $filename;
213 print STDERR "FILENAME NOW: $filename\n";
214 my $image_base = basename($filename);
215 my ($object_name, $description, $extension);
216 if ($opt_m) {
217 $object_name = $name_map{$object . "." . $ext } ;
220 print STDERR "OBJECT = $object...\n";
221 # if ($image_base =~ /(.*?)\_(.*?)(\..*?)?$/) {
222 if ($image_base =~ m/(.*)(\.$ext)/i) {
223 $extension = $2;
224 $image_base = $1;
226 if ($image_base =~ m/(.*)\_(.*)/) {
227 $object_name = $1;
228 $description = $2;
231 else {
232 $object_name = $image_base;
234 print STDERR "Object: $object OBJECT NAME: $object_name DESCRPTION: $description EXTENSIO: $extension\n";
237 print STDOUT "Processing file $file...\n";
238 print STDOUT "Loading $object_name, image $filename\n";
239 print STDERR "Loading $object_name, image $filename\n";
240 my $image_id; # this will be set later, depending if the image is new or not
241 if (! -e $filename) {
242 warn "The specified file $filename does not exist! Skipping...\n";
243 next();
246 if (!exists($name2id{lc($object)})) {
247 message ("$object does not exist in the database...\n");
250 else {
251 print STDERR "Adding $filename...\n";
252 if (exists($image_hash{$filename})) {
253 print STDERR "$filename is already loaded into the database...\n";
254 $image_id = $image_hash{$filename}->get_image_id();
255 $connections{$image_id."-".$name2id{lc($object)}}++;
256 if ($connections{$image_id."-".$name2id{lc($object)}} > 1) {
257 print STDERR "The connection between $object and image $filename has already been made. Skipping...\n";
259 elsif ($image_hash{$filename}) {
260 print STDERR qq { Associating $chado_table $name2id{lc($object)} with already loaded image $filename...\n };
263 else {
264 print STDERR qq { Generating new image object for image $filename and associating it with $chado_table $object, id $name2id{lc($object) } ...\n };
266 if ($opt_t) {
267 print STDOUT qq { Would associate file $filename to $chado_table $object_name, id $name2id{lc($object)}\n };
268 $new_image_count++;
270 else {
271 my $image = CXGN::Image->new(dbh=>$dbh, image_dir=>$db_image_dir);
272 $image_hash{$filename}=$image;
274 my $error;
275 ($image_id, $error) = $image->process_image("$filename", $chado_table , $name2id{lc($object)}, 1);
277 print STDERR "IMAGE ID $image_id, ERROR: $error\n";
279 if ($error eq "ok") {
282 $image->set_description("$description");
283 $image->set_name(basename($filename , ".$ext"));
284 $image->set_sp_person_id($sp_person_id);
285 $image->set_obsolete("f");
286 $image_id = $image->store();
287 #link the image with the BCS object
288 $new_image_count++;
289 my $image_subpath = $image->image_subpath();
290 print STDERR "FINAL IMAGE PATH = $db_image_dir/$image_subpath\n";
297 print STDERR "Connecting image $filename and id $image_id with stock ".$stock->stock_id()."\n";
298 #store the image_id - stock_id link
299 my $q = "INSERT INTO phenome.stock_image (stock_id, image_id, metadata_id) VALUES (?,?,?)";
300 my $sth = $dbh->prepare($q);
301 $sth->execute($stock->stock_id, $image_id, $metadata_id);
304 if ($@) {
305 print STDERR "ERROR OCCURRED WHILE SAVING NEW INFORMATION. $@\n";
306 $dbh->rollback();
308 else {
309 $dbh->commit();
316 #close(ERR);
317 close(F);
322 print STDERR "Inserted $new_image_count images.\n";
323 print STDERR "Done. \n";
325 sub usage {
326 print "Usage: load_images.pl -D dbname [ cxgn | sandbox ] -H dbhost -t [trial mode ] -i input dir -r chado table name for the object to link with the image \n";
327 exit();
330 sub message {
331 my $message=shift;
332 print STDERR $message;