Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 18063)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 18065)
@@ -26,5 +26,5 @@
 
     /**
-     * Match a list of photos to a gpx track with a given offset.
+     * Match a list of photos to a gpx track with given settings.
      * All images need a exifTime attribute and the List must be sorted according to these times.
      * @param images images to match
@@ -35,4 +35,9 @@
     public static int matchGpxTrack(List<? extends GpxImageEntry> images, GpxData selectedGpx, GpxImageCorrelationSettings settings) {
         int ret = 0;
+
+        if (Logging.isDebugEnabled()) {
+            Logging.debug("Correlating {0} images to {1} GPX track segments using {2}",
+                    images.size(), selectedGpx.getTrackSegsCount(), settings);
+        }
 
         boolean trkInt, trkTag, segInt, segTag;
@@ -73,5 +78,5 @@
         WayPoint prevWp = null;
 
-        for (List<List<WayPoint>> segs : loadTracks(selectedGpx.tracks)) {
+        for (List<List<WayPoint>> segs : loadTracks(selectedGpx.getTracks())) {
             boolean firstSegment = true;
             for (List<WayPoint> wps : segs) {
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java	(revision 18063)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java	(revision 18065)
@@ -59,3 +59,9 @@
         return directionPositionSettings;
     }
+
+    @Override
+    public String toString() {
+        return "[offset=" + offset + ", forceTags=" + forceTags
+                + ", directionPositionSettings=" + directionPositionSettings + ']';
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageDirectionPositionSettings.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageDirectionPositionSettings.java	(revision 18063)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageDirectionPositionSettings.java	(revision 18065)
@@ -70,3 +70,10 @@
         return elevationShift;
     }
+
+    @Override
+    public String toString() {
+        return "[setImageDirection=" + setImageDirection
+                + ", imageDirectionAngleOffset=" + imageDirectionAngleOffset + ", shiftImageX=" + shiftImageX
+                + ", shiftImageY=" + shiftImageY + ", elevationShift=" + elevationShift + ']';
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 18063)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 18065)
@@ -11,4 +11,5 @@
 import java.util.Locale;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.function.Consumer;
 
@@ -512,8 +513,10 @@
      * {@link #applyTmp()} or {@link #discardTmp()} if the temporary variable
      * is not needed anymore.
-     */
-    public void createTmp() {
+     * @return the fresh copy.
+     */
+    public GpxImageEntry createTmp() {
         tmp = new GpxImageEntry(this);
         tmp.tmp = null;
+        return tmp;
     }
 
@@ -765,3 +768,22 @@
         }
     }
+
+    /**
+     * Returns a {@link WayPoint} representation of this GPX image entry.
+     * @return a {@code WayPoint} representation of this GPX image entry (containing position, instant and elevation)
+     * @since 18065
+     */
+    public WayPoint asWayPoint() {
+        CachedLatLon position = getPos();
+        WayPoint wpt = null;
+        if (position != null) {
+            wpt = new WayPoint(position);
+            wpt.setInstant(Optional.ofNullable(exifGpsTime).orElse(exifTime));
+            Double ele = getElevation();
+            if (ele != null) {
+                wpt.put(GpxConstants.PT_ELE, ele.toString());
+            }
+        }
+        return wpt;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 18063)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 18065)
@@ -24,10 +24,9 @@
 import java.io.File;
 import java.text.ParseException;
-import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 
 import javax.swing.AbstractAction;
@@ -52,5 +51,4 @@
 import org.openstreetmap.josm.data.gpx.GpxImageCorrelation;
 import org.openstreetmap.josm.data.gpx.GpxImageCorrelationSettings;
-import org.openstreetmap.josm.data.gpx.GpxImageEntry;
 import org.openstreetmap.josm.data.gpx.GpxTimeOffset;
 import org.openstreetmap.josm.data.gpx.GpxTimezone;
@@ -152,7 +150,5 @@
             case CANCEL:
                 if (yLayer != null) {
-                    for (ImageEntry ie : yLayer.getImageData().getImages()) {
-                        ie.discardTmp();
-                    }
+                    yLayer.discardTmp();
                     yLayer.updateBufferAndRepaint();
                 }
@@ -188,13 +184,10 @@
                 }
 
-                for (ImageEntry ie : yLayer.getImageData().getImages()) {
-                    ie.applyTmp();
-                }
-
+                yLayer.applyTmp();
                 yLayer.updateBufferAndRepaint();
 
                 break;
             default:
-                throw new IllegalStateException();
+                throw new IllegalStateException(Integer.toString(result));
             }
         }
@@ -469,7 +462,7 @@
         JLabel labelPosition = new JLabel(tr("Override position for: "));
 
-        int numAll = getSortedImgList(true, true).size();
-        int numExif = numAll - getSortedImgList(false, true).size();
-        int numTagged = numAll - getSortedImgList(true, false).size();
+        int numAll = yLayer.getSortedImgList(true, true).size();
+        int numExif = numAll - yLayer.getSortedImgList(false, true).size();
+        int numTagged = numAll - yLayer.getSortedImgList(true, false).size();
 
         cbExifImg = new JCheckBox(tr("Images with geo location in exif data ({0}/{1})", numExif, numAll));
@@ -581,5 +574,5 @@
         statusBar.add(statusBarText);
 
-        RepaintTheMapListener repaintTheMap = new RepaintTheMapListener();
+        RepaintTheMapListener repaintTheMap = new RepaintTheMapListener(yLayer);
         pDirectionPosition.addFocusListenerOnComponent(repaintTheMap);
         tfTimezone.addFocusListener(repaintTheMap);
@@ -703,15 +696,10 @@
             // The selection of images we are about to correlate may have changed.
             // So reset all images.
-            for (ImageEntry ie: yLayer.getImageData().getImages()) {
-                ie.discardTmp();
-            }
+            yLayer.discardTmp();
 
             // Construct a list of images that have a date, and sort them on the date.
             List<ImageEntry> dateImgLst = getSortedImgList();
             // Create a temporary copy for each image
-            dateImgLst.forEach(ie -> {
-                ie.createTmp();
-                ie.getTmp().unflagNewGpsData();
-            });
+            dateImgLst.forEach(ie -> ie.createTmp().unflagNewGpsData());
 
             GpxDataWrapper selGpx = selectedGPX(false);
@@ -731,5 +719,12 @@
     }
 
-    private class RepaintTheMapListener implements FocusListener {
+    static class RepaintTheMapListener implements FocusListener {
+
+        private final GeoImageLayer yLayer;
+
+        RepaintTheMapListener(GeoImageLayer yLayer) {
+            this.yLayer = Objects.requireNonNull(yLayer);
+        }
+
         @Override
         public void focusGained(FocusEvent e) { // do nothing
@@ -877,21 +872,5 @@
 
     private List<ImageEntry> getSortedImgList() {
-        return getSortedImgList(cbExifImg.isSelected(), cbTaggedImg.isSelected());
-    }
-
-    /**
-     * Returns a list of images that fulfill the given criteria.
-     * Default setting is to return untagged images, but may be overwritten.
-     * @param exif also returns images with exif-gps info
-     * @param tagged also returns tagged images
-     * @return matching images
-     */
-    private List<ImageEntry> getSortedImgList(boolean exif, boolean tagged) {
-        return yLayer.getImageData().getImages().stream()
-                .filter(GpxImageEntry::hasExifTime)
-                .filter(e -> e.getExifCoor() == null || exif)
-                .filter(e -> tagged || !e.isTagged() || e.getExifCoor() != null)
-                .sorted(Comparator.comparing(ImageEntry::getExifInstant))
-                .collect(Collectors.toList());
+        return yLayer.getSortedImgList(cbExifImg.isSelected(), cbTaggedImg.isSelected());
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/EditImagesSequenceAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/EditImagesSequenceAction.java	(revision 18065)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/EditImagesSequenceAction.java	(revision 18065)
@@ -0,0 +1,80 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.List;
+import java.util.Objects;
+
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.data.gpx.GpxImageCorrelation;
+import org.openstreetmap.josm.data.gpx.GpxImageCorrelationSettings;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.geoimage.CorrelateGpxWithImages.RepaintTheMapListener;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Edit a sequence of geo-located images.
+ * @since 18065
+ */
+public class EditImagesSequenceAction extends JosmAction {
+
+    private final transient GeoImageLayer yLayer;
+    private final ImageDirectionPositionPanel pDirectionPosition;
+
+    /**
+     * Constructs a new {@code EditImagesSequenceAction}.
+     * @param layer The image layer
+     */
+    public EditImagesSequenceAction(GeoImageLayer layer) {
+        super(tr("Edit images sequence"), "dialogs/geoimage/gpx2img", "geoimage_editsequence",
+            Shortcut.registerShortcut("geoimage:editsequence", tr("Edit images sequence"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE),
+            false);
+        this.yLayer = Objects.requireNonNull(layer);
+        this.pDirectionPosition = ImageDirectionPositionPanel.forImageSequence();
+
+        pDirectionPosition.addFocusListenerOnComponent(new RepaintTheMapListener(yLayer));
+        pDirectionPosition.addChangeListenerOnComponents(new Updater());
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        ExtendedDialog ed = new ExtendedDialog(
+                MainApplication.getMainFrame(), tr("Edit images sequence"), tr("Apply"), tr("Cancel"))
+            .setContent(pDirectionPosition).setButtonIcons("ok", "cancel");
+        ed.setResizable(false);
+        if (ed.showDialog().getValue() == 1) {
+            yLayer.applyTmp();
+        } else {
+            yLayer.discardTmp();
+        }
+        yLayer.updateBufferAndRepaint();
+    }
+
+    class Updater implements ChangeListener {
+
+        @Override
+        public void stateChanged(ChangeEvent e) {
+            matchAndUpdate();
+        }
+
+        void matchAndUpdate() {
+            // The selection of images we are about to correlate may have changed.
+            // So reset all images.
+            yLayer.discardTmp();
+            // Construct a list of images that have a date, and sort them on the date.
+            List<ImageEntry> dateImgLst = yLayer.getSortedImgList(true, true);
+            // Create a temporary copy for each image
+            dateImgLst.forEach(ie -> ie.createTmp().unflagNewGpsData());
+            GpxImageCorrelation.matchGpxTrack(dateImgLst, yLayer.getFauxGpxData(),
+                            new GpxImageCorrelationSettings(0, false, pDirectionPosition.getSettings()));
+            yLayer.updateBufferAndRepaint();
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 18063)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 18065)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.layer.geoimage;
 
+import static java.util.stream.Collectors.toList;
 import static org.openstreetmap.josm.tools.I18n.tr;
 import static org.openstreetmap.josm.tools.I18n.trn;
@@ -21,7 +22,11 @@
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -31,4 +36,5 @@
 
 import org.openstreetmap.josm.actions.AutoScaleAction;
+import org.openstreetmap.josm.actions.ExpertToggleAction;
 import org.openstreetmap.josm.actions.RenameLayerAction;
 import org.openstreetmap.josm.actions.mapmode.MapMode;
@@ -40,5 +46,6 @@
 import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener;
 import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.data.gpx.GpxImageEntry;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -72,4 +79,5 @@
     GpxLayer gpxLayer;
     GpxLayer gpxFauxLayer;
+    GpxData gpxFauxData;
 
     private CorrelateGpxWithImages gpxCorrelateAction;
@@ -247,4 +255,7 @@
         entries.add(SeparatorLayerAction.INSTANCE);
         entries.add(getGpxCorrelateAction());
+        if (ExpertToggleAction.isExpert()) {
+            entries.add(new EditImagesSequenceAction(this));
+        }
         entries.add(new ShowThumbnailAction(this));
         if (!menuAdditions.isEmpty()) {
@@ -807,11 +818,23 @@
         if (gpxLayer != null) return getGpxLayer();
         if (gpxFauxLayer == null) {
-            GpxData gpxData = new GpxData();
-            for (ImageEntry image : data.getImages()) {
-                gpxData.addWaypoint(new WayPoint(image.getPos()));
-            }
-            gpxFauxLayer = new GpxLayer(gpxData);
+            gpxFauxLayer = new GpxLayer(getFauxGpxData());
         }
         return gpxFauxLayer;
+    }
+
+    /**
+     * Returns a faux GPX data built from the images or the associated GPX layer data.
+     * @return A faux GPX data or the associated GPX layer data
+     * @since 18065
+     */
+    public synchronized GpxData getFauxGpxData() {
+        if (gpxLayer != null) return getGpxLayer().data;
+        if (gpxFauxData == null) {
+            gpxFauxData = new GpxData();
+            gpxFauxData.addTrack(new GpxTrack(Arrays.asList(
+                    data.getImages().stream().map(ImageEntry::asWayPoint).filter(Objects::nonNull).collect(toList())),
+                    Collections.emptyMap()));
+        }
+        return gpxFauxData;
     }
 
@@ -870,3 +893,27 @@
         return data;
     }
+
+    void applyTmp() {
+        data.getImages().forEach(ImageEntry::applyTmp);
+    }
+
+    void discardTmp() {
+        data.getImages().forEach(ImageEntry::discardTmp);
+    }
+
+    /**
+     * Returns a list of images that fulfill the given criteria.
+     * Default setting is to return untagged images, but may be overwritten.
+     * @param exif also returns images with exif-gps info
+     * @param tagged also returns tagged images
+     * @return matching images
+     */
+    List<ImageEntry> getSortedImgList(boolean exif, boolean tagged) {
+        return data.getImages().stream()
+                .filter(GpxImageEntry::hasExifTime)
+                .filter(e -> e.getExifCoor() == null || exif)
+                .filter(e -> tagged || !e.isTagged() || e.getExifCoor() != null)
+                .sorted(Comparator.comparing(ImageEntry::getExifInstant))
+                .collect(toList());
+    }
 }
