diff --git a/README.md b/README.md index 66b1e2c..2ae20f4 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ During the test phase, input images of arbitrary size are processed. --label_map_path class_labels_car.pbtxt \ --train_model_path [ssd_train_path] \ --tf_cfg_train_file ssd_inception_v2_simrdwn.config \ - --use_tfrecords=1 \ + --use_tfrecords=0 \ --testims_dir cowc/Utah_AGRC \ --keep_test_slices 0 \ --test_slice_sep __ \ @@ -142,7 +142,7 @@ During the test phase, input images of arbitrary size are processed. # YOLT vehicle search python /raid/local/src/simrdwn/core/simrdwn.py \ - --framework yolt \ + --framework yolt2 \ --mode test \ --outname dense_cowc \ --label_map_path class_labels_car.pbtxt \ diff --git a/docker/Dockerfile b/docker/Dockerfile index 823c651..dbb86a0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,11 +2,6 @@ FROM nvidia/cuda:9.0-devel-ubuntu16.04 MAINTAINER avanetten -# nvidia-docker build -t simrdwn2.1 . # build (use existing packages) -# nvidia-docker build --no-cache -t simrdwn2.2 . # rebuild from scratch -# NV_GPU=0 nvidia-docker run -it -v /local_data:/local_data --name simrdwn2.2_gpu0 simrdwn2.2 -# NV_GPU=0 nvidia-docker run -it -v /local_data:/local_data -v /cosmiq:/cosmiq --name simrdwn2.1_gpu0 simrdwn2.1 - # IF YOU WANT PROGRESS PRINTED TO TERMINAL # Update model_main to log to screen... # https://stackoverflow.com/questions/52016255/tensorflow-object-detection-api-not-displaying-global-steps @@ -73,78 +68,84 @@ SHELL ["/bin/bash", "-c"] ENV PATH /opt/conda/bin:$PATH # install anaconda -RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-4.5.4-Linux-x86_64.sh -O ~/miniconda.sh && \ +# https://repo.continuum.io/miniconda/ +RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-4.6.14-Linux-x86_64.sh -O ~/miniconda.sh && \ /bin/bash ~/miniconda.sh -b -p /opt/conda && \ rm ~/miniconda.sh && \ /opt/conda/bin/conda clean -tipsy && \ ln -s /opt/conda/etc/profile.d/conda.sh /etc/profile.d/conda.sh && \ echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc && \ echo "conda activate base" >> ~/.bashrc -ENV TINI_VERSION v0.16.1 +# ENV TINI_VERSION v0.16.1 +ENV TINI_VERSION v0.18.0 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini RUN chmod +x /usr/bin/tini # use conda-forge instead of default channel -RUN conda update conda && \ - conda config --remove channels defaults && \ - conda config --add channels conda-forge +RUN conda config --add channels conda-forge + # && \ + # conda update conda + # conda config --remove channels defaults && \ # set up conda environment and add to $PATH -RUN conda create -n simrdwn2 python=3.6 \ - && echo "source activate simrdwn2" > ~/.bashrc -ENV PATH /opt/conda/envs/simrdwn2/bin:$PATH +RUN conda create -n simrdwn python=3.6 \ + && echo "source activate simrdwn" > ~/.bashrc +ENV PATH /opt/conda/envs/simrdwn/bin:$PATH # install GPU version of tensorflow -RUN source activate simrdwn2 && \ - conda install -n simrdwn2 -c defaults tensorflow-gpu=1.13.1 +RUN source activate simrdwn && \ + conda install -n simrdwn -c defaults tensorflow-gpu=1.13.1 # install keras with tf backend ENV KERAS_BACKEND=tensorflow -RUN source activate simrdwn2 \ - && conda install -n simrdwn2 keras - -RUN conda install -n simrdwn2 \ - #awscli \ - affine \ - pyproj \ +RUN source activate simrdwn \ + && conda install -n simrdwn keras=2.2.4 + +RUN source activate simrdwn \ + && conda install -n simrdwn \ + libgdal=2.4.1 \ + gdal=2.4.1 \ + geopandas=0.5.0 \ + opencv=4.1.0 \ + affine=2.2.2 \ + pyproj=2.1.3 \ pyhamcrest=1.9.0 \ - cython \ - contextlib2 \ - fiona \ - h5py \ - ncurses \ - jupyter \ - jupyterlab \ - ipykernel \ - libgdal \ - matplotlib \ - ncurses \ - numpy \ - #opencv=3.4.1 \ - #py-opencv \ - pandas \ - pillow \ - pip \ - scipy \ - scikit-image \ - scikit-learn \ - shapely \ - gdal \ - rtree \ - testpath \ - tqdm \ - pandas \ - geopandas \ - rasterio \ - opencv=4.0.0 \ + cython=0.29.10 \ + contextlib2=0.5.5 \ + h5py=2.9.0 \ + ncurses=6.1 \ + jupyter=1.0.0 \ + jupyterlab=0.35.6 \ + ipykernel=5.1.1 \ + matplotlib=3.1.0 \ + numpy=1.16.4 \ + pandas=0.24.2 \ + pillow=6.0.0 \ + pip=19.1.1 \ + scipy=1.3.0 \ + scikit-image=0.15.0 \ + scikit-learn=0.21.2 \ + shapely=1.6.4 \ + rtree=0.8.3 \ + testpath=0.4.2 \ + tqdm=4.32.1 \ + statsmodels=0.10.1 \ && conda clean -p \ && conda clean -t \ && conda clean --yes --all -RUN pip install statsmodels +# Below is a hack to get around conda issues (2019-07-19) +RUN source activate simrdwn \ + && conda install -n simrdwn \ + -c conda-forge rasterio=1.0.24 \ + && conda clean -p \ + && conda clean -t \ + && conda clean --yes --all # tf object detection api RUN git clone https://github.com/tensorflow/models.git /tensorflow/models +WORKDIR /tensorflow/models/research/ +RUN git checkout r1.13.0 #WORKDIR /tensorflow/models/research/ #RUN protoc object_detection/protos/*.proto --python_out=. # WORKDIR /tensorflow/models/research/ @@ -167,8 +168,28 @@ RUN export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim ENV PYTHONPATH $PYTHONPATH:/tensorflow/models/:/tensorflow/models/slim ENV PYTHONPATH $PYTHONPATH:/tensorflow/models/:/tensorflow/models/research/slim +# # this always seems to fail, so do it manually (as above) +# RUN git clone https://github.com/cocodataset/cocoapi.git /cocoapi +# WORKDIR /cocoapi/PythonAPI +# RUN make +# RUN cp -r pycocotools /tensorflow/models/research/ +# # From tensorflow/models/research/ +# WORKDIR /tensorflow/models/research/ +# RUN protoc object_detection/protos/*.proto --python_out=. + +# # test +# WORKDIR /tensorflow/models/research/ +# RUN PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim +# RUN python /tensorflow/models/research/object_detection/builders/model_builder_test.py +# +# # RUN source activate simrdwn && \ +# # python /tensorflow/models/research/object_detection/builders/model_builder_test.py +# # # ENV MODELS_DIR /tensorflow/models/research/ +# # # PYTHONPATH=${MODELS_DIR}/research:$MODELS_DIR/research/slim \ +# # #PYTHON $MODELS_DIR/research/object_detection/builders/model_builder_test.py + # # add a jupyter kernel for the conda environment in case it's wanted -RUN source activate simrdwn2 && python -m ipykernel.kernelspec +RUN source activate simrdwn && python -m ipykernel.kernelspec RUN python -m ipykernel.kernelspec diff --git a/simrdwn/core/add_geo_coords.py b/simrdwn/core/add_geo_coords.py index aff543e..ba782be 100644 --- a/simrdwn/core/add_geo_coords.py +++ b/simrdwn/core/add_geo_coords.py @@ -185,9 +185,12 @@ def add_geo_coords_to_df(df_, inProj_str='epsg:4326', outProj_str='epsg:3857', # raster geo transform gdal_geomTransform = gdal.Open(raster_loc).GetGeoTransform() affineObject = rio.open(raster_loc).transform + if verbose: print("raster_loc:", raster_loc) print("gdal_geomTransform:", gdal_geomTransform) + print("gdal_geomTransform == (0.0, 1.0, 0.0, 0.0, 0.0, 1.0))", + gdal_geomTransform == (0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) print("affineObject:", affineObject) geo_dict[raster_loc] = [gdal_geomTransform, affineObject] @@ -204,14 +207,21 @@ def add_geo_coords_to_df(df_, inProj_str='epsg:4326', outProj_str='epsg:3857', row['Xmin_Glob'], row['Ymin_Glob'], row['Xmax_Glob'], row['Ymax_Glob']) - out_arr_row, poly_geo = get_row_geo_coords( - row, affineObject=affineObject, - gdal_geomTransform=gdal_geomTransform, - inProj_str=inProj_str, outProj_str=outProj_str, - verbose=verbose) - out_arr.append(out_arr_row) - if create_geojson: - out_arr_json.append(poly_geo) + # check if the the image as geographic metadata + if gdal_geomTransform == (0.0, 1.0, 0.0, 0.0, 0.0, 1.0): + out_arr_row = 8 * [0] + out_arr.append(out_arr_row) + + # else, get geo locations + else: + out_arr_row, poly_geo = get_row_geo_coords( + row, affineObject=affineObject, + gdal_geomTransform=gdal_geomTransform, + inProj_str=inProj_str, outProj_str=outProj_str, + verbose=verbose) + out_arr.append(out_arr_row) + if create_geojson: + out_arr_json.append(poly_geo) # update dataframe # [lon0, lat0, lon1, lat1, x0_wmp, y0_wmp, x1_wmp, y1_wmp] @@ -227,7 +237,7 @@ def add_geo_coords_to_df(df_, inProj_str='epsg:4326', outProj_str='epsg:3857', # geodataframe if desired # https://gis.stackexchange.com/questions/174159/convert-a-pandas-dataframe-to-a-geodataframe - if create_geojson: + if create_geojson and (len(out_arr_json) > 0): crs_init = {'init': inProj_str} df_json = pd.DataFrame(out_arr_json, columns=['geometry']) # add important columns to df_json diff --git a/simrdwn/core/infer_detections.py b/simrdwn/core/infer_detections.py index 89c5329..0df635d 100644 --- a/simrdwn/core/infer_detections.py +++ b/simrdwn/core/infer_detections.py @@ -68,8 +68,7 @@ tf.flags.DEFINE_string('inference_graph', None, 'Path to the inference graph with embedded weights.') tf.flags.DEFINE_boolean('verbose', False, 'Lots o print statements') -tf.flags.DEFINE_boolean('use_tfrecords', True, 'Switch to use tfrecords') - +tf.flags.DEFINE_boolean('use_tfrecords', False, 'Switch to use tfrecords') # tfrecords tf.flags.DEFINE_string('input_tfrecord_paths', None, @@ -97,8 +96,8 @@ tf.flags.DEFINE_integer('BGR2RGB', 0, 'Sometimes we need to change cv2 images to BGR') - FLAGS = tf.flags.FLAGS +# print("FLAGS:", FLAGS) ############################################################################### @@ -166,7 +165,7 @@ def main(_): str(t1 - t0) + ' seconds') else: - + # infer on csv if FLAGS.verbose: print("min_thresh:", FLAGS.min_thresh) t0 = time.time() @@ -180,7 +179,7 @@ def main(_): tf.import_graph_def(graph_def, name='') print("Time to load graph:", time.time() - t0, "seconds") - with open(FLAGS.output_csv_path, 'wb') as csvfile: + with open(FLAGS.output_csv_path, 'w') as csvfile: csvwriter = csv.writer(csvfile, delimiter=',') output_columns = ['Loc_Tmp', u'Prob', u'Xmin', u'Ymin', u'Xmax', u'Ymax', u'Category'] @@ -196,9 +195,19 @@ def main(_): line_count = 0 for i, image_path in enumerate(image_paths): - image_root = os.path.basename(image_path).strip() - image_bgr = cv2.imread(image_path.strip(), 1) + # print("image_path:", image_path) + # print("str image_path.strip", str(image_path.strip())) + # print("image_path.strip", image_path.strip().decode('utf-8')) + #print("str image_path.strip", str(image_path.strip().decode('utf-8'))) + # print("os.path.exists image_path.strip", os.path.exists(image_path.strip())) + # print("os.path.exists str image_path.strip", os.path.exists(str(image_path.strip()))) + # print("os.path.exists str image_path.strip", os.path.exists(str(image_path.strip()).strip())) + # print("os.path.exists str image_path.strip", os.path.exists(str(image_path.strip().decode('utf-8')))) + + # image_bgr = cv2.imread(image_path, cv2.IMREAD_COLOR) + # image_bgr = cv2.imread(str(image_path.strip()), 1) + image_bgr = cv2.imread(str(image_path.strip().decode('utf-8')), 1) # invert colors, if required if FLAGS.BGR2RGB == 1: image = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) diff --git a/simrdwn/core/post_process.py b/simrdwn/core/post_process.py index 3c66357..bb89ade 100755 --- a/simrdwn/core/post_process.py +++ b/simrdwn/core/post_process.py @@ -548,6 +548,8 @@ def refine_df(df, groupby='Image_Path', if verbose: print("num boxes_all:", len(xmins)) print("num good_idxs:", len(good_idxs)) + if len(boxes) == 0: + print("Error, No boxes detected!") boxes = boxes[good_idxs] scores = scores[good_idxs] df_idxs = df_idxs[good_idxs] diff --git a/simrdwn/core/simrdwn.py b/simrdwn/core/simrdwn.py index 925d014..173ecda 100755 --- a/simrdwn/core/simrdwn.py +++ b/simrdwn/core/simrdwn.py @@ -122,7 +122,8 @@ def update_args(args): args.test_tfrecord_out = os.path.join( args.results_dir, 'predictions.tfrecord') else: - args.test_presliced_tfrecord_tot, args.test_tfrecord_out = '', '' + args.test_presliced_tfrecord_tot = '' + args.test_tfrecord_out = '' if len(args.test_presliced_list) > 0: args.test_splitims_locs_file = args.test_presliced_list_tot @@ -161,7 +162,7 @@ def update_args(args): args.weight_file_tot = os.path.join( args.results_topdir, args.train_model_path, args.weight_file) args.tf_cfg_train_file = os.path.join( - args.results_topdir, args.train_model_path, 'logs', + args.results_topdir, args.train_model_path, # 'logs', args.tf_cfg_train_file) # assume weights and cfg are in the training dir @@ -183,7 +184,6 @@ def update_args(args): args.train_tf_record = os.path.join( args.train_data_dir, args.train_tf_record) - ########################## # set tf cfg file out tf_cfg_base = os.path.basename(args.tf_cfg_train_file) @@ -572,7 +572,7 @@ def tf_infer_cmd_dual(inference_graph_path='', input_file_list='', in_tfrecord_path='', out_tfrecord_path='', - use_tfrecords=1, + use_tfrecords=0, min_thresh=0.05, GPU=0, BGR2RGB=0, @@ -594,19 +594,21 @@ def tf_infer_cmd_dual(inference_graph_path='', 'python', infer_src_path + '/' + 'infer_detections.py', '--inference_graph=' + inference_graph_path, - '--GPU=' + str(GPU), - '--use_tfrecord=' + str(use_tfrecords), - + '--GPU=' + str(GPU) + ] + if bool(use_tfrecords): + cmd_arg_list.extend(['--use_tfrecord=' + str(use_tfrecords)]) + + cmd_arg_list.extend([ # first method, with tfrecords '--input_tfrecord_paths=' + in_tfrecord_path, '--output_tfrecord_path=' + out_tfrecord_path, - # second method, with file list '--input_file_list=' + input_file_list, '--BGR2RGB=' + str(BGR2RGB), '--output_csv_path=' + output_csv_path, '--min_thresh=' + str(min_thresh) - ] + ]) cmd = ' '.join(cmd_arg_list) return cmd @@ -1019,6 +1021,8 @@ def run_test(framework='YOLT2', t0 = time.time() # run command + print("Running", infer_cmd) + os.system('echo ' + infer_cmd + ' >> ' + log_file) os.system(infer_cmd) # run_cmd(outcmd) t1 = time.time() cmd_time_str = '"\nLength of time to run command: ' + infer_cmd \ @@ -1472,7 +1476,9 @@ def execute(args, train_cmd1, test_cmd_tot, test_cmd_tot2=''): zero_frac_thresh=args.zero_frac_thresh, ) # return if only interested in prepping - if bool(args.test_prep_only): + if (bool(args.test_prep_only)) \ + and (bool(args.use_tfrecords)): + # or (args.framework.upper() not in ['YOLT2', 'YOLT3']): print("Convert to tfrecords...") TF_RecordPath = os.path.join( args.results_dir, 'test_splitims.tfrecord') @@ -1481,7 +1487,6 @@ def execute(args, train_cmd1, test_cmd_tot, test_cmd_tot2=''): args.label_map_dict, TF_RecordPath, TF_PathVal='', val_frac=0.0, convert_dict={}, verbose=False) - print("Done prepping test files, ending") return @@ -1668,7 +1673,7 @@ def execute(args, train_cmd1, test_cmd_tot, test_cmd_tot2=''): print("Num objects at thresh:", plot_thresh_tmp, "=", len(df_refine)) # save json - if bool(args.save_json): + if bool(args.save_json) and (len(json) > 0): output_json_path = os.path.join(args.results_dir, args.val_prediction_df_refine_tot_root_part + '_thresh=' + str(plot_thresh_tmp) + '.GeoJSON') @@ -1772,7 +1777,7 @@ def main(): # test settings parser.add_argument('--train_model_path', type=str, default='', help="Location of trained model") - parser.add_argument('--use_tfrecords', type=int, default=1, + parser.add_argument('--use_tfrecords', type=int, default=0, help="Switch to use tfrecords for inference") parser.add_argument('--test_presliced_tfrecord_path', type=str, default='', help="Location of presliced training data tfrecord " diff --git a/simrdwn/data_prep/prep_data_cowc.py b/simrdwn/data_prep/prep_data_cowc.py index 2ffef36..2246538 100644 --- a/simrdwn/data_prep/prep_data_cowc.py +++ b/simrdwn/data_prep/prep_data_cowc.py @@ -47,15 +47,6 @@ # label_path_root = '/local_data/simrdwn3/data/train_data' # test_out_dir = '/local_data/simrdwn3/data/test_images/cowc' - -# dev box -# cowc_data_dir = '/raid/data/gdo152.ucllnl.org/cowc/datasets/ground_truth_sets/' -# simrdwn_data_dir = '/raid/simrdwn/data/' -# train_out_dir = '/raid/simrdwn/training_datasets/cowc/' -# test_out_dir = '/raid/simrdwn/test_images/cowc/' -# label_map_file = 'class_labels_car.pbtxt' -# verbose = True - label_map_path = os.path.join(label_path_root, label_map_file) print ("label_map_path:", label_map_path)