#22303 closed enhancement (fixed)
Open drone image as background image
Reported by: | CjMalone | Owned by: | team |
---|---|---|---|
Priority: | normal | Milestone: | |
Component: | Plugin geotools | Version: | |
Keywords: | Cc: |
Description
It would be nice to be able to open quad copter imagery as a background layer in JOSM. I think it has enough metadata available to position the image automatically. I'll upload a image, if trac strips the exif tags I'll upload them separately.
I don't know if this should be a JOSM thing, or a PicLayer thing. I've no idea how to generate a "World file Calibration" for PicLayer.
Attachments (2)
Change History (10)
by , 3 years ago
Attachment: | DJI_0245.JPG added |
---|
follow-up: 2 comment:1 by , 3 years ago
comment:2 by , 3 years ago
Replying to taylor.smock:
But you might want to read osmwiki:JOSM/Plugins/PicLayer#Usage. You can manipulate the photo location, rotation, scale, and so on, with the piclayer plugin.
There is also a gif at the top of that page that quickly shows how to position a photo manually.
Im' not sure if automatic positioning would be precise enough anyway (maybe in areas where no other sources are available).
follow-up: 4 comment:3 by , 3 years ago
Depending upon the manufacturer (DJI), the Resolution exif data might be in pixels, mm, inches, etc. For what you want, GPSAltitude is useless (ASL instead of AGL). It would work near coastlines, but nowhere else (using FOV + ASL).
That's annoying, I assumed the (usable) height would be in there.
But you might want to read osmwiki:JOSM/Plugins/PicLayer#Usage. You can manipulate the photo location, rotation, scale, and so on, with the piclayer plugin.
I really want to avoid doing this manually if possible. Or at least the majority of it, then just some manual tweaks after.
TBH, I'd probably look at https://opendronemap.org/ for processing aerial images. I've used it personally, and it works fairly well. It uses Mapillary's Structure From Motion library to create an aerial image. It can also do point clouds and elevation models (building:height).
I have used it, I felt that the output images had a few too many issues to trace buildings from, so I was trying just taking images directly above key buildings. I need to keep playing with the settings. I didn't know it could do point clouds either. Is there an easy way to open odm_orthophoto.tif in JOSM?
With my drone (Parrot Anafi), I set the drone to take a picture every 16ft (pictures taken straight down -- theoretically, ODM can do well with 45 degree pictures, but I am typically looking at single family homes from close up, and trying to avoid going over other people's property).
DJI Mavric 2 Zoom. I'm testing it at 80m or 100m. I don't think DJI GS Pro (flight plan app) shows how frequently the images are taken, it shows overlap which defaults to 75% front and 70% side. I'll have to test reducing them.
There is also a gif at the top of that page that quickly shows how to position a photo manually.
I can't get the second part (after clicking the red arrow) to work, but I expect it's me doing something wrong.
comment:4 by , 3 years ago
Replying to CjMalone:
That's annoying, I assumed the (usable) height would be in there.
Maybe it is, and the manufacturer is using something stupid for it. Or I missed it.
I really want to avoid doing this manually if possible. Or at least the majority of it, then just some manual tweaks after.
Fair.
I have used it, I felt that the output images had a few too many issues to trace buildings from, so I was trying just taking images directly above key buildings. I need to keep playing with the settings. I didn't know it could do point clouds either. Is there an easy way to open odm_orthophoto.tif in JOSM?
osmwiki:JOSM/Plugins/ImportImagePlugin
But there is also a plugin for WebODM that lets it serve JOSM the image via remote control (WMS IIRC).
DJI Mavric 2 Zoom. I'm testing it at 80m or 100m. I don't think DJI GS Pro (flight plan app) shows how frequently the images are taken, it shows overlap which defaults to 75% front and 70% side. I'll have to test reducing them.
If it is a flight planning app, it might be able to take images every x meters. I don't use it, so I don't know where to look.
by , 3 years ago
Attachment: | odm_orthophoto.tif added |
---|
comment:5 by , 3 years ago
2022-08-22 22:55:10.420 INFO: ImportImagePlugin LoadImageAction: File chosen: /home/cj/Documents/Pictures/Aerial/Raj, Small/odm_orthophoto/odm_orthophoto.tif 2022-08-22 22:55:10.438 WARNING: Can't load a service for category "Operation". Cause is "ServiceConfigurationError: org.opengis.coverage.processing.Operation: Provider org.geotools.coverage.processing.operation.ShadedRelief could not be instantiated". java.util.ServiceConfigurationError: org.opengis.coverage.processing.Operation: Provider org.geotools.coverage.processing.operation.ShadedRelief could not be instantiated at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:582) at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:804) at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:722) at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1395) at org.geotools.util.factory.FactoryRegistry.register(FactoryRegistry.java:967) at org.geotools.util.factory.FactoryRegistry.scanForPlugins(FactoryRegistry.java:873) at org.geotools.util.factory.FactoryRegistry.scanForPluginsIfNeeded(FactoryRegistry.java:903) at org.geotools.util.factory.FactoryRegistry.getFactories(FactoryRegistry.java:265) at org.geotools.coverage.processing.CoverageProcessor.scanForPlugins(CoverageProcessor.java:600) at org.geotools.coverage.processing.CoverageProcessor.getOperation(CoverageProcessor.java:477) at org.openstreetmap.josm.plugins.ImportImagePlugin.PluginOperations.reprojectCoverage(PluginOperations.java:74) at org.openstreetmap.josm.plugins.ImportImagePlugin.ImageLayer.createImage(ImageLayer.java:94) at org.openstreetmap.josm.plugins.ImportImagePlugin.ImageLayer.<init>(ImageLayer.java:74) at org.openstreetmap.josm.plugins.ImportImagePlugin.LoadImageAction.actionPerformed(LoadImageAction.java:47) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1020) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1064) at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342) at java.desktop/java.awt.Component.processEvent(Component.java:6400) at java.desktop/java.awt.Container.processEvent(Container.java:2263) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) Caused by: org.opengis.coverage.processing.OperationNotFoundException: No such "ShadedRelief" operation for this processor. at org.geotools.coverage.processing.OperationJAI.getOperationDescriptor(OperationJAI.java:209) at org.geotools.coverage.processing.operation.ShadedRelief.<init>(ShadedRelief.java:153) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:780) ... 50 more 2022-08-22 22:55:10.470 INFO: Problem occurs when computing a tile by the owner. java.lang.NullPointerException at it.geosolutions.imageioimpl.plugins.tiff.TIFFDeflateDecompressor.decodeRaw(TIFFDeflateDecompressor.java:136) at it.geosolutions.imageio.plugins.tiff.TIFFDecompressor.decode(TIFFDecompressor.java:2637) at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.decodeTile(TIFFImageReader.java:1764) at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.read(TIFFImageReader.java:2075) at com.sun.media.jai.imageioimpl.ImageReadOpImage.computeTile(ImageReadOpImage.java:697) at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:904) at javax.media.jai.OpImage.getTile(OpImage.java:1129) at it.geosolutions.jaiext.iterators.RandomIterFallbackByte.makeCurrent(RandomIterFallbackByte.java:124) at it.geosolutions.jaiext.iterators.RandomIterFallbackByte.getSample(RandomIterFallbackByte.java:133) at it.geosolutions.jaiext.warp.WarpNearestOpImage.computeRectByte(WarpNearestOpImage.java:162) at it.geosolutions.jaiext.warp.WarpOpImage.computeRect(WarpOpImage.java:294) at it.geosolutions.jaiext.warp.WarpOpImage.computeTile(WarpOpImage.java:241) at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:904) at javax.media.jai.OpImage.getTile(OpImage.java:1129) at javax.media.jai.PlanarImage.copyData(PlanarImage.java:2343) at javax.media.jai.RenderedOp.copyData(RenderedOp.java:2299) at javax.media.jai.PlanarImage.getAsBufferedImage(PlanarImage.java:2525) at javax.media.jai.PlanarImage.getAsBufferedImage(PlanarImage.java:2546) at org.geotools.image.ImageWorker.getBufferedImage(ImageWorker.java:644) at org.openstreetmap.josm.plugins.ImportImagePlugin.ImageLayer.createImage(ImageLayer.java:153) at org.openstreetmap.josm.plugins.ImportImagePlugin.ImageLayer.<init>(ImageLayer.java:74) at org.openstreetmap.josm.plugins.ImportImagePlugin.LoadImageAction.actionPerformed(LoadImageAction.java:47) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1020) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1064) at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342) at java.desktop/java.awt.Component.processEvent(Component.java:6400) at java.desktop/java.awt.Container.processEvent(Container.java:2263) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) 2022-08-22 22:55:10.472 INFO: Problem occurs when computing a tile by the owner. java.lang.NullPointerException at it.geosolutions.imageioimpl.plugins.tiff.TIFFDeflateDecompressor.decodeRaw(TIFFDeflateDecompressor.java:136) at it.geosolutions.imageio.plugins.tiff.TIFFDecompressor.decode(TIFFDecompressor.java:2637) at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.decodeTile(TIFFImageReader.java:1764) at it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader.read(TIFFImageReader.java:2075) at com.sun.media.jai.imageioimpl.ImageReadOpImage.computeTile(ImageReadOpImage.java:697) at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:904) at javax.media.jai.OpImage.getTile(OpImage.java:1129) at it.geosolutions.jaiext.iterators.RandomIterFallbackByte.makeCurrent(RandomIterFallbackByte.java:124) at it.geosolutions.jaiext.iterators.RandomIterFallbackByte.getSample(RandomIterFallbackByte.java:133) at it.geosolutions.jaiext.warp.WarpNearestOpImage.computeRectByte(WarpNearestOpImage.java:162) at it.geosolutions.jaiext.warp.WarpOpImage.computeRect(WarpOpImage.java:294) at it.geosolutions.jaiext.warp.WarpOpImage.computeTile(WarpOpImage.java:241) at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:904) at javax.media.jai.OpImage.getTile(OpImage.java:1129) at javax.media.jai.PlanarImage.copyData(PlanarImage.java:2343) at javax.media.jai.RenderedOp.copyData(RenderedOp.java:2299) at javax.media.jai.PlanarImage.getAsBufferedImage(PlanarImage.java:2525) at javax.media.jai.PlanarImage.getAsBufferedImage(PlanarImage.java:2546) at org.geotools.image.ImageWorker.getBufferedImage(ImageWorker.java:644) at org.openstreetmap.josm.plugins.ImportImagePlugin.ImageLayer.createImage(ImageLayer.java:153) at org.openstreetmap.josm.plugins.ImportImagePlugin.ImageLayer.<init>(ImageLayer.java:74) at org.openstreetmap.josm.plugins.ImportImagePlugin.LoadImageAction.actionPerformed(LoadImageAction.java:47) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1020) at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1064) at java.desktop/java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:297) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6635) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342) at java.desktop/java.awt.Component.processEvent(Component.java:6400) at java.desktop/java.awt.Container.processEvent(Container.java:2263) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2772) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) 2022-08-22 22:55:10.473 SEVERE: ImportImagePlugin LoadImageAction: Error while creating image layer: null
comment:8 by , 3 years ago
Component: | Core → Plugin geotools |
---|
Running the file through exiftool, I got (trimmed):
Depending upon the manufacturer (DJI), the Resolution exif data might be in pixels, mm, inches, etc. For what you want, GPSAltitude is useless (ASL instead of AGL). It would work near coastlines, but nowhere else (using FOV + ASL).
But you might want to read osmwiki:JOSM/Plugins/PicLayer#Usage. You can manipulate the photo location, rotation, scale, and so on, with the piclayer plugin.
TBH, I'd probably look at https://opendronemap.org/ for processing aerial images. I've used it personally, and it works fairly well. It uses Mapillary's Structure From Motion library to create an aerial image. It can also do point clouds and elevation models (
building:height
).With my drone (Parrot Anafi), I set the drone to take a picture every 16ft (pictures taken straight down -- theoretically, ODM can do well with 45 degree pictures, but I am typically looking at single family homes from close up, and trying to avoid going over other people's property).