From 7e79f15d2ff4b2cee2bd87eed1c57fdb2a963116 Mon Sep 17 00:00:00 2001 From: Trey Smith Date: Thu, 1 Aug 2024 10:46:36 -0400 Subject: [PATCH] Overhaul pano stitching and viewer interface (#173) --- pano/README.md | 7 +- pano/docker/pano.Dockerfile | 37 +- pano/docker/run.sh | 1 + pano/pano_stitch/scripts/pano_image_meta.py | 7 +- pano/pano_view/CMakeLists.txt | 2 +- .../config/phase1x_inspection_results.config | 183 ++++++++++ pano/pano_view/media/camera_highlight.png | Bin 0 -> 8997 bytes .../media/favicon/favicon-128x128.png | Bin 0 -> 9511 bytes .../pano_view/media/favicon/favicon-16x16.png | Bin 0 -> 687 bytes .../media/favicon/favicon-192x192.png | Bin 0 -> 22026 bytes .../media/favicon/favicon-196x196.png | Bin 0 -> 16460 bytes .../media/favicon/favicon-228x228.png | Bin 0 -> 28250 bytes .../pano_view/media/favicon/favicon-32x32.png | Bin 0 -> 1702 bytes .../pano_view/media/favicon/favicon-57x57.png | Bin 0 -> 5218 bytes .../pano_view/media/favicon/favicon-76x76.png | Bin 0 -> 7321 bytes .../pano_view/media/favicon/favicon-96x96.png | Bin 0 -> 6603 bytes pano/pano_view/media/inspection.png | Bin 0 -> 9032 bytes pano/pano_view/scripts/generate_tour.py | 56 ++- pano/pano_view/scripts/prep_source_images.py | 45 ++- pano/pano_view/static/css/isaac_pano.css | 34 +- pano/pano_view/static/js/isaac_pano.js | 301 ++++++++++++---- .../pano_view/static/js/isaac_source_image.js | 338 +++++++++++++----- pano/pano_view/templates/help.html | 112 ++++++ pano/pano_view/templates/index.html | 2 +- .../templates/isaac_source_image.html | 47 ++- pano/pano_view/templates/pannellum.htm | 34 -- pano/pano_view/templates/pannellum.html | 60 ++++ 27 files changed, 1031 insertions(+), 235 deletions(-) create mode 100644 pano/pano_view/config/phase1x_inspection_results.config create mode 100644 pano/pano_view/media/camera_highlight.png create mode 100755 pano/pano_view/media/favicon/favicon-128x128.png create mode 100755 pano/pano_view/media/favicon/favicon-16x16.png create mode 100755 pano/pano_view/media/favicon/favicon-192x192.png create mode 100755 pano/pano_view/media/favicon/favicon-196x196.png create mode 100755 pano/pano_view/media/favicon/favicon-228x228.png create mode 100755 pano/pano_view/media/favicon/favicon-32x32.png create mode 100755 pano/pano_view/media/favicon/favicon-57x57.png create mode 100755 pano/pano_view/media/favicon/favicon-76x76.png create mode 100755 pano/pano_view/media/favicon/favicon-96x96.png create mode 100644 pano/pano_view/media/inspection.png create mode 100644 pano/pano_view/templates/help.html delete mode 100644 pano/pano_view/templates/pannellum.htm create mode 100644 pano/pano_view/templates/pannellum.html diff --git a/pano/README.md b/pano/README.md index 3485af31..edb34f77 100644 --- a/pano/README.md +++ b/pano/README.md @@ -148,8 +148,11 @@ Note that some of the individual steps within each panorama stitch (e.g., `enble ### View the tour -TODO +In the host OS, point a web browser at `http://127.0.0.1:8080/`. The `run.sh` script forwards port 8080 of the host to port 80 of the container, where an Apache server is running to provide a preview of the tour. +### Install the tour + +Recursively copy the `$ISAAC_PANO_OUTPUT/html` folder wherever you want on your web server. Make sure permissions are set to enable your users to access files in the folder. No special configuration should be needed as long as the server is configured to serve static files with the appropriate MIME types. None of the application logic runs on the web server; the viewing interfaces run completely in the browser. When users make annotations, they will be stored locally in the user's web browser, not on the web server. ### Generate target pose from image @@ -185,4 +188,4 @@ An example output would be: Things to look for are that the timestamps are not too large, this would mean that results are unreliable. Pay attention to the point cloud point to vector distance to make sure that the point is not too far away from the target vector, meaning that the point cloud does not include the target which is possible due to different field of views between the cameras. -Lastly the mesh and pcl should not disagree, if they do, some manual analysis is needed. Be aware that the attitude provided is defined by the direction pointing at the target assuming roll zero. \ No newline at end of file +Lastly the mesh and pcl should not disagree, if they do, some manual analysis is needed. Be aware that the attitude provided is defined by the direction pointing at the target assuming roll zero. diff --git a/pano/docker/pano.Dockerfile b/pano/docker/pano.Dockerfile index ea986cd4..80017faa 100644 --- a/pano/docker/pano.Dockerfile +++ b/pano/docker/pano.Dockerfile @@ -4,29 +4,37 @@ ARG REMOTE=ghcr.io/nasa FROM ${REMOTE}/isaac:latest-ubuntu${UBUNTU_VERSION} +# apache2: Local web server for previewing pano tour interface # default-jre: Java runtime needed for minifying Pannellum web files # hugin: pano stitching tools (and hsi Python interface) # libvips-tools: convert images to multires, zoomable in OpenSeaDragon # python3-pip: for installing Python packages later in this Dockerfile RUN apt-get update \ && apt-get install -y --no-install-recommends \ + apache2 \ default-jre \ + gfortran \ hugin \ + libfftw3-dev \ + libopenblas-dev \ libvips-tools \ python3-pip \ - gfortran libopenblas-dev libfftw3-dev \ && rm -rf /var/lib/apt/lists/* -# pandas: pulled in as pyshtools dependency but install breaks if not mentioned explicitly (?) -# pyshtools: used during Pannellum multires generation -# snakemake: modern build system based on Python, manages stitching workflows - # Install Jupyter explicitly first -RUN pip3 install --no-cache-dir --upgrade pip && \ - pip3 install --no-cache-dir jupyter +RUN pip3 install --no-cache-dir --upgrade pip \ + && pip3 install --no-cache-dir jupyter # Install other Python packages: jupyter package needs to be installed before attempting to build pyshtools -RUN pip3 install --no-cache-dir pandas pyshtools snakemake pulp==2.7 --ignore-installed PyYAML +# - pandas: pulled in as pyshtools dependency but install breaks if not mentioned explicitly (?) +# - pyshtools: used during Pannellum multires generation +# - snakemake: modern build system based on Python, manages stitching workflows +RUN pip3 install --no-cache-dir \ + --ignore-installed PyYAML \ + pandas \ + pulp==2.7 \ + pyshtools \ + snakemake # pannellum: library for viewing/navigating panorama tours RUN mkdir -p /opt \ @@ -73,3 +81,16 @@ RUN echo 'source "/src/isaac/devel/setup.bash"\nexport ASTROBEE_CONFIG_DIR="/src # once new pano folder is merged into develop and official docker # images are updated. RUN echo 'export ROS_PACKAGE_PATH="${ROS_PACKAGE_PATH}:/src/isaac/src/pano/pano_stitch::/src/isaac/src/pano/pano_view"' >> "${HOME}/.bashrc" + +# This is a bit unusual, but starting apache in .bashrc ensures it's +# running whenever we run an interactive session using +# run.sh. (Running it multiple times doesn't cause a problem.) +RUN echo 'apachectl start' >> "${HOME}/.bashrc" + +# Make /output/html the DocumentRoot for the apache2 debug web server +RUN perl -i -ple 's:/var/www:/output:g' \ + /etc/apache2/apache2.conf \ + /etc/apache2/sites-available/000-default.conf + +# Expose local web server for pano tour preview +EXPOSE 80 diff --git a/pano/docker/run.sh b/pano/docker/run.sh index f6513fb2..2879e59d 100755 --- a/pano/docker/run.sh +++ b/pano/docker/run.sh @@ -20,4 +20,5 @@ docker run \ --mount type=bind,source=${ISAAC_PANO_INPUT},target=/input,readonly \ --mount type=bind,source=${ISAAC_PANO_OUTPUT},target=/output \ --mount type=bind,source=${ISAAC_SRC},target=/src/isaac/src \ + -p 127.0.0.1:8080:80 \ isaac/pano diff --git a/pano/pano_stitch/scripts/pano_image_meta.py b/pano/pano_stitch/scripts/pano_image_meta.py index b20934cd..c8c1f6f3 100755 --- a/pano/pano_stitch/scripts/pano_image_meta.py +++ b/pano/pano_stitch/scripts/pano_image_meta.py @@ -26,7 +26,7 @@ import rosbag from tf.transformations import euler_from_quaternion -IMAGE_TOPIC = ["/hw/cam_sci/compressed", "/hw/cam_sci_info"] +IMAGE_TOPICS = ["/hw/cam_sci/compressed", "/hw/cam_sci_info"] POSE_TOPIC = "/loc/pose" FIELD_NAMES = ( "timestamp", @@ -50,9 +50,8 @@ def get_image_meta(inbag_path, num_images=None): images = [] with rosbag.Bag(inbag_path) as bag: img_meta = None - topics = IMAGE_TOPIC + [POSE_TOPIC] - for topic, msg, t in bag.read_messages(topics): - if topic in IMAGE_TOPIC: + for topic, msg, t in bag.read_messages([*IMAGE_TOPICS, POSE_TOPIC]): + if topic in IMAGE_TOPICS: if num_images is not None and len(images) == num_images: break diff --git a/pano/pano_view/CMakeLists.txt b/pano/pano_view/CMakeLists.txt index 0c727839..d0251ffd 100644 --- a/pano/pano_view/CMakeLists.txt +++ b/pano/pano_view/CMakeLists.txt @@ -82,7 +82,7 @@ add_dependencies(point_cloud_intersect ${catkin_EXPORTED_TARGETS}) target_link_libraries(point_cloud_intersect ${catkin_LIBRARIES}) -## Declare a C++ executable: find_point_coordinate +## Declare a C++ executable: find_point_coordinate add_executable(find_point_coordinate tools/find_point_coordinate.cc) add_dependencies(find_point_coordinate ${catkin_EXPORTED_TARGETS}) target_link_libraries(find_point_coordinate mesh_intersect point_cloud_intersect diff --git a/pano/pano_view/config/phase1x_inspection_results.config b/pano/pano_view/config/phase1x_inspection_results.config new file mode 100644 index 00000000..2e9d3bc6 --- /dev/null +++ b/pano/pano_view/config/phase1x_inspection_results.config @@ -0,0 +1,183 @@ +# ====================================================================== +# The content below the line is from the file +# isaac/src/pano/pano_view/config/phase1x_inspection_results.config +# and is designed to be copy/pasted at the bottom of pano_meta.yaml. + +# How inspection_results was generated: The photos were manually +# selected from all hatch seal targeted inspection photos to be the +# best ones (at most one from each focus stack) for showing +# recognizable damage sites. Pitch/yaw values for each image were +# manually selected using the Pannellum hotSpotDebug feature. +inspection_results: + scene001_isaac11_bumble_usl_bay6: + # ISAAC11 USL aft hatch seal inspection + - pitch: -19.496113033067832 + yaw: -178.49501734467697 + image: /input/inspection_results/isaac11_usl_aft/1657549131.173.jpg + slug: Hatch Seal ISAAC16 USL AFT + + scene004_isaac11_queen_usl_bay1: + # ISAAC16 USL forward hatch seal deck section positions, numbered 0 .. 3 port -> starboard + # Only position 1 has a recognizable damage site, leaving out the others + + #- pitch: -23.829139007892287 + # yaw: -9.57794857674467 + # image: /input/inspection_results/isaac16_usl_fwd/1720198615.236.jpg + # slug: Hatch Seal ISAAC16 USL FWD 0 + - pitch: -24.233722398730837 + yaw: -2.3869610431019694 + image: /input/inspection_results/isaac16_usl_fwd/1720199288.313.jpg + slug: Hatch Seal ISAAC16 USL FWD 1 + #- pitch: -24.210064732216285 + # yaw: 6.143908859653246 + # image: /input/inspection_results/isaac16_usl_fwd/1720199367.399.jpg + # slug: Hatch Seal ISAAC16 USL FWD 2 + #- pitch: -24.167778451658435 + # yaw: 10.29111636247168 + # image: /input/inspection_results/isaac16_usl_fwd/1720199447.824.jpg + # slug: Hatch Seal ISAAC16 USL FWD 3 + + # ISAAC11 USL forward hatch seal inspection + - pitch: -24.233722398730837 + yaw: -1 + image: /input/inspection_results/isaac11_usl_fwd/1657551186.506.jpg + slug: Hatch Seal ISAAC11 USL FWD + +# How initial_annotations was generated: I used the existing target +# selection feature to annotate the (somewhat) recognizable damage +# sites, saved the results, and simply copy/pasted the file contents +# here. Conveniently, YAML is a superset of the JSON format used for +# the annotations, so it was already valid YAML (even if the style +# clashes with the one used above). +initial_annotations: { + "scene004_isaac11_queen_usl_bay1": { + "1720199288.313": [ + { + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [ + { + "type": "TextualBody", + "value": "A: Divot on Inner Seal", + "purpose": "commenting" + } + ], + "target": { + "source": "http://localhost:8080/src/undefined", + "selector": { + "type": "FragmentSelector", + "conformsTo": "http://www.w3.org/TR/media-frags/", + "value": "xywh=pixel:3449.820556640625,1809.1005859375,52.701171875,39.3167724609375" + } + }, + "id": "#5e67f4b4-86ed-4eaf-9bf2-caeac4358691" + }, + { + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [ + { + "type": "TextualBody", + "value": "B: Cut on Inner Seal", + "purpose": "commenting" + } + ], + "target": { + "source": "http://localhost:8080/src/undefined", + "selector": { + "type": "FragmentSelector", + "conformsTo": "http://www.w3.org/TR/media-frags/", + "value": "xywh=pixel:3723.783203125,1791.1153564453125,124.642333984375,58.97509765625" + } + }, + "id": "#f5f60596-a44a-48d2-aafb-49d63621bd20" + } + ], + "1657551186.506": [ + { + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [ + { + "type": "TextualBody", + "value": "B: Cut on Inner Seal", + "purpose": "commenting" + } + ], + "target": { + "source": "http://localhost:8080/src/undefined", + "selector": { + "type": "FragmentSelector", + "conformsTo": "http://www.w3.org/TR/media-frags/", + "value": "xywh=pixel:3658.030517578125,2492.563720703125,110.6806640625,51.651123046875" + } + }, + "id": "#5a8d060a-259e-47f9-9b42-519a09246897" + }, + { + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [ + { + "type": "TextualBody", + "value": "A: Divot on Inner Seal", + "purpose": "commenting" + } + ], + "target": { + "source": "http://localhost:8080/src/undefined", + "selector": { + "type": "FragmentSelector", + "conformsTo": "http://www.w3.org/TR/media-frags/", + "value": "xywh=pixel:3269.641845703125,2496.58837890625,52.992431640625,42.930908203125" + } + }, + "id": "#49a5daa0-41c1-4856-b21b-09164687415a" + } + ] + }, + "scene001_isaac11_bumble_usl_bay6": { + "1657549131.173": [ + { + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [ + { + "type": "TextualBody", + "value": "F: Divot and Cut on Inner Seal", + "purpose": "commenting" + } + ], + "target": { + "source": "http://localhost:8080/src/undefined", + "selector": { + "type": "FragmentSelector", + "conformsTo": "http://www.w3.org/TR/media-frags/", + "value": "xywh=pixel:2259.4794921875,2235.703125,56.346435546875,41.589111328125" + } + }, + "id": "#0b8ab636-3697-425a-b683-089712796e24" + }, + { + "@context": "http://www.w3.org/ns/anno.jsonld", + "type": "Annotation", + "body": [ + { + "type": "TextualBody", + "value": "G: Divot on Inner Seal", + "purpose": "commenting" + } + ], + "target": { + "source": "http://localhost:8080/src/undefined", + "selector": { + "type": "FragmentSelector", + "conformsTo": "http://www.w3.org/TR/media-frags/", + "value": "xywh=pixel:2729.704833984375,2227.653564453125,63.72509765625,38.906005859375" + } + }, + "id": "#84eb0fa7-4601-43e1-a900-46077fc93c4a" + } + ] + } +} diff --git a/pano/pano_view/media/camera_highlight.png b/pano/pano_view/media/camera_highlight.png new file mode 100644 index 0000000000000000000000000000000000000000..6c742bd0254a3154818baa92028c701e2310f1c6 GIT binary patch literal 8997 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 V*d3ZxJ(>Uj002ovPDHLkV1g$&C}RKs literal 0 HcmV?d00001 diff --git a/pano/pano_view/media/favicon/favicon-192x192.png b/pano/pano_view/media/favicon/favicon-192x192.png new file mode 100755 index 0000000000000000000000000000000000000000..39a0e8e8a31e0946dc9fdd78f806a71bcca7f29d GIT binary patch literal 22026 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
pb48wg5zL_TDAwU`j z7eF*U$Wnf!UUbosoNM#e?uB6R4eYMJ7u4|BK4puIYJMf|hvgtS7k>q1Hi>?gI?89M zM%n#Oo2?QWhV^ywAvbM}$JdrM%x~A8%yziMKO$Q?Uf*jFq{a|)NLk6Mb2+dU^}o=U z&1XK6OHsslWGnb*rX8_tz#Fo^kXQDTc$@^|%Hr9`T|$ri~7iDHVaX~K#rsb zB>3T3Ge*oIvrt2}skAU_o-SgM(2DIn)9O%52qxn(q5bZF`!Zxa2(K%=h;kcH*9w;J& zfx@93Ik>kZ0p>Uhk&)8&hqq@*SaW(Hp+~))wr5y7jchpLD&R35d6|=yD0{|&gp6rS zd(+00D5UMFhxb{+zJQ_g)_sM(2?f6P( zG5W#O6_^XkUu+As!t>Z~s9O%(!Xnj*?oT*VhC}!&u?>2zR%D&b-46fItD?u)@sFsr z6YFs2NMMha)ibM zmkHrat{B&rsJc)siTCPWJr1Mh;hF95a-g*fyhwb??Z09JB_P(JYD9ctf59T&u;ykZ z5O#3!XDYUoQxs6w;C9!t|t_9ypqv4Bp>q zLIBl`Y@VikHPBLS^%ffU)W{l0U;*1icJI~v?YnpLZr#cK2yB*-GpJf7*Sto)!?R9o zOa9I7;BvVa30flPzu7Cn>c9`?ElOvDP(bH)E#`uzr<$XS?Tg4EJ0!j|1?Z;gC3iss zXhDhV>WLe)8|2JTQ^cDlP`q7NZwwmPXBXyH1#w!eRUFa*JOJx4S;_LiITREwKUfVz z8;Y}4#erHrvX_5?Y{vusI?kzbkP1p03*=(p)8-QP%2vBN8K}qC!5IFAdtKM{*MBJk ztf$-mdPl2h_XLwinwyqjZtkY={9pk9jpV9=8xf@n2C-aTrPwPXcjo7y@;WqU-ITzAjsyqVb!(BU6ixNc2;i& z9&+_tdvHoJUA|jl?qh>6*V&5dHBUS`zBA1-*2v^~^~X9?eq z;uBW4;ipd!R5M{HUcc<@XTRWQ6MO<%6;qMG9F8Y$x#T>{R;3m7)q~YP6Psw!@v*@u zDY8aT+vf_T+dSu9PEe{a5B$mk9q}rRt*}~%Uv5S}52!;NrMgKG|&?y9oW)*G6iONR4WPq`0-Byf&c#4ewals zU}3HkiUzE~Dr;AImp?Oammc-V>jeQhUbG#|<{yXAg%YaAs5VsrgAe+AGWk^>w)n~a j-dX?u{rHL}U*G{!A)i~e_oSe|2LO|iP!z8fH4gqib)v_< literal 0 HcmV?d00001 diff --git a/pano/pano_view/media/favicon/favicon-228x228.png b/pano/pano_view/media/favicon/favicon-228x228.png new file mode 100755 index 0000000000000000000000000000000000000000..58a5ea38608320e69f467253a4d784304e684e68 GIT binary patch literal 28250 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�mVck{Z7ioxo#uH<{p2Tit|tq2esAFofRKQ4{O8 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 literal 0 HcmV?d00001 diff --git a/pano/pano_view/media/favicon/favicon-32x32.png b/pano/pano_view/media/favicon/favicon-32x32.png new file mode 100755 index 0000000000000000000000000000000000000000..f0a1d1aa18d3ab74b45e26474da61d1a421cc98c GIT binary patch literal 1702 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' + '
  • ' "{module} {bay}" "
  • " ), @@ -452,14 +471,37 @@ def generate_scene_index(config, out_folder): print("wrote to %s" % out_path) +def install_pano_images(config, out_folder): + for scene_id, config_scene_meta in config["scenes"].items(): + # Would be more in the spirit of things to not hard-code this input path + in_image = os.path.join("/output/stitch", scene_id, "pano.jpg") + out_image_folder = os.path.join(out_folder, "scenes", scene_id) + install_file(in_image, out_image_folder, "pano.jpg") + + +def reorganize_config(config): + """ + Modify `config` in place. For the top-level inspection_results + field: add the value for each scene into the config field of the + same name for that scene. (And delete the top-level field.) + """ + scenes = config["scenes"] + for field in ["inspection_results"]: + value = config.pop(field, {}) + for scene_id, scene_value in value.items(): + scenes[scene_id][field] = scene_value + + def generate_tour(config_path, out_folder, package_paths): with open(config_path, "r") as config_stream: config = yaml.safe_load(config_stream) + reorganize_config(config) install_static_files(out_folder, package_paths) generate_tour_json(config, out_folder) generate_scene_index(config, out_folder) - dosys("chmod a+rX %s" % out_folder) + install_pano_images(config, out_folder) + dosys("chmod -R a+rX %s" % out_folder) class CustomFormatter( diff --git a/pano/pano_view/scripts/prep_source_images.py b/pano/pano_view/scripts/prep_source_images.py index d617773a..2ec0b2be 100755 --- a/pano/pano_view/scripts/prep_source_images.py +++ b/pano/pano_view/scripts/prep_source_images.py @@ -31,6 +31,8 @@ import hsi import yaml +OUTPUT_PNG = False + def dosys(cmd, exit_on_error=True): print("+ " + cmd) @@ -50,7 +52,7 @@ def read_pto(pto_path): return pano -def read_scene_source_images_meta(stitch_folder, scene_id): +def read_scene_source_images_meta(stitch_folder, scene_id, images_dir): pto_path = os.path.join(stitch_folder, scene_id, "stitch_final.pto") pano = read_pto(pto_path) num_images = pano.getNrOfImages() @@ -61,6 +63,8 @@ def read_scene_source_images_meta(stitch_folder, scene_id): images_meta[img_id] = { "yaw": img.getYaw(), "pitch": img.getPitch(), + "image": os.path.join(images_dir, img_id + ".jpg"), + "task": "pano", } return images_meta @@ -80,10 +84,15 @@ def do_prep_image(job_args): if any((os.path.exists(p) for p in partial_paths)): dosys("rm -rf %s" % (" ".join(partial_paths))) - dosys("vips dzsave %s %s_partial" % (image_in, dz_out)) + png_arg = "--suffix .png" if OUTPUT_PNG else "" + dosys("vips dzsave %s %s_partial %s" % (image_in, dz_out, png_arg)) for p in partial_paths: dosys("mv %s %s" % (p, p.replace("_partial", ""))) + # Copy original source image to output as well (enables download link) + ext = os.path.splitext(image_in)[1] + dosys("cp %s %s" % (image_in, dz_out + ext)) + def write_images_meta(images_meta, meta_out_path): meta_out_path_parent = os.path.dirname(meta_out_path) @@ -95,14 +104,26 @@ def write_images_meta(images_meta, meta_out_path): print("wrote %s" % meta_out_path) +def get_inspection_results(scene_meta): + infos = scene_meta.get("inspection_results", []) + for info in infos: + info["task"] = "inspection" + return { + os.path.splitext(os.path.basename(info["image"]))[0]: info for info in infos + } + + def get_scene_q(config, stitch_folder, out_folder, scene_id): - images_meta = read_scene_source_images_meta(stitch_folder, scene_id) scene_meta = config["scenes"][scene_id] + images_meta = read_scene_source_images_meta( + stitch_folder, scene_id, scene_meta["images_dir"] + ) + images_meta.update(get_inspection_results(scene_meta)) scene_out = os.path.join(out_folder, "source_images", scene_id) prep_image_q = [] - for img_id in images_meta.keys(): - image_in = os.path.join(scene_meta["images_dir"], img_id + ".jpg") + for img_id, img_meta in images_meta.items(): + image_in = img_meta["image"] dz_out = os.path.join(scene_out, img_id) if os.path.exists(dz_out + ".dzi"): continue @@ -129,9 +150,23 @@ def join_lists(lists): return functools.reduce(operator.iadd, lists, []) +def reorganize_config(config): + """ + Modify `config` in place. For the top-level inspection_results + field: add the value for each scene into the config field of the + same name for that scene. (And delete the top-level field.) + """ + scenes = config["scenes"] + for field in ["inspection_results"]: + value = config.pop(field, {}) + for scene_id, scene_value in value.items(): + scenes[scene_id][field] = scene_value + + def prep_source_images(config_path, stitch_folder, out_folder, num_jobs): with open(config_path, "r") as config_stream: config = yaml.safe_load(config_stream) + reorganize_config(config) prep_image_q = join_lists( ( diff --git a/pano/pano_view/static/css/isaac_pano.css b/pano/pano_view/static/css/isaac_pano.css index dfa5a280..9042933b 100644 --- a/pano/pano_view/static/css/isaac_pano.css +++ b/pano/pano_view/static/css/isaac_pano.css @@ -23,6 +23,23 @@ body { font-family: sans-serif; } +.isaac-flex { + display: flex; + flex-flow: column; + height: 100%; +} + +.pnlm-container { + flex: 1 1 auto; +} + +.isaac-title { + font-size: 1.2em; + font-weight: bold; + vertical-align: middle; + margin-right: 0.5em; +} + /********************************************************************** * Overview map **********************************************************************/ @@ -80,9 +97,17 @@ body { background-position: 0 0px !important; } +.isaac-source-image.isaac-annotated { + background-image: url('../media/camera_highlight.png') !important; +} + +.isaac-source-image.isaac-inspection { + background-image: url('../media/inspection.png') !important; +} + /* make this wider so scene link tooltips don't have to wrap */ div.pnlm-tooltip span { - max-width: 300px; + max-width: 400px; } /********************************************************************** @@ -90,6 +115,7 @@ div.pnlm-tooltip span { **********************************************************************/ .isaac-navbar { + flex: 0 1; padding: 5px; } @@ -124,7 +150,7 @@ div.pnlm-tooltip span { } .isaac-dropdown-content .isaac-toggle-entry { - font-size: 12px; + font-size: 16px; color: black; padding: 3px 4px; text-decoration: none; @@ -146,3 +172,7 @@ div.pnlm-tooltip span { .isaac-dropdown .show { display: block; } + +#isaac-load-input { + display: none; +} diff --git a/pano/pano_view/static/js/isaac_pano.js b/pano/pano_view/static/js/isaac_pano.js index bca475a8..d83d8e4f 100644 --- a/pano/pano_view/static/js/isaac_pano.js +++ b/pano/pano_view/static/js/isaac_pano.js @@ -39,10 +39,9 @@ function getClosestScene(pos, config, maxDistance) { } function getMousePos(event) { - var mapOriginX = window.overviewMap.offsetLeft; - var mapOriginY = window.overviewMap.offsetTop; - var offsetX = event.clientX - mapOriginX; - var offsetY = event.clientY - mapOriginY; + var mapRect = window.overviewMap.getBoundingClientRect(); + var offsetX = event.clientX - mapRect.x; + var offsetY = event.clientY - mapRect.y; return [offsetX, offsetY]; } @@ -81,7 +80,7 @@ function updateMapCurrent() { } function updateYaw() { - var yaw = window.viewer.getConfig().yaw; + var yaw = window.viewer.getYaw(); var mapCurrent = window.mapCurrent; var northOffset = window.viewer.getConfig().northOffset || 0; mapCurrent.style.transform = ( @@ -90,49 +89,6 @@ function updateYaw() { ); } -function initIsaacPano(event) { - var config = event.configFromURL; - window.initialConfig = config; - - var uiContainer = document.getElementsByClassName('pnlm-ui')[0]; - - var overviewMap = document.createElement('div'); - overviewMap.className = 'pnlm-overview-map pnlm-controls pnlm-control'; - uiContainer.appendChild(overviewMap); - window.overviewMap = overviewMap; - - overviewMap.addEventListener('click', overviewMapClick); - overviewMap.addEventListener('mousemove', overviewMapMouseMove); - overviewMap.addEventListener('mouseleave', overviewMapMouseLeave); - - for (let [sceneName, scene] of Object.entries(config.scenes)) { - var mapMarker = document.createElement('div'); - mapMarker.className = 'pnlm-map-marker'; - var pos = scene.overviewMapPosition; - mapMarker.style.left = pos[0] + "px"; - mapMarker.style.top = pos[1] + "px"; - overviewMap.appendChild(mapMarker); - } - - var mapHighlight = document.createElement('div'); - mapHighlight.className = 'pnlm-map-highlight'; - overviewMap.appendChild(mapHighlight); - window.mapHighlight = mapHighlight; - - var mapCurrent = document.createElement('div'); - mapCurrent.className = 'pnlm-map-current'; - overviewMap.appendChild(mapCurrent); - window.mapCurrent = mapCurrent; - - updateMapCurrent(); - - window.viewer.on("scenechange", updateMapCurrent); - window.viewer.on("mouseup", updateYaw); - window.viewer.on("touchend", updateYaw); -} - -document.addEventListener('pannellumloaded', initIsaacPano, false); - /********************************************************************** * View options dropdown menu **********************************************************************/ @@ -156,51 +112,92 @@ function isaacSetVisibility(className, visibility) { function isaacShowNavControls(visibility) { isaacSetVisibility('pnlm-controls-container', visibility); + isaacSetVisibility('pnlm-panorama-info', visibility); } function isaacShowOverviewMap(visibility) { isaacSetVisibility('pnlm-overview-map', visibility); } -function isaacShowHotSpotType(hotSpotType, visibility) { +/* Return true if `hotSpot` in `sceneId` has annotations according to + * `storageItem`. + * + * @param storageItem The JSON-parsed HTML5 local storage object containing annotations. + * @param sceneId The sceneId for the current pano scene from the tour config. + * @param hotSpot A source image hotspot object from the tour config. + */ +function isaacHasAnnotations(storageItem, sceneId, hotSpot) { + const sceneAnnotations = storageItem[sceneId]; + if (sceneAnnotations == undefined) return false; + + const imageAnnotations = sceneAnnotations[hotSpot.id]; + if (imageAnnotations == undefined) return false; + + return imageAnnotations.length > 0; +} + +/* Set the cssClass property of `hotSpot` so that it is rendered in the + * annotated style or not depending on the `isAnnotated` flag. + * + * @param hotSpot A source image hotspot object from the tour config. + * @param isAnnotated If true, style the hotspot in the annotated style. + */ +function isaacSetAnnotatedStyle(hotSpot, isAnnotated) { + const unannotatedCssClass = hotSpot.cssClass.replace("isaac-annotated", ""); + const annotateClass = "isaac-annotated"; + let cssClass = unannotatedCssClass; + if (isAnnotated) { + cssClass += " " + annotateClass; + } + hotSpot.cssClass = cssClass; +} + +function isaacIsHotSpotVisible(hotSpot) { + const viewConfig = window.hotSpotViewConfig; + if (hotSpot.type == "scene") { + return viewConfig.showSceneLinks; + } else if (hotSpot.type == "info") { + return viewConfig.showSourceImageLinks; + } else { + console.log("ERROR: Unknown hotspot type " + hotSpot.type); + return false; + } +} + +function isaacRefreshHotSpots() { var config = window.viewer.getConfig(); - var currentSceneId = window.viewer.getScene(); + var storageItem = isaacStorageGetRoot(); - // Update hotSpots for all scenes. That way the visibility change - // will persist when the scene changes. for (let [sceneId, scene] of Object.entries(config.scenes)) { - // back up original complete hotSpots array if needed - if (!scene.hasOwnProperty('initialHotSpots')) { - scene.initialHotSpots = [...scene.hotSpots]; + // Remove all hotspots in the current Pannellum view. Note: We + // have to copy the current hotspots first to avoid iterating + // through an array while modifying it. + const currentHotSpots = [...scene.hotSpots]; + for (let hotSpot of currentHotSpots) { + window.viewer.removeHotSpot(hotSpot.id, sceneId); } - if (visibility) { - // add hotSpots matching type - for (const hotSpot of scene.initialHotSpots) { - if (hotSpot.type == hotSpotType) { - // console.log("window.viewer.addHotSpot(" + hotSpot.id + "," + sceneId + ");"); - window.viewer.addHotSpot(hotSpot, sceneId); - } - } - } else { - // remove hotSpots matching type - var hotSpotsCopy = [...scene.hotSpots]; - for (const hotSpot of hotSpotsCopy) { - if (hotSpot.type == hotSpotType) { - // console.log("window.viewer.removeHotSpot(" + hotSpot.id + "," + sceneId + ");"); - window.viewer.removeHotSpot(hotSpot.id, sceneId); + // Add back hotspots that should be visible currently, + // adjusting styling if needed. + for (let hotSpot of scene.initialHotSpots) { + if (isaacIsHotSpotVisible(hotSpot)) { + if (hotSpot.type == "info") { + isaacSetAnnotatedStyle(hotSpot, isaacHasAnnotations(storageItem, sceneId, hotSpot)); } + window.viewer.addHotSpot(hotSpot, sceneId); } } } } function isaacShowSceneLinks(visibility) { - isaacShowHotSpotType("scene", visibility); + window.hotSpotViewConfig.showSceneLinks = visibility; + isaacRefreshHotSpots(); } function isaacShowSourceImageLinks(visibility) { - isaacShowHotSpotType("info", visibility); + window.hotSpotViewConfig.showSourceImageLinks = visibility; + isaacRefreshHotSpots(); } const ISAAC_CHANGE_VISIBILITY_HANDLERS = { @@ -217,6 +214,10 @@ function isaacToggleEntryCheckBox(event) { ISAAC_CHANGE_VISIBILITY_HANDLERS[elt.id](visibility); } +function isaacDeepCopy(obj) { + return JSON.parse(JSON.stringify(obj)); +} + function isaacInitViewDropDown() { document.getElementsByClassName("isaac-drop-button")[0].onclick = isaacToggleDropDown; @@ -225,6 +226,19 @@ function isaacInitViewDropDown() { entry.onclick = isaacToggleEntryCheckBox; } + // Back up the initial/complete list of hotspots for each scene, + // given we may need to remove and add them back later based on the + // user's selected view options. + var config = window.viewer.getConfig(); + for (let [sceneId, scene] of Object.entries(config.scenes)) { + scene.initialHotSpots = [...scene.hotSpots]; + } + + window.hotSpotViewConfig = { + showSceneLinks: true, + showSourceImageLinks: true + }; + // Close the dropdown if the user clicks outside of it window.onclick = async function(event) { if (!event.target.matches('.isaac-drop-button')) { @@ -239,4 +253,145 @@ function isaacInitViewDropDown() { } } -isaacInitViewDropDown(); +/* Return an array of [sceneId, imageid] for images that have annotations. */ +function isaacGetImagesWithTargets() { + var storageItem = isaacStorageGetRoot(); + var result = []; + for (const [sceneId, imageAnnotationsMap] of Object.entries(storageItem)) { + for (const [imageId, annotations] of Object.entries(imageAnnotationsMap)) { + if (annotations.length > 0) { + result.push([sceneId, imageId]); + } + }; + }; + return result; +} + +/* Process an annotation update that comes from the annotation storage + * object. This highlights source images that contain targets and enables + * the target selection Next/Previous buttons. + */ +function isaacPanoProcessStorageUpdate() { + isaacRefreshHotSpots(); +} + +/* Change the annotation review index by `delta`. Each review index + * refers to a sceneId, imageId pair. Changing the index switches to + * the scene and pans to the image. + * + * @param delta Specify delta = 1 for the Next button or -1 for the Previous button. + */ +function isaacPanoReviewUpdate(delta) { + const reviewImages = isaacGetImagesWithTargets(); + if (reviewImages.length == 0) return; + ISAAC_REVIEW_INDEX = (ISAAC_REVIEW_INDEX + delta + reviewImages.length) % reviewImages.length; + const [sceneId, imageId] = reviewImages[ISAAC_REVIEW_INDEX]; + const hotSpot = window.initialConfig.scenes[sceneId].hotSpots.find((hs) => (hs.id == imageId)); + if (hotSpot == undefined) { + console.log("isaacPanoReviewUpdate: invalid sceneId, imageId:", sceneId, imageId); + return; + } + const reviewHfov = 50.0; + if (window.viewer.getScene() != sceneId) { + window.viewer.loadScene(sceneId, hotSpot.pitch, hotSpot.yaw, reviewHfov); + } else { + window.viewer.lookAt(hotSpot.pitch, hotSpot.yaw, reviewHfov); + } +} + +/* Download the full pano image as a file called '_pano.jpg'. */ +function isaacDownloadPanoImage() { + const sceneId = window.viewer.getScene(); + const a = document.createElement('a'); + a.href = "scenes/" + sceneId + "/pano.jpg"; + a.download = sceneId + "_pano.jpg"; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); +} + +/********************************************************************** + * Main initialization + **********************************************************************/ + +function isaacPanoInit(event) { + var config = event.configFromURL; + + if (config.initialAnnotations == null) { + config.initialAnnotations = {}; + } + // Initialize default annotation content in local storage, making + // it available to source image tabs that don't load the config + // from tour.json, just in case they need it. (This seems + // unlikely.) + window.localStorage.setItem(ISAAC_DEFAULT_CONTENT_KEY, JSON.stringify(config.initialAnnotations)); + + // Initialize annotations to the default if none are present. + var storageItem = isaacStorageGetRoot(); + delete storageItem.source_window_id; // ignore this field if present + if (Object.keys(storageItem).length == 0) { + isaacStorageSetRoot(config.initialAnnotations); + } + + window.initialConfig = config; + + var uiContainer = document.getElementsByClassName('pnlm-ui')[0]; + + var overviewMap = document.createElement('div'); + overviewMap.className = 'pnlm-overview-map pnlm-controls pnlm-control'; + uiContainer.appendChild(overviewMap); + window.overviewMap = overviewMap; + + overviewMap.addEventListener('click', overviewMapClick); + overviewMap.addEventListener('mousemove', overviewMapMouseMove); + overviewMap.addEventListener('mouseleave', overviewMapMouseLeave); + + for (let [sceneName, scene] of Object.entries(config.scenes)) { + var mapMarker = document.createElement('div'); + mapMarker.className = 'pnlm-map-marker'; + var pos = scene.overviewMapPosition; + mapMarker.style.left = pos[0] + "px"; + mapMarker.style.top = pos[1] + "px"; + overviewMap.appendChild(mapMarker); + } + + var mapHighlight = document.createElement('div'); + mapHighlight.className = 'pnlm-map-highlight'; + overviewMap.appendChild(mapHighlight); + window.mapHighlight = mapHighlight; + + var mapCurrent = document.createElement('div'); + mapCurrent.className = 'pnlm-map-current'; + overviewMap.appendChild(mapCurrent); + window.mapCurrent = mapCurrent; + + updateMapCurrent(); + + // Pannellum's default HFOV bounds of [50, 120] don't allow the + // user to zoom in extremely close, which is sometimes useful. + window.viewer.setHfovBounds([5, 120]); + + window.viewer.on("scenechange", updateMapCurrent); + window.viewer.on("mouseup", updateYaw); + window.viewer.on("touchend", updateYaw); + window.viewer.on("animatefinished", updateYaw); + + isaacInitViewDropDown(); + isaacConfigureLoadSaveClear(isaacPanoProcessStorageUpdate); + + document.getElementById('isaac-pano-image').addEventListener('click', isaacDownloadPanoImage); + + document.getElementById('isaac-previous').addEventListener('click', event => isaacPanoReviewUpdate(-1)); + document.getElementById('isaac-next').addEventListener('click', event => isaacPanoReviewUpdate(1)); + + // Load annotations + isaacPanoProcessStorageUpdate(); + + // Handle annotation changes triggered by other windows + window.addEventListener( + "storage", + (event) => isaacPanoProcessStorageUpdate() + ); +} + +document.addEventListener('pannellumloaded', isaacPanoInit, false); diff --git a/pano/pano_view/static/js/isaac_source_image.js b/pano/pano_view/static/js/isaac_source_image.js index c1d24588..3c22ec50 100644 --- a/pano/pano_view/static/js/isaac_source_image.js +++ b/pano/pano_view/static/js/isaac_source_image.js @@ -19,6 +19,24 @@ /* View source image with OpenSeaDragon */ +const ISAAC_STORAGE_ROOT_KEY = 'isaac_anno'; +const ISAAC_DEFAULT_CONTENT_KEY = 'isaac_anno_default'; + +/* The index used to remember what annotation we're reviewing using + * the Next/Previous buttons. */ +var ISAAC_REVIEW_INDEX = 0; + +/* Simple should-be-unique ID for this window. Used to distinguish + * between local storage updates coming from this window vs. from + * other windows. The timestamp has millisecond precision. */ +const ISAAC_WINDOW_ID = Date.now(); + +/* Return a configuration dict parsed from the hash component of the + * window's location URL. Falls back to the query parameter component + * if the hash component is not set. The parsing is strict and will + * only accept fields 'scene' and 'imageId'. Example: URL + * 'https://some.url/#scene=x&imageId=y' -> {scene: 'x', imageId: + * 'y'}. */ function parseUrlParameters() { var url; if (window.location.hash.length > 0) { @@ -42,6 +60,7 @@ function parseUrlParameters() { switch(option) { case 'scene': case 'imageId': + case 'slug': configFromUrl[option] = decodeURIComponent(value); break; default: @@ -53,85 +72,113 @@ function parseUrlParameters() { return configFromUrl; } +/* Return obj[field] if set. Otherwise, set obj[field] = defaultValue + * and return defaultValue. */ function isaacSetDefault(obj, field, defaultValue) { if (obj[field] == undefined) { - obj[field] = defaultValue; - return defaultValue; + obj[field] = defaultValue; + return defaultValue; } return obj[field]; } +/* Return the application's storage object (parsed from a JSON string stored + * at the ISAAC_STORAGE_ROOT_KEY in HTML5 window.localStorage). */ function isaacStorageGetRoot() { - var storageItemText = window.localStorage.getItem('annotations') || "{}"; + var storageItemText = window.localStorage.getItem(ISAAC_STORAGE_ROOT_KEY); + if (storageItemText == null) { + storageItemText = window.localStorage.getItem(ISAAC_DEFAULT_CONTENT_KEY); + } + if (storageItemText == null) { + storageItemText = "{}"; + } return JSON.parse(storageItemText); } +/* Set the applications storage object to `obj`. */ function isaacStorageSetRoot(obj) { - window.localStorage.setItem('annotations', JSON.stringify(obj)); + obj.source_window_id = ISAAC_WINDOW_ID; + window.localStorage.setItem(ISAAC_STORAGE_ROOT_KEY, JSON.stringify(obj)); } +/* Return the result of drilling down into `obj`, treating `fieldPath` + * as an array of references to retrieve. Example: + * isaacGetFieldPath(obj, ["foo", 1]) -> obj.foo[1]. */ function isaacGetFieldPath(obj, fieldPath) { for (fieldElt of fieldPath) { - obj = obj[fieldElt]; - if (obj == undefined) { - return undefined; - } + obj = obj[fieldElt]; + if (obj == undefined) { + return undefined; + } } return obj; } +/* Return the storage object value at `fieldPath`, where `fieldPath` + * is an array of field names used to drill down into the storage + * object. */ function isaacStorageGet(fieldPath) { var storageItem = isaacStorageGetRoot(); return isaacGetFieldPath(storageItem, fieldPath); } +/* Companion to `isaacStorageGet()`. Set the storage object value at + * `fieldPath` to `value`. */ function isaacStorageSet(fieldPath, value) { if (fieldPath.length == 0) { - isaacStorageSetRoot(value); - return; + isaacStorageSetRoot(value); + return; } var storageItem = isaacStorageGetRoot(); var obj = storageItem; for (fieldElt of fieldPath.slice(0, -1)) { - obj = isaacSetDefault(obj, fieldElt, {}); + obj = isaacSetDefault(obj, fieldElt, {}); } obj[fieldPath[fieldPath.length - 1]] = value; isaacStorageSetRoot(storageItem); } +/* Return the storage object value at `fieldPath`. If not set, set it + * to defaultValue and return defaultValue. + */ function isaacStorageSetDefault(fieldPath, defaultValue) { var storageItem = isaacStorageGetRoot(); var obj = storageItem; for (fieldElt of fieldPath.slice(0, -1)) { - obj = isaacSetDefault(obj, fieldElt, {}); + obj = isaacSetDefault(obj, fieldElt, {}); } var fieldLast = fieldPath[fieldPath.length - 1]; if (obj[fieldLast] == undefined) { - obj[fieldLast] = defaultValue; - isaacStorageSetRoot(storageItem); - return defaultValue; + obj[fieldLast] = defaultValue; + isaacStorageSetRoot(storageItem); + return defaultValue; } return obj[fieldLast]; } +/* Delete the storage object value at `fieldPath`. */ function isaacStorageDelete(fieldPath) { var storageItem = isaacStorageGetRoot(); var obj = storageItem; for (fieldElt of fieldPath.slice(0, -1)) { - obj = isaacSetDefault(obj, fieldElt, {}); + obj = isaacSetDefault(obj, fieldElt, {}); } delete obj[fieldPath[fieldPath.length - 1]]; isaacStorageSetRoot(storageItem); } +/* Convert `data` to a JSON string and trigger the browser to download + * it as an attachment named `fileName`. Note: This has a side-effect + * of deleting the `source_window_id` field of `data`, which we don't want to save. */ function isaacSaveData(data, fileName) { + delete data.source_window_id; var json = JSON.stringify(data, null, 4); var blob = new Blob([json], {type: 'application/json'}); var url = window.URL.createObjectURL(blob); @@ -148,23 +195,29 @@ function isaacSaveData(data, fileName) { a.remove(); } +/* The maximum depth of the history undo and redo stacks. */ var ISAAC_HISTORY_MAX_LENGTH = 10; +/* Set the disabled status of the Undo and Redo buttons based on the + * annotation history stacks. */ function isaacHistoryUpdateEnabled(history) { document.getElementById('isaac-undo').disabled = (history.undoStack.length == 0); document.getElementById('isaac-redo').disabled = (history.redoStack.length == 0); } +/* Log a debug message about the annotation history stacks. */ function isaacHistoryDebug(history) { console.log("#undo=" + history.undoStack.length + " #redo=" + history.redoStack.length) } +/* Save a new annotation state to the history and update the disabled + * state of the Undo/Redo buttons. */ function isaacHistorySaveState(history, state) { if (history.current != null) { - history.undoStack.push(history.current); + history.undoStack.push(history.current); } if (history.undoStack.length > ISAAC_HISTORY_MAX_LENGTH) { - history.undoStack.shift(); + history.undoStack.shift(); } history.current = state; history.redoStack = []; @@ -173,16 +226,32 @@ function isaacHistorySaveState(history, state) { isaacHistoryDebug(history); } +/* Update the Annotorious part of the UI to reflect a new annotation + * state. This doesn't modify the storage object or update the + * history. + * + * @param history A history object with fields 'current', 'undoStack', 'redoStack'. + * @param state The annotation state (corresponds to the complete storage object). + * @param imageStoragePath A path within `state` referencing the annotation state for the current image. + * @param anno A reference to the live instance of the Annotorious viewer. + */ function isaacRenderState(history, state, imageStoragePath, anno) { var imageAnnotations = isaacGetFieldPath(state, imageStoragePath) || []; anno.setAnnotations(imageAnnotations); isaacHistoryUpdateEnabled(history); } +/* Perform an undo operation. This updates the current annotation state, adjusts the history undo/redo stacks, + * saves the annotation state to the storage object, and updates the UI. + * + * @param history A history object with fields 'current', 'undoStack', 'redoStack'. + * @param imageStoragePath A path within the storage object referencing the annotation state for the current image. + * @param anno A reference to the live instance of the Annotorious viewer. + */ function isaacHistoryUndo(history, imageStoragePath, anno) { if (history.undoStack.length == 0) { - console.log('got undo request with no undo stack, should never happen'); - return; + console.log('got undo request with no undo stack, should never happen'); + return; } history.redoStack.push(history.current); history.current = history.undoStack.pop(); @@ -193,10 +262,11 @@ function isaacHistoryUndo(history, imageStoragePath, anno) { isaacHistoryDebug(history); } +/* Perform a redo operation. Params and effects similar to undo (see above). */ function isaacHistoryRedo(history, imageStoragePath, anno) { if (history.redoStack.length == 0) { - console.log('got redo request with no redo stack, should never happen'); - return; + console.log('got redo request with no redo stack, should never happen'); + return; } history.undoStack.push(history.current); history.current = history.redoStack.pop(); @@ -207,44 +277,144 @@ function isaacHistoryRedo(history, imageStoragePath, anno) { isaacHistoryDebug(history); } +/* Record an Annotorious edit operation. This updates the storage object and the + history undo/redo stacks, and updates the non-Annotorious part of the UI. + (The Annotorious part of the UI is assumed to be the source of the edit and + shouldn't need to be updated.) */ function isaacUpdateAnnotations(fieldPath, value, history) { isaacStorageSet(fieldPath, value); isaacHistorySaveState(history, isaacStorageGetRoot()); } +/* Return a Promise that resolves to the text content of `file` (a + local file picked by the user for upload using the "Load" + button). */ function isaacReadAsText(file) { // Always return a Promise return new Promise((resolve, reject) => { - let content = ''; - const reader = new FileReader(); - // Wait till complete - reader.onloadend = function(e) { - resolve(e.target.result); - }; - // Make sure to handle error states - reader.onerror = function(e) { - reject(e); - }; - reader.readAsText(file); + let content = ''; + const reader = new FileReader(); + // Wait till complete + reader.onloadend = function(e) { + resolve(e.target.result); + }; + // Make sure to handle error states + reader.onerror = function(e) { + reject(e); + }; + reader.readAsText(file); }); } +/* Change the annotation review index by `delta`. This changes which + * annotation is highlighted and pans to the highlighted annotation. + * + * @param imageStoragePath A path within the storage object referencing the annotation state for the current image. + * @param anno A reference to the live instance of the Annotorious viewer. + * @param delta Specify delta = 1 for the Next button or -1 for the Previous button. + */ +function isaacReviewUpdater(imageStoragePath, anno, delta) { + var annotations = isaacStorageGet(imageStoragePath); + if (!annotations) return; + ISAAC_REVIEW_INDEX = (ISAAC_REVIEW_INDEX + delta + annotations.length) % annotations.length; + var annoId = annotations[ISAAC_REVIEW_INDEX].id; + anno.selectAnnotation(annoId); + anno.panTo(annoId); +} + +/* Process an annotation update that comes from the storage + * object. This updates the history and both the Annotorious and + * non-Annotorious parts of the UI. + * + * @param history A history object with fields 'current', 'undoStack', 'redoStack'. + * @param imageStoragePath A path within the storage object referencing the annotation state for the current image. + * @param anno The live instance of the Annotorious viewer. + */ +function isaacProcessStorageUpdate(history, imageStoragePath, anno) { + var storageItem = isaacStorageGetRoot(); + isaacRenderState(history, storageItem, imageStoragePath, anno); + isaacHistorySaveState(history, storageItem); +} + +/* Handle an annotation update that comes from the storage + * object. This updates the history and both the Annotorious and + * non-Annotorious parts of the UI. + * + * @param history A history object with fields 'current', 'undoStack', 'redoStack'. + * @param imageStoragePath A path within the storage object referencing the annotation state for the current image. + * @param anno The live instance of the Annotorious viewer. + */ +function isaacHandleStorageEvent(history, imageStoragePath, anno, event) { + if (event.key !== null && event.key != ISAAC_STORAGE_ROOT_KEY) { + // Ignore storage events unless they affect our key. The event key will be null + // for a clear event that affects all keys. + return; + } + var storageItem = JSON.parse(event.newValue); + if (storageItem.source_window_id == ISAAC_WINDOW_ID) { + // Ignore storage events that were triggered by changes made in this + // window -- they will already have been explicitly handled, or not, + // as needed. + return; + } + isaacProcessStorageUpdate(history, imageStoragePath, anno); +} + +/* Configure handlers for the Load, Save, and Clear buttons. + * + * @param storageUpdateHandler A callback invoked with no arguments when the storage object changes. + */ +function isaacConfigureLoadSaveClear(storageUpdateHandler) { + var isaacLoadInput = document.getElementById('isaac-load-input'); + document.getElementById('isaac-load').addEventListener('click', function(event) { + isaacLoadInput.click(); + }); + isaacLoadInput.addEventListener('change', async function(event) { + console.log('load change event'); + console.log(isaacLoadInput); + if (isaacLoadInput.files.length > 0) { + var loadFile = isaacLoadInput.files[0]; + var loadText = await isaacReadAsText(loadFile); + var storageItem = JSON.parse(loadText); + isaacStorageSetRoot(storageItem); + storageUpdateHandler(); + } + }); + + document.getElementById('isaac-save').addEventListener('click', function(event) { + isaacSaveData(isaacStorageGetRoot(), 'isaac_iss_annotations.json'); + }); + document.getElementById('isaac-clear').addEventListener('click', function(event) { + isaacStorageSetRoot({}); + storageUpdateHandler(); + }); +} + +/* Perform overall initialization for the ISAAC pano tour source image + viewer. */ function initIsaacSourceImage() { var configFromUrl = parseUrlParameters(); // Initialize OpenSeaDragon viewer and Annotorious plugin var viewer = OpenSeadragon({ id: 'container', - prefixUrl: '../../media/openseadragon/', - tileSources: '../../source_images/' + configFromUrl['scene'] + '/' - + configFromUrl['imageId'] + '.dzi' + prefixUrl: '../media/openseadragon/', + tileSources: '../source_images/' + configFromUrl['scene'] + '/' + + configFromUrl['imageId'] + '.dzi', + maxZoomPixelRatio: 5 }); - var anno = OpenSeadragon.Annotorious(viewer); + const annoConfig = { + allowEmpty: true + }; + var anno = OpenSeadragon.Annotorious(viewer, annoConfig); + // anno.setDrawingEnabled(true); var history = { - 'current': null, - 'undoStack': [], - 'redoStack': [] + 'current': null, + 'undoStack': [], + 'redoStack': [] }; + // anno.removeDrawingTool('rect'); + // anno.removeDrawingTool('polygon'); // Export symbols for debugging window.configFromUrl = configFromUrl; @@ -254,77 +424,55 @@ function initIsaacSourceImage() { // Configure extra point drawing tool (default tools are rect and polygon only) Annotorious.SelectorPack(anno, { - tools: ['point'] + tools: ['point'] }); - // Create toolbar - Annotorious.Toolbar(anno, document.getElementById('isaac-toolbar-container')); + // Set slug text + slugText = configFromUrl['slug'].replaceAll("_", " "); + document.getElementById('isaac-slug').textContent = slugText; + document.title = slugText + ": ISAAC ISS Tour"; // Configure other button handlers + document.getElementById('isaac-raw-anchor').href = '../../source_images/' + + configFromUrl['scene'] + '/' + + configFromUrl['imageId'] + '.jpg'; var imageStoragePath = [configFromUrl.scene, configFromUrl.imageId]; document.getElementById('isaac-undo').addEventListener( - "click", - event => isaacHistoryUndo(history, imageStoragePath, anno) + 'click', + event => isaacHistoryUndo(history, imageStoragePath, anno) ); document.getElementById('isaac-redo').addEventListener( - "click", - event => isaacHistoryRedo(history, imageStoragePath, anno) + 'click', + event => isaacHistoryRedo(history, imageStoragePath, anno) ); - var isaacLoadInput = document.getElementById('isaac-load-input'); - document.getElementById('isaac-load').addEventListener('click', function(event) { - isaacLoadInput.click(); - }); - isaacLoadInput.addEventListener('change', async function(event) { - console.log('load change event'); - console.log(isaacLoadInput); - if (isaacLoadInput.files.length > 0) { - var loadFile = isaacLoadInput.files[0]; - var loadText = await isaacReadAsText(loadFile); - var storageItem = JSON.parse(loadText); - isaacStorageSetRoot(storageItem); - isaacHistorySaveState(history, storageItem); - isaacRenderState(history, storageItem, imageStoragePath, anno); - } - }); + document.getElementById('isaac-add').addEventListener( + 'click', + event => { + anno.setDrawingTool('rect'); + anno.setDrawingEnabled(true); + } + ); - document.getElementById('isaac-save').addEventListener('click', function(event) { - isaacSaveData(isaacStorageGetRoot(), 'annotations.json'); - }); - document.getElementById('isaac-clear').addEventListener('click', function(event) { - isaacRenderState(history, {}, imageStoragePath, anno); - isaacUpdateAnnotations([], {}, history); - }); + var storageUpdateHandler = () => isaacProcessStorageUpdate(history, imageStoragePath, anno) + isaacConfigureLoadSaveClear(storageUpdateHandler); - var reviewIndex = 0; - var reviewUpdater = function(delta) { - return function(event) { - var annotations = isaacStorageGet(imageStoragePath); - if (!annotations) return; - reviewIndex = (reviewIndex + delta + annotations.length) % annotations.length; - var annoId = annotations[reviewIndex].id; - anno.selectAnnotation(annoId); - anno.panTo(annoId); - } - } + var reviewUpdater = delta => (event => isaacReviewUpdater(imageStoragePath, anno, delta)); document.getElementById('isaac-previous').addEventListener('click', reviewUpdater(-1)); document.getElementById('isaac-next').addEventListener('click', reviewUpdater(1)) // Restore annotations on this image from HTML5 local storage - var storageItem = isaacStorageGetRoot(); - isaacRenderState(history, storageItem, imageStoragePath, anno); - isaacHistorySaveState(history, storageItem); + isaacProcessStorageUpdate(history, imageStoragePath, anno); + + // Handle storage changes triggered by other windows + window.addEventListener( + "storage", + (event) => isaacHandleStorageEvent(history, imageStoragePath, anno, event) + ); // Save subsequent drawing events to HTML5 local storage - anno.on('createAnnotation', function(annotation) { - isaacUpdateAnnotations(imageStoragePath, anno.getAnnotations(), history); - }); - anno.on('updateAnnotation', function(annotation) { - isaacUpdateAnnotations(imageStoragePath, anno.getAnnotations(), history); - }); - anno.on('deleteAnnotation', function(annotation) { - isaacUpdateAnnotations(imageStoragePath, anno.getAnnotations(), history); - }); + var annoEventHandler = annotation => isaacUpdateAnnotations(imageStoragePath, anno.getAnnotations(), history); + anno.on('createAnnotation', annoEventHandler); + anno.on('updateAnnotation', annoEventHandler); + anno.on('deleteAnnotation', annoEventHandler); } - -initIsaacSourceImage(); diff --git a/pano/pano_view/templates/help.html b/pano/pano_view/templates/help.html new file mode 100644 index 00000000..bed09ebc --- /dev/null +++ b/pano/pano_view/templates/help.html @@ -0,0 +1,112 @@ + + + + + + Help: ISAAC ISS Tour + + + +

    ISAAC ISS Tour Help

    +

    Panoramic Tour Viewer

    +

    The Panoramic Tour Viewer lets you freely explore the interior of the ISS. Some features include:

    +
      +
    • Throughout the panorama view: +
        +
      • Click/tap and drag to pan your view and look in different directions.
      • +
      • Zoom in and out with a pinch gesture on a multitouch display, or mouse wheel scroll if you have a mouse.
      • +
      +
    • +
    • The panorama controls at the upper left provide: +
        +
      • The [+] and [-] buttons are another way to zoom in and out. +
      • The button with the viewfinder icon toggles full-screen mode for more immersive exploration.
      • +
      +
    • +
    • The overview map at the upper right provides: +
        +
      • The map shows the modules of the U.S. Orbital Segment of the ISS where the Astrobee robots are able to operate to collect panoramic survey data. (Only three modules have been surveyed so far.)
      • +
      • The red arrow shows the position and orientation (yaw) of the current view so you can stay aware of where you are.
      • +
      • The gray dots show the locations of ISS module bays where panorama scenes are available to explore. Click/tap on one of the dots to move to that scene.
      • +
      +
    • +
    • The icons scattered throughout the panorama provide: +
        +
      • An upward pointing arrow icon is a hotspot that links to a neighboring panorama scene. Click/tap on the hotspot to move the tour view to that scene.
      • +
      • The camera icons are hotspots that link to one of the source images that were stitched together to form the panorama. You may prefer to view these images because they are free from stitching artifacts, or because you want to add annotations. Click/tap on the hotspot to open an Image Viewer window on that image. The camera icon is normally colored grey but is highlighted yellow if the image has been annotated.
      • +
      • The blue magnifying glass icons are hotspots that link to a targeted inspection image. You may prefer to view these images because they provide higher resolution than the panorama due to being captured closer up and with optimized lighting. Click/tap on the hotspot to open an Image Viewer window on that image.
      • +
      +
    • +
    • The toolbar above the panorama provides: +
        +
      • The "Help" button opens this help.
      • +
      • The "View Options" menu lets you toggle hide/show for various elements of the tour interface. You may prefer to hide some elements you don't need in order to minimize distractions, especially when taking screenshots.
      • +
      • The "Pano Image" button starts a download of the full stitched panorama image. You may find this image helpful if you want to work with the panorama using other applications. Note that: You can't substitute for the "Pano Image" button using browser features like "Open Image in New Tab" or "Save Image": at best, they will open an image tile rather than the whole panorama. The downloaded panorama image will have very high resolution (typical: 26K x 13K pixels, 60+ MB), so you may have trouble opening it with some applications.
      • +
      • The "Annotations" section provides: +
          +
        • The "Previous" and "Next" buttons cycle through the list of annotated images throughout the whole tour. Each time you click/tap one of these buttons, the view will pan to focus on the hotspot for the previous/next annotated image (switching to a new scene if needed). Click/tap on the hotspot to open an Image Viewer window on that image, where you can view its annotations.
        • +
        • The "Load" button loads a whole-tour set of annotations that were previously saved. They are loaded into the local storage for your browser and will only be visible to you when you use that browser.
        • +
        • The "Save" button saves your current set of whole-tour annotations, downloading them as a file called "isaac_iss_annotations.json". You can share this file with other users, who can load it into the tour interface in their browser, or analyze it using other tools. For example, we have a tool that interprets a set of annotations as requested inspection targets and extracts the 3D target positions to use for commanding Astrobee follow-up inspections during a future ISS activity.
        • +
        • The "Clear" button deletes your current whole-tour set of annotations. (Like all annotation edits, this change only affects your view in your current browser.)
        • +
        • (The "Load", "Save", and "Clear" buttons have exactly the same behavior in both the Panoramic Tour Viewer and Image Viewer.)
        • +
        +
      • +
      +
    • +
    + +

    Image Viewer

    +

    The Image Viewer lets you view and annotate an individual image collected by the Astrobee robots. Some features include:

    +
      +
    • Throughout the image view: +
        +
      • Click/tap and drag to pan your view and look at different parts of the image.
      • +
      • Zoom in and out with a pinch gesture on a multitouch display, or mouse wheel scroll if you have a mouse.
      • +
      • Shift-click and drag to add an annotation if you have a keyboard and mouse.
      • +
      +
    • +
    • The view controls at the upper left provide: +
        +
      • The [+] and [-] buttons are another way to zoom in and out.
      • +
      • The home button restores the original image view (zooms out to view the whole image).
      • +
      • The rectangle+arrow button toggles full-screen mode for more immersive exploration.
      • +
      • (These buttons auto-hide themselves after a period of inactivity. You can make them reappear by moving around in the image.)
      • +
      +
    • +
    • The rectangular annotations in the image provide: +
        +
      • Click/tap on an annotation to open it. This lets you view or edit the annotation text, move the rectangle corners to adjust its shape and position, or delete the annotation using its trash can button.
      • +
      +
    • +
    • The toolbar above the panorama provides: +
        +
      • The "Help" button opens this help.
      • +
      • The "Raw" button opens a new browser window displaying the full-size raw image without the Image Viewer interface. From the new window, you can view the raw image using your browser's normal interface, or download it to work with it using other applications. Note that you can't substitute for the "Raw" button by using browser features like "Open Image in New Tab" or "Save Image" in the Image Viewer: at best, they will open an image tile rather than the full-size raw image.
      • +
      • The "Annotations" section provides: +
          +
        • The "Undo" and "Redo" buttons undo or redo annotation edits in the current image only.
        • +
        • The "Add" button activates add-annotation mode. After you click/tap this button, click/tap and drag anywhere in the image to add a new annotation.
        • +
        • The "Previous" and "Next" buttons cycle through the list of annotations on the current image. Each time you click/tap one of these buttons, the view will open the previous/next annotation.
        • +
        • The "Load" button loads a whole-tour set of annotations that were previously saved. They are loaded into the local storage for your browser and will only be visible to you when you use that browser.
        • +
        • The "Save" button saves your current set of whole-tour annotations, downloading them as a file called "isaac_iss_annotations.json". You can share this file with other users, who can load it into the tour interface in their browser, or analyze it using other tools. For example, we have a tool that interprets a set of annotations as requested inspection targets and extracts the 3D target positions to use for commanding Astrobee follow-up inspections during a future ISS activity.
        • +
        • The "Clear" button deletes your current whole-tour set of annotations. (Like all annotation edits, this change only affects your view in your current browser.)
        • +
        • (The "Load", "Save", and "Clear" buttons have exactly the same behavior in both the Panoramic Tour Viewer and Image Viewer.)
        • +
        +
      • +
      +
    • +
    + + + diff --git a/pano/pano_view/templates/index.html b/pano/pano_view/templates/index.html index f3eb9416..69a62b90 100644 --- a/pano/pano_view/templates/index.html +++ b/pano/pano_view/templates/index.html @@ -6,7 +6,7 @@

    ISAAC Astrobee Panoramas

    -

    [Start exploring here]

    +

    [Start exploring here]

    Or jump straight to a specific bay:

    diff --git a/pano/pano_view/templates/isaac_source_image.html b/pano/pano_view/templates/isaac_source_image.html index 024e7a8a..44bb9e79 100644 --- a/pano/pano_view/templates/isaac_source_image.html +++ b/pano/pano_view/templates/isaac_source_image.html @@ -3,13 +3,23 @@ - ISAAC Source Image - + ISAAC ISS Tour + + + + + + + + + +
    + ISAAC ISS Tour: + + + + + Annotations: -
    + Load +