[Merkaartor] geotagged images
Chris Browet
cbro at semperpax.com
Wed Aug 20 10:51:28 BST 2008
Hi,
I tried your patch but had a SEGFAULT. I used a file I quickly geotagged
with Picassa, so I guess it must be problematic. I'm attaching it for
reference. I was using exiv2 0.17 on Gentoo.
Could you please put somewhere working track/jpg that I can test further?
I don't have any.
Some remarks already:
1) As a rule of thumb, features needing external libraries should be
optional, so please be sure to adapt the Merkaartor.pro accordingly (i.e. à
la OSMARENDER)
2) Merkaartor being a multi-platform project, please be sure that exiv2 is
available/compilable on windows under mingw; I don't know about Mac. Bart?
3) Would it be possible before the final patch to format the sources to
avoid the 1-line IFs? I somewhat find them unreadable.
Thanks already
- Chris -
2008/8/19 Timo Schlüßler <timo at schluessler.org>
> For all who want to test my implementation, here is the patch. It's not
> ready at all but you can give it a try and send me bugs.
>
> You have to apply the patch and then add the files to the directory Map.
>
> regards
>
> Timo Schlüßler wrote:
>
> Hello,
>
> I think this would be a very great feature for merkaartor and I would
> like to implement it.
>
> But before starting with that, I want to ask you if you are (still)
> interested in a "geotagged images"-feature or if there's yet a plugin for
> merkaartor doing this.
>
> best regards,
> timo
>
>
> Hanno Böck wrote:
>
> Hi,
>
> I'm glad merkaartor seems to get better, as I don't really like josm (and I
> even less like potlach).
>
> However, there's one thing that I'm using for all my mapping activity and that
> is using geotagged images. That's the single reason I'm stuck with josm.
> I want a feature to show locations of jpeg images (by their exif gps tags) and
> show then on a click. josm has two plugins for that, I like the interface of
> AfPifoJ better than geotagged.
>
> Is this feature planned (or even still possible and I didn't find it)?
>
>
>
> ------------------------------
>
> _______________________________________________
> Merkaartor mailing listMerkaartor at openstreetmap.orghttp://lists.openstreetmap.org/cgi-bin/mailman/listinfo/merkaartor
>
> ------------------------------
>
> _______________________________________________
> Merkaartor mailing listMerkaartor at openstreetmap.org
> http://lists.openstreetmap.org/listinfo/merkaartor
>
>
> Index: MainWindow.h
> ===================================================================
> --- MainWindow.h (revision 9959)
> +++ MainWindow.h (working copy)
> @@ -8,6 +8,7 @@
> #include <QProgressBar>
> #include <QLabel>
>
> +
> class LayerDock;
> class MapDocument;
> class MapLayer;
> @@ -18,6 +19,7 @@
> class DirtyDock;
> class QGPS;
> class FeaturePainter;
> +class GeoImage;
>
> class MainWindow : public QMainWindow, public Ui::MainWindow
> {
> Index: MainWindow.cpp
> ===================================================================
> --- MainWindow.cpp (revision 9959)
> +++ MainWindow.cpp (working copy)
> @@ -31,6 +31,7 @@
> #include "Map/Road.h"
> #include "Map/RoadManipulations.h"
> #include "Map/TrackPoint.h"
> +#include "Map/GeoImage.h"
> #include "PaintStyle/EditPaintStyle.h"
> #include "PaintStyle/PaintStyleEditor.h"
> #include "Sync/SyncOSM.h"
> @@ -391,6 +392,7 @@
> "OpenStreetMap binary format (*.osb)\n" \
> "Noni GPSPlot format (*.ngt)\n" \
> "NMEA GPS log format (*.nmea *.nme)\n" \
> + "Geotagged images (*.jpg)\n" \
> "All Files (*)")
> #define FILTER_IMPORT_SUPPORTED \
> tr("Supported formats (*.gpx *.osm *.osb *.ngt *.nmea *.nme)\n" \
> @@ -538,7 +540,16 @@
> return;
>
> QStringList fileNames(fileList);
> +
> + QStringList images = fileNames.filter(".jpg", Qt::CaseInsensitive);
> + if (!images.isEmpty()) {
> + GeoImage::loadImages(images, theDocument, theView);
> + QString cur;
> + foreach (cur, images) fileNames.removeAll(cur);
> + }
>
> + if (fileNames.isEmpty()) return;
> +
> QApplication::setOverrideCursor(Qt::BusyCursor);
> theLayers->setUpdatesEnabled(false);
> view()->setUpdatesEnabled(false);
> @@ -549,6 +560,7 @@
> while (it.hasNext())
> {
> const QString & fn = it.next();
> +
> if (fn.endsWith(".mdc") == false)
> continue;
>
> Index: Merkaartor.pri
> ===================================================================
> --- Merkaartor.pri (revision 9959)
> +++ Merkaartor.pri (working copy)
> @@ -36,6 +36,7 @@
> ./Map/Road.h \
> ./Map/RoadManipulations.h \
> ./Map/TrackPoint.h \
> +./Map/GeoImage.h \
> ./Map/TrackSegment.h \
> ./MapView.h \
> ./PaintStyle/EditPaintStyle.h \
> @@ -84,6 +85,7 @@
> ./Map/Road.cpp \
> ./Map/RoadManipulations.cpp \
> ./Map/TrackPoint.cpp \
> +./Map/GeoImage.cpp \
> ./Map/TrackSegment.cpp \
> ./MapView.cpp \
> ./Interaction/CreateAreaInteraction.cpp \
> Index: Merkaartor.pro
> ===================================================================
> --- Merkaartor.pro (revision 9959)
> +++ Merkaartor.pro (working copy)
> @@ -109,3 +109,5 @@
> }
> QT += webkit
> }
> +
> +LIBS += -lexiv2
> Index: Map/ImportGPX.cpp
> ===================================================================
> --- Map/ImportGPX.cpp (revision 9959)
> +++ Map/ImportGPX.cpp (working copy)
> @@ -88,6 +88,7 @@
> if (!t.isNull() && t.tagName() == "trkpt")
> {
> TrackPoint* Pt = importTrkPt(t,theDocument,
> theLayer, theList);
> + Pt->setParent(S);
> if (MakeSegment)
> S->add(Pt);
> progress.setValue(progress.value()+1);
> Index: Map/MapDocument.cpp
> ===================================================================
> --- Map/MapDocument.cpp (revision 9959)
> +++ Map/MapDocument.cpp (working copy)
> @@ -372,8 +372,8 @@
> QVector<MapFeature*> theFeatures;
> for (VisibleFeatureIterator i(this); !i.isEnd(); ++i) {
> if (!layerType)
> - theFeatures.append(i.get());
> - else
> + qDebug() << "append :)";
> + else
> if (i.get()->layer()->className() == *layerType)
> theFeatures.append(i.get());
> }
>
> #include "GeoImage.h"
>
> #include "Command/DocumentCommands.h"
>
> /*#include <QtGui/QStandardItemModel>
> #include <QtGui/QDialog>
> #include <QtGui/QListView>
> #include <QtGui/QDialogButtonBox>*/
> #include <QtGui/QInputDialog>
> #include <QtGui/QMessageBox>
>
> class TrackSegment;
>
> GeoImage::GeoImage(TrackPoint * Pt, QImage img)
> : TrackPoint(*Pt), Image(img)
> {
> }
>
> GeoImage::~GeoImage()
> {
> }
>
> void GeoImage::draw(QPainter& P, const Projection& theProjection)
> {
>
> QPointF me = theProjection.project(position());
> P.setPen(QPen(QColor(0, 0, 0), 2));
> QRectF box(me - QPointF(10, 6), me + QPointF(10, 6));
> P.drawRect(box);
> bound = CoordBox(theProjection.inverse(box.topLeft()),
> theProjection.inverse(box.bottomRight()));
> }
> void GeoImage::drawFocus(QPainter& P, const Projection& theProjection)
> {
> QPointF me = theProjection.project(position());
> double aspect = (double)Image.height() / (double)Image.width();
> QPointF middle(P.device()->width()*0.2, aspect *
> P.device()->width()*0.2);
> P.drawImage(QRectF(me - middle, me + middle), Image);
> }
>
> /*CoordBox GeoImage::boundingBox(void)
> {
> qDebug() << bound.topLeft().lat() << bound.topLeft().lon() <<
> bound.bottomRight().lat();
> if (bound.isNull()) return TrackPoint::boundingBox();
> else return bound;
> }*/
>
>
> void GeoImage::loadImages(QStringList fileNames, MapDocument *theDocument,
> MapView *theView)
> {
> QString file;
> QImage img;
> QDateTime time;
> bool foundTime;
>
> Exiv2::Image::AutoPtr image;
> Exiv2::ExifData *exifData;
> Exiv2::ExifData::const_iterator i, end;
>
> MapLayer *theLayer;
> {
> QStringList layers;
> unsigned int i;
> for (i=0;i<theDocument->layerSize();i++)
> layers.append(theDocument->getLayer(i)->name());
>
> bool ok;
> QString layer = QInputDialog::getItem(NULL,
> MainWindow::tr("Load geotagged Images"),
> MainWindow::tr("Select the layer to which the images
> belong:"), layers, 0, false, &ok);
> if (ok && !layer.isEmpty())
> theLayer =
> theDocument->getLayer(layers.indexOf(layer));
> else return;
>
> /*
> QDialog dlg;
>
> QVBoxLayout layout(&dlg);
> QLabel text("Select the layer the images belong to.");
> QListView list(&dlg);
> QStandardItemModel *model = new QStandardItemModel(&list);
> list.setModel(model);
> list.setSelectionMode(QAbstractItemView::SingleSelection);
> QDialogButtonBox buttons(QDialogButtonBox::Ok |
> QDialogButtonBox::Cancel);
> layout.addWidget(&text, 0);
> layout.addWidget(&list, 1);
> layout.addWidget(&buttons, 2, Qt::AlignRight);
>
> dlg.setWindowTitle("Load geotagged Images");
>
> unsigned int i;
> qDebug() << theDocument->layerSize();
> for (i=0;i<theDocument->layerSize();i++)
> model->appendRow(new QStandardItem(theDocument->getLayer(i)->name()));
>
> dlg.connect(&buttons, SIGNAL(accepted()), &dlg,
> SLOT(accept()));
> dlg.connect(&buttons, SIGNAL(rejected()), &dlg,
> SLOT(reject()));
> if (dlg.exec() != QDialog::Accepted) return;
>
> QModelIndexList selection =
> list.selectionModel()->selectedRows();
> if (selection.size() != 1) return;
> theLayer = theDocument->getLayer(selection.first().row());
>
> delete model;
> */
> }
>
> CommandList * theList = new CommandList(MainWindow::tr("Loading
> Images"));
>
> bool ok;
> int offset = QInputDialog::getInteger( NULL, MainWindow::tr("Set
> offset"),
> MainWindow::tr("Specify an offset\n(positive values will position
> the images more to the end of the track):"),
> 0, 0, (int) ((unsigned int)-1 / 2), 1, &ok);
> qDebug() << (unsigned int)-1 << (int)((unsigned int)-1 /2);
> if (!ok) offset = 0;
>
> foreach(file, fileNames) {
> if (!img.load(file)) { if (warning(MainWindow::tr("Image
> broken"), MainWindow::tr("Cannot open image %1.").arg(file))) continue; else
> return;}
> if (img.isNull()) continue;
>
> image = Exiv2::ImageFactory::open(file.toAscii().constData());
> if (image.get() == 0) { qWarning("Error with exiv2 in
> %s.\n", file.toAscii().constData()); continue; }
> image->readMetadata();
>
> exifData = & image->exifData();
> if (exifData->empty()) {
> qWarning("No exif data. Skipping.\n"); continue;
> }
> end = exifData->end();
> foundTime = false;
> for (i = exifData->begin(); i != end; i++) {
> if (i->key() == "Exif.Image.DateTime") {
> time =
> QDateTime::fromString(i->value().toString().c_str(), "yyyy:MM:dd hh:mm:ss");
> qDebug() << "time is" << time;
> foundTime = true;
> }
> }
> if (!foundTime) { if (warning(MainWindow::tr("No
> timestamp"), MainWindow::tr("Image doesn't provide any time information.")))
> continue; else return; }
>
>
> time = time.addSecs(offset);
>
> qDebug() << theLayer;
> qDebug() << "theLayer" << theLayer->size();
> MapFeature *feature = NULL, *bestFeature = NULL;
> TrackPoint *Pt;
> unsigned int secondsTo = (unsigned int)-1, a;
> unsigned int u;
> for (u=0; u<theLayer->size(); feature = theLayer->get(u++))
> {
> if (!feature) { qDebug() << "is this a bug???";
> continue; } // TODO
> if (!(Pt = dynamic_cast<TrackPoint*>(feature)))
> continue;
> a = time.secsTo(Pt->time());
> if (a < secondsTo) { secondsTo = a; bestFeature =
> feature; }
> }
> if (!bestFeature) { qDebug() << "no features found";
> continue; }
>
> if (secondsTo >= 15)
> if ( QMessageBox::question(NULL,
> MainWindow::tr("Wrong image?"),
> MainWindow::tr("Image \"%1\" was taken %2 seconds
> before the next trackpoint was recorded.\n" \
> "Do you still want to use
> it?").arg(file).arg(secondsTo), QMessageBox::Yes | QMessageBox::No,
> QMessageBox::No ) != QMessageBox::Yes) continue;
>
> TrackSegment *S;
> int idx;
> if (bestFeature->sizeParents() == 1 &&
> (Pt = dynamic_cast<TrackPoint*>(bestFeature)) &&
> (S =
> dynamic_cast<TrackSegment*>(bestFeature->getParent(0))) )
> idx = S->find(Pt);
> else { qWarning() << "Can't access TrackPoint or it's parent
> or the parent is not a TrackSegment!\n"; continue; }
>
> if (bestFeature->deleteChildren(theDocument, theList)) {
> std::vector<MapFeature*> Alternatives;
> theList->add(new RemoveFeatureCommand(theDocument,
> Pt, Alternatives));
> }
>
> GeoImage * GeoPoint = new GeoImage(Pt, QImage(file));
> theList->add(new AddFeatureCommand(theLayer, GeoPoint,
> false));
>
> S->add(GeoPoint, idx);
> }
> if (theList->size()) {
> theDocument->addHistory(theList);
> theView->invalidate(true, false);
> }
> else delete theList;
>
> }
>
> bool GeoImage::warning(QString title, QString message)
> {
> if ( QMessageBox::warning ( NULL, title, message,
> QMessageBox::Ignore | QMessageBox::Cancel, QMessageBox::Ignore ) ==
> QMessageBox::Ignore) return true;
> else return false;
> }
>
>
> #include "Map/TrackPoint.h"
> #include "Map/TrackSegment.h"
> #include "Map/Projection.h"
> #include "MapView.h"
> #include <QtGui/QPainter>
> #include <exiv2/image.hpp>
> #include <exiv2/exif.hpp>
> #include "TrackPoint.h"
>
> class GeoImage : public TrackPoint
> {
> public:
> GeoImage(TrackPoint *Pt, QImage img);
> virtual ~GeoImage();
>
> static void loadImages(QStringList fileNames, MapDocument
> *theDocument, MapView *theView);
>
> virtual void draw(QPainter& P, const Projection& theProjection);
> virtual void drawFocus(QPainter& P, const Projection&
> theProjection);
> //virtual CoordBox boundingBox(void);
>
> private:
> QImage Image;
> CoordBox bound;
>
> static bool warning(QString title, QString message);
> };
>
>
> _______________________________________________
> Merkaartor mailing list
> Merkaartor at openstreetmap.org
> http://lists.openstreetmap.org/listinfo/merkaartor
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstreetmap.org/pipermail/merkaartor/attachments/20080820/29791c00/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 103117.jpg
Type: image/jpeg
Size: 66927 bytes
Desc: not available
URL: <http://lists.openstreetmap.org/pipermail/merkaartor/attachments/20080820/29791c00/attachment.jpg>
More information about the Merkaartor
mailing list