10

I have a map of an area and georeferenced photos. I need to be able to bring the pictures as points and then be able to click at a certain point and an image pop up.

I have revisited this issue, i managed to get this far but the pop up doesn't work.

enter image description here

1
  • 1
    Welcome to gis.stackexchange! Please note that a good question on this site is expected to show some degree of research on your part, i.e. what you have tried and - if applicable - code so far. For more info, you can check our faq.
    – underdark
    Aug 30, 2015 at 8:32

7 Answers 7

7

Like Maj said, I think that he easiest way to do something like you said is based om the map tips functionality. You can find the steps by step description here

  • First you should have a file name or a path in the points layer attributes associated with your pictures.
  • Second, edit the map tips with following HTML code :
    < img src="[% image %]" width=300 height=300 >
    Where [% image %]refers to the path of your picture
  • Alternatly you can set
    < img src="YOURPATHT/[% image %]" width=300 height=300 >
    if [% image %] refers to your file name.

    This was quite effective for me. Hope it helps.

  • 1
    • 3
      The HTML code in the answer didn't work as is, there is an extra space before img and the end should be />. Here is what worked for me in QGIS 2.18.9 (photo refers to the field name I'm using to store the image path): <img src=[% "photo" %] width=300 height=300 />
      – Techie_Gus
      Jun 9, 2017 at 18:30
    6

    At 3.8.0, here's what works for me:

    1. Create a point layer (Geopackage, shape file, etc)

    2. Create a text attribute field in the point layer:

    • call it, say, image_path
    • A reasonable maximum length is 320 characters, which will be able to contain the max Windows file path length. EDIT: If you are using a shapefile, the maximum length for a text field is 254 characters.
    1. Edit that attribute table and populate image_path with the file path and name for the image associated with each record, such as: file:///C:\TEST\IMAGES\photo_1.jpg
    • note the prefix file:///
    • this prefix is required, starting (I think) at QGIS 3.x. It doesn't appear to be necessary at 2.x
    • the image file name will likely be unique for each record in the table; that is, you will likely (but not necessarily) have a different image path/name for each map point.
    1. In the QGIS map document:
    • Open the point Layer Properties window > Display
    • In the HTML Map Tip pane, insert this line: <img src=[% "image_path" %] >, where image_path is the attribute field name from #2 above.
    • Click Ok
    1. Make sure that QGIS > View > Show Map Tips is checked on.

    2. Hover the cursor over one of the points.

    3. Voila, the image pops up!

    1
    • 3
      I had to add quotes around my path: <img src="[% (formula) %]" />
      – user94812
      Jul 20, 2019 at 1:05
    2

    You need to create a point file from your georeferenced photos (if you haven't already) and include the file-path of your image in the attribute table (which again may already exist depending on how the geo-ref photos have been created). It is then possible to use hyperlinks that will open your photo as a pop-up when you select the point in the map view.

    Below are some step by step guides, but essentially you need to use activate map tips in the layer properties so that the point will open a hyperlink when it is selected.

    https://www.youtube.com/watch?v=CUxkddOP3BQ http://manual.linfiniti.com/en/create_vector_data/actions.html

    More info on map tips:

    http://nathanw.net/2012/08/05/html-map-tips-in-qgis/

    qgis how to assign a field to map tips

    1

    While all other answers are correct,
    since 2018, the easiest way to do this is use the import photos plugin.
    It works very well and fast on a folder of georefrenced photos and creates fields for both the full path and the relative path to where you create the shapefile.

    2
    • ... well, would be great, but for me on Linux Mint with QGIS 3.8, it does not work. While importing of photos works (once, with the next import the plugin throws errors), the Viewer does not do anything, but show a tooltip-entry of the feature id.
      – Bernd V.
      Jul 5, 2019 at 17:13
    • 1
      You should consider reporting that, it might be a matter of a missing package in your OS or something that can be added to the plugin. Please remember that open source developers can't cover every usecase, and the plugin might have been developed on windows.
      – Dror Bogin
      Jul 26, 2019 at 5:25
    1

    I tried few options:

    1. Action: open : [%Path%] that's the easiest but more like hyperlink

    then I tried the

    1. identifier, attachment, Image

    2. HTML: <img src="[% (Path) %]" width=400pt></img>

    the path I added file:///, but not all images work, some do and some not I wonder why the format is like this: file:///X:/Erwitte/10400001/DSC_0207.JPG

    0

    What I did is create a postgres/ postgis database of all my pictures that includes a column thumbnail of the images at a reasonable scale. I can then create a layer that shows the picture locations as in the figure below.

    enter image description here

    I then made a plugin that when I click on the canvas it selects the nearest picture and displays it in a separate window with some meta data.

    enter image description here

    The core code of the plugin is:

    # -*- coding: utf-8 -*-
    """
    /***************************************************************************
     PictureLinker
                                     A QGIS plugin
     Shows picture of points
     Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                                  -------------------
            begin                : 2020-09-14
            git sha              : $Format:%H$
            copyright            : (C) 2020 by Bruno Vermeulen
            email                : [email protected]
     ***************************************************************************/
    
    /***************************************************************************
     *                                                                         *
     *   This program is free software; you can redistribute it and/or modify  *
     *   it under the terms of the GNU General Public License as published by  *
     *   the Free Software Foundation; either version 2 of the License, or     *
     *   (at your option) any later version.                                   *
     *                                                                         *
     ***************************************************************************/
    """
    import os
    
    # if using Linux then add a path to the site-packages
    if os.name == 'posix':
        import sys
        import_path = os.path.expanduser('~/.local/share/QGIS/QGIS3/profiles/default/python/site-packages')
        sys.path.insert(0, import_path)
    
    from qgis.core import (
        QgsProject, QgsDistanceArea, QgsFeatureRequest, QgsPointXY,
    )
    from qgis.gui import (
        QgsMapTool, QgsMapToolEmitPoint, QgsVertexMarker,
    )
    from qgis.PyQt.QtCore import Qt, QSettings, QTranslator, QCoreApplication
    from qgis.PyQt.QtGui import QIcon
    from qgis.PyQt.QtWidgets import QAction
    
    from .pyqt_picture import PictureShow
    
    # Initialize Qt resources from file resources.py
    from .resources import qInitResources, qCleanupResources
    qInitResources()
    
    pictures_layer = 'picture year'
    d = QgsDistanceArea()
    d.setEllipsoid('WGS84')
    
    
    class PicLayer():
        def __init__(self):
            layer = QgsProject.instance().mapLayersByName(pictures_layer)[0]
            self._features = list(layer.getFeatures(QgsFeatureRequest()))
    
        @property
        def nearest_feature(self):
            return self._nearest_feature
    
        def select_nearest_picture(self, point):
            ''' Calculates the distance from point and all pictures and selects the
                one with the minimum distance. Returns point either of closest
                picture or original point if not picture is found
                    argument: point: QgsPointXY
                    returns: point: QgsPointXY
            '''
            min_distance = float('inf')
            self._nearest_feature = None
            for feature in self._features:
                distance = d.measureLine(feature.geometry().asPoint(), point)
                if distance < min_distance:
                    min_distance = distance
                    self._nearest_feature = feature
    
            if self._nearest_feature:
                return self._nearest_feature.geometry().asPoint()
    
            else:
                return point
    
    
    class SelectPicMapTool(QgsMapToolEmitPoint):
        def __init__(self, canvas):
            self.canvas = canvas
            QgsMapToolEmitPoint.__init__(self, self.canvas)
    
            self.pic_layer = PicLayer()
            self.marker = None
            self.picshow = PictureShow()
    
        def reset(self):
            self.canvas.scene().removeItem(self.marker)
    
        def canvasPressEvent(self, e):
            point = self.toMapCoordinates(e.pos())
            point = QgsPointXY(point.x(), point.y())
    
            self.reset()
            point = self.pic_layer.select_nearest_picture(point)
            print(  #open console to see result
                f'picture id: {self.pic_layer.nearest_feature.attributes()[2]} - '
                f'year taken: {self.pic_layer.nearest_feature.attributes()[3]:.0f} - '
                f'x: {point.x():.6f}, y: {point.y():.6f}'
            )
            self.show_marker(point)
            self.show_picture()
    
        def show_marker(self, point):
            self.marker = QgsVertexMarker(self.canvas)
            self.marker.setColor(Qt.yellow)
            self.marker.setIconSize(6)
            self.marker.setIconType(QgsVertexMarker.ICON_CROSS)  # or ICON_BOX, ICON_X
            self.marker.setPenWidth(3)
            self.marker.setCenter(point)
            self.marker.show()
    
        def show_picture(self):
            self.picshow.cntr_select_pic(
                self.pic_layer.nearest_feature.attributes()[2])
            self.picshow.show_picture()
    
        def deactivate(self):
            self.reset()
            self.picshow.cntr_quit()
    
    
    class PictureLinker:
        """QGIS Plugin ImplementationL"""
    
        def __init__(self, iface):
            self.iface = iface
    
            self.plugin_dir = os.path.dirname(__file__)
    
            locale = QSettings().value('locale/userLocale')[0:2]
            locale_path = os.path.join(
                self.plugin_dir,
                'i18n',
                'PictureLinker_{}.qm'.format(locale))
    
            if os.path.exists(locale_path):
                self.translator = QTranslator()
                self.translator.load(locale_path)
                QCoreApplication.installTranslator(self.translator)
    
            self.actions = []
            self.menu = self.tr(u'&Picture linker')
    
        def tr(self, message):
            return QCoreApplication.translate('PictureLinker', message)
    
        def add_action(self,
                       icon_path,
                       text,
                       callback,
                       checkable=True,
                       enabled_flag=True,
                       add_to_menu=True,
                       add_to_toolbar=True,
                       status_tip=None,
                       whats_this=None,
                       parent=None):
    
            icon = QIcon(icon_path)
            action = QAction(icon, text, parent)
            action.triggered.connect(callback)
            action.setEnabled(enabled_flag)
    
    
            if checkable:
                action.setCheckable(True)
    
            if status_tip is not None:
                action.setStatusTip(status_tip)
    
            if whats_this is not None:
                action.setWhatsThis(whats_this)
    
            if add_to_toolbar:
                self.iface.addToolBarIcon(action)
    
            if add_to_menu:
                self.iface.addPluginToMenu(
                    self.menu,
                    action)
    
            self.actions.append(action)
    
            return action
    
        def initGui(self):
            icon_path = ':/plugins/picture_linker/icon.png'
            self.add_action(
                icon_path,
                text=self.tr('Show pictures'),
                callback=self.run,
                parent=self.iface.mainWindow())
    
        def unload(self):
            """Removes the plugin menu item and icon from QGIS GUI."""
            for action in self.actions:
                self.iface.removePluginMenu(
                    self.tr(u'&Picture linker'),
                    action
                )
    
                self.iface.removeToolBarIcon(action)
    
        def run(self):
            try:
                self.select_pic.deactivate()
    
            except AttributeError:
                pass
    
    
            if self.actions[0].isChecked():
                canvas = self.iface.mapCanvas()
                self.select_pic = SelectPicMapTool(canvas)
                canvas.setMapTool(self.select_pic)
    
            else:
                self.select_pic.deactivate()
                self.iface.mapCanvas().unsetMapTool(self.select_pic)
    

    Note 1:there is a module pyqt_picture that deals with extracting the thumbnail picture from the database and displays the picture

    Note 2: The thumbnail size is (600, 600) and for 25,000 pictures the database size is about 2 Gigabyte, so quite managable

    0

    The easiest way I found to do this is to use a plugin: ImportPhotos (https://mariosmsk.com/2019/07/02/qgis-plugin-importphotos/)

    It will allow You to:

    1. import GeoTagged photos to QGIS project,

    2. it will create an associate shp file and with another

    3. tool and double click it will open an image connected to a point data.

    enter image description here

    Your Answer

    By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

    Not the answer you're looking for? Browse other questions tagged or ask your own question.