Open brancomat opened 2 years ago
in RMAP I use Latitude/Longitude, reftime, imagedescription,usercomment
https://github.com/r-map/rmap/blob/0ef0ce01ecf0e88b7530e1d09cc303fa53db473e/python/rmap/exifutils.py#L153 but usercomment is not usefull as arkimet metadata (I am not sure!).
The dimensions I think are not usefull metadata too.
I use imagedescription to identify the provider of image (is the only standard exif metadata I found usefull for this) but is possible to change it.
So I suggest those minimal metadata for arkimet: Latitude/Longitude, reftime, imagedescription
those are the linked exif metadata:
In @brancomat example we have also altitude -> station height, although that's not usually metadatum (using jhead
):
GPS Latitude : N **d 30m 2.7179s
GPS Longitude: E **d 19m 43.2263s
GPS Altitude : 98.00m
for the webcam network we need other metadata. For example:
Do you expect to need to have a dataset with hybrid image formats, like .png
and .jpg
?
I'd say no. The dataset content format should be consistent (as in any other arkimet dataset). Should we face multiple source formats, either the import procedure should standardize the format or we could create different datasets based on image format.
Ok, perfect. Mixing different formats in the same dataset would require a significantly more extensive redesign work
We have initial JPEG support:
$ gzip -cd test/data/jpeg/autumn.jpg.gz > /tmp/autumn.jpg
$ arki-scan --yaml /tmp/autumn.jpg
Source: BLOB(jpeg,/tmp/autumn.jpg:0+94701)
Reftime: 2021-10-24T13:11:40Z
Area: GRIB(latfirst=459497, latlast=459497, lonfirst=110197, lonlast=110197, type=0)
Note: [2021-11-24T14:02:36Z]Scanned from autumn.jpg
The scanning script is in conf/scan/jpeg.py
and is a draft: in particular, the area should be a point, but not knowing how to represent a point I used a rectangle collapsed into a point just to make a demo.
Most of the pieces should be there to start a JPEG dataset. We now need real-world test samples to fine tune the scanner, and see if the existing metadata types are ok or we neeed to add new ones
Most of the pieces should be there to start a JPEG dataset. We now need real-world test samples to fine tune the scanner, and see if the existing metadata types are ok or we neeed to add new ones
@spanezz can you describe the metadata ?
I don't know if we have ever compiled a complete census of all metadata available in arkimet: the variety grew quite organically.
It may be time to do it, and it's a non trivial amount of work that would warrant its own ticket.
Can you (plural you) confirm that we don't have that documentation, and it's not that we actually have it and I cannot find it, and then open a ticket asking for it?
Coming back to a previous message
We have initial JPEG support:
Area: GRIB(latfirst=459497, latlast=459497, lonfirst=110197, lonlast=110197, type=0)
The scanning script is in
conf/scan/jpeg.py
and is a draft: in particular, the area should be a point, but not knowing how to represent a point I used a rectangle collapsed into a point just to make a demo.
Why can't we use
Area: GRIB(lat=3993000, lon=971000)
as it is done for BUFR stations (although it says GRIB)?
I don't know if we have ever compiled a complete census of all metadata available in arkimet: the variety grew quite organically.
I ask for JPEG only dataset. @spanez ask:
if the existing metadata types are ok or we neeed to add new ones
which "existing metadata types"?
see above:
$ gzip -cd test/data/jpeg/autumn.jpg.gz > /tmp/autumn.jpg
$ arki-scan --yaml /tmp/autumn.jpg
Source: BLOB(jpeg,/tmp/autumn.jpg:0+94701)
==> Reftime: 2021-10-24T13:11:40Z
==> Area: GRIB(latfirst=459497, latlast=459497, lonfirst=110197, lonlast=110197, type=0)
Note: [2021-11-24T14:02:36Z]Scanned from autumn.jpg
Area: GRIB(latfirst=459497, latlast=459497, lonfirst=110197, lonlast=110197, type=0)
Why can't we use
Area: GRIB(lat=3993000, lon=971000)
as it is done for BUFR stations (although it says GRIB)?
Good catch. I pushed the change, now it's the same as with BUFR
I don't know if we have ever compiled a complete census of all metadata available in arkimet: the variety grew quite organically. I ask for JPEG only dataset
The scanner for JPEG datasets can generate any metadata value that is used by all other scanners: arkimet doesn't have a concept of format-specific metadata.
Sometimes the name of a format makes it to metadata values, like in product:GRIB,…
, product:BUFR,…
, and that means that the product is described with a given set of values that follow the rules for product definitions in GRIB or BUFR standards.
if the existing metadata types are ok or we neeed to add new ones which "existing metadata types"?
I mean all the metadata available in arkimet for all other formats: can they be reused to describe everything needed for a JPEG, or do we need to create new ones? That's not something that we can answer up front, I think, and we'll see as we start putting real world data into a dataset, and figuring out what are the aspect of those data that we want to be able to query with arkimet
so we can use any metadata we suggest in the posts before for jpeg to query arkimet? For example:
do you fill
At the moment, none of that is filled. Deciding how to scan metadata is not something I can do up front, and it's something that grows organically from the intersection and interaction of at least the actual data that need to be stored, and the needs and use cases that underlie how the dataset will be queried.
I made a kind of an example scanning script, and I give it to you all to maintain and expand, like it happens with the other file formats. I can code technological requirements in arkimet, and the scanning script are the place where you all encode your very specific "business logic", so to speak
For what I see there are three separate tasks here:
Sounds about right. For each metadata actually needed, I'd need to see not just a pointer to the information to store/query, but also a high level description of real use case for it
After a chat with @spanezz we agreed to change the current python dependecy from exiftool
to PIL
to read EXIF metadata.
See also:
io ho usato piexif che è pure python https://github.com/hMatoba/Piexif
$ python3 -c "import this"|grep only
There should be one-- and preferably only one --obvious way to do it.
io ho usato piexif
I'd rather stick with an already packaged and mantained module (at least in the Red Hat ecosystem and in already enabled repos):
exiftool
is not packagedpiexif
is only packaged for fedora (no centOS)pillow
is already available for centOS and fedora
bonus points: we're already using pillow
at least in one of Meteosatlib scripts
Done: scanning now uses pillow, removing the need for the extra dependency
Dal progetto della rete di monitoraggio della costa con webcam ipotizziamo questi metadati come chiave univoche di accesso:
A quanto ho capito GPSIFD.GPSLatitudeRef
(e anche GPSIFD.GPSLongitudeRef
) definiscono solo il segno di lat e lon che sono unsigned, v. https://exiftool.org/TagNames/GPS.html dei gusti non si discute, per cui mi parrebbe più logico interpretare le coordinate nel nostro data model, come forse è già stato fatto, e non usare i tag originali come chiavi di accesso.
mi ero scordato GPSIFD.GPSLongitudeRef
Io sarei per tenere il più possibile i campi standard perchè presenti nella maggioranza delle immagini "consumer" (almeno per data e coordinate) sono presenti.
In python questa la funzione che utilizzo per estrarre lat e lon in RMAP e georeferenziare le immagini
class Rational:
"""A simple fraction class. Python 2.6 could use the inbuilt Fraction class."""
def __init__(self, num, den):
"""Create a number fraction num/den."""
self.num = num
self.den = den
def __repr__(self):
"""Return a string representation of the fraction."""
return "%s / %s" % (self.num, self.den)
def as_tuple(self):
"""Return the fraction a numerator, denominator tuple."""
return (self.num, self.den)
def get_geo(exif_dict):
"""Return a tuple of (latitude, longitude)."""
def convert(x):
deg=Rational(x[0][0],x[0][1])
min=Rational(x[1][0],x[1][1])
sec=Rational(x[2][0],x[2][1])
return (float(deg.num) / deg.den) + \
(1/60.0 * float(min.num) / min.den) + \
(1/3600.0 * float(sec.num) / sec.den)
lat = convert(exif_dict["GPS"][piexif.GPSIFD.GPSLatitude])
lng = convert(exif_dict["GPS"][piexif.GPSIFD.GPSLongitude])
if exif_dict["GPS"][piexif.GPSIFD.GPSLatitudeRef] == "S":
lat = -lat
if exif_dict["GPS"][piexif.GPSIFD.GPSLongitudeRef] == "W":
lng = -lng
return lat, lng
Per i tag custom, parlando con Paolo si ipotizzava di usare il tag User Comment
in cui mettere un JSON con dentro i metadati.
La proposta è di usare una sintassi del genere:
User Comment = COMMENTO {% METADATI %} COMMENTO
L'elenco dei metadati è il seguente:
[pindicator, p1, p2]
[leveltype1,l1,leveltype2,l2]
channel=V|IR
(visibile o infrarosso) e direction=INTEGER
(direzione in gradi).La conversione in metadati arkimet potrebbe essere:
Timedef
GRIB1
proddef
con stile GRIB1
Il JSON sarebbe quindi una cosa del genere:
{
"timerange": [254, 0, 0],
"level": [103, 2000, null, null],
"product": { "channel": "V", "direction": 90}
}
@pat1 ti chiedo una review delle specifiche.
per me OK, ma proporrei di sostituire "direction" con: camera_pan camera_tilt camera_roll Camera angles: pan, tilt, roll
definendo: camera_pan: preso come fulcro la telecamera l'angolo formato partendo da nord in verso orario del il punto al centro dell'immagine espresso in gradi sessadecimali senza decimali; valori 0-359
camera_tilt: zero piano orizzontale, positivo verso il cielo, negativo verso terra, espresso in gradi sessadecimali senza decimali
camera_roll: zero piano verticale, zero in alto, l'angolo formato dalla rotazione dell'immagine positivo in senso orario, negativo antiorario
camera_pan: preso come fulcro la telecamera l'angolo formato partendo da nord in verso orario del il punto al centro dell'immagine espresso in gradi sessadecimali senza decimali; valori 0-359
camera_tilt: zero piano orizzontale, positivo verso il cielo, negativo verso terra, espresso in gradi sessadecimali senza decimali
camera_roll: zero piano verticale, zero in alto, l'angolo formato dalla rotazione dell'immagine positivo in senso orario, negativo antiorario
Questi metadati potrebbero essere tra gli standard:
0xb20b | 45579 | MpfInfo | Exif.MpfInfo.MPFYawAngle | Long | MPF Yaw Angle
0xb20c | 45580 | MpfInfo | Exif.MpfInfo.MPFPitchAngle | Long | MPF Pitch Angle
0xb20d | 45581 | MpfInfo | Exif.MpfInfo.MPFRollAngle | Long | MPF Roll Angle
Per quanto riguarda il livello, mi sfugge perché le informazioni GPS non possono essere usate:
0x0005 | 5 | GPSInfo | Exif.GPSInfo.GPSAltitudeRef | Byte | Indicates the altitude used as the reference altitude. If the reference is sea level and the altitude is above sea level, 0 is given. If the altitude is below sea level, a value of 1 is given and the altitude is indicated as an absolute value in the GSPAltitude tag. The reference unit is meters. Note that this tag is BYTE type, unlike other reference tags.
0x0006 | 6 | GPSInfo | Exif.GPSInfo.GPSAltitude | Rational | Indicates the altitude based on the reference in GPSAltitudeRef. Altitude is expressed as one RATIONAL value. The reference unit is meters.
Rimarrebbero, a quel punto, solo channel
, timerange
(e level
, se quello del GPS non va bene).
@pat1 te la riassegno per una review.
Per quanto riguarda il livello, mi sfugge perché le informazioni GPS non possono essere usate
secondo me per compatibilità con tutto il resto e per indiscussa versatilità del sistema WMO e inoltre l'altitudine usata come riferimento non mi è chiarissimo come usarla. Ma se è conforme usarla come:
ma secondo me essendo da GPS si intende tutt'altro.
Channel nelle immagini pare abbia un altro significato lo sostituirei con "spectral band" o sinteticamente "band" e potrebbe essere declinato in:
oppure:
ma secondo me essendo da GPS si intende tutt'altro.
Ok, allora manteniamo il level dentro allo UserComment così siamo a posto.
Channel nelle immagini pare abbia un altro significato lo sostituirei con "spectral band" o sinteticamente "band"
Sul channel benissimo tramutarlo in band, ma io non ho idea di cosa si stia parlando, quindi scegli pure tu quali valori usare.
Non ho invece capito se
0xb20b | 45579 | MpfInfo | Exif.MpfInfo.MPFYawAngle | Long | MPF Yaw Angle 0xb20c | 45580 | MpfInfo | Exif.MpfInfo.MPFPitchAngle | Long | MPF Pitch Angle 0xb20d | 45581 | MpfInfo | Exif.MpfInfo.MPFRollAngle | Long | MPF Roll Angle
Possono andare bene oppure vogliamo metterli come metadati custom camera_pan, camera_roll e camera_tilt?
Non ho invece capito se
0xb20b | 45579 | MpfInfo | Exif.MpfInfo.MPFYawAngle | Long | MPF Yaw Angle 0xb20c | 45580 | MpfInfo | Exif.MpfInfo.MPFPitchAngle | Long | MPF Pitch Angle 0xb20d | 45581 | MpfInfo | Exif.MpfInfo.MPFRollAngle | Long | MPF Roll Angle
Possono andare bene oppure vogliamo metterli come metadati custom camera_pan, camera_roll e camera_tilt?
LONG è definito come 32-bit (4-byte) unsigned integer il che è già un problema perchè bisogna inventarsi una rappresentazione unsigned. Poi quei tag fanno parte di:
MPF Tags These tags are part of the CIPA Multi-Picture Format specification, and are found in the APP2 "MPF" segment of JPEG images.
Multi-Picture Format The file format includes MP extensions which enable to store multiple Individual Images in a single file. Individual Image has the same structure as Exif JPEG data.
quindi direi non c'entrano nulla con il nostro caso.
riassumendo oltre ai tag exif per lat, lon,datetime :
Per i metadati custom usare il tag User Comment
in cui mettere un JSON con dentro i metadati.
La proposta è di usare una sintassi del genere:
User Comment = COMMENTO {% METADATI %} COMMENTO
L'elenco dei metadati è il seguente:
[pindicator, p1, p2]
[leveltype1,l1,leveltype2,l2]
"band" e potrebbe essere declinato in:
oppure:
camera_pan camera_tilt camera_roll Camera angles: pan, tilt, roll
definendo: camera_pan: preso come fulcro la telecamera l'angolo formato partendo da nord in verso orario del il punto al centro dell'immagine espresso in gradi sessadecimali senza decimali; valori 0-359
camera_tilt: zero piano orizzontale, positivo verso il cielo, negativo verso terra, espresso in gradi sessadecimali senza decimali
camera_roll: zero piano verticale, zero in alto, l'angolo formato dalla rotazione dell'immagine positivo in senso orario, negativo antiorario
Il JSON sarebbe quindi una cosa del genere:
{
"timerange": [254, 0, 0],
"level": [103, 2000, null, null],
"product": { "camera_band": "VIS", "camera_pan": -78,"camera_roll":0}
}
La conversione in metadati arkimet potrebbe essere:
Timedef
GRIB1
proddef
con stile GRIB1
Per me va benissimo
Siete dei maghi! Aggiungo solo che la classificazione VIS, VIR,... SLW mi pare più adatta per definire la banda perché pare orientata alle applicazioni fotografiche e affini, mentre l'altra classificazione è più fisica, e la banda effettivamente usata potrebbe essere "a cavallo" tra 2 definizioni; però parlo un po' a sentimento.
Le spefiche sono state trasmesse alla ditta che dovrà generare i file JPEG. Attendiamo, per il proseguimento del lavoro, un file di test da parte loro.
@spanezz ti avviso non appena me lo inviano.
Assegno la issue a @pat1 (si veda e-mail "Tag EXIF per progetto camERa" di oggi) che dovrebbe verificare la correttezza dei tag EXIF nei file JPEG che la ditta ci sta mandando per poterteli poi passare.
Allego le specifiche v0.1 del progetto camERa Progetto camERa_ specifiche EXIF tag - v0.1.pdf.
Per ora, i metadati che sono sicuramente da implementare sono:
@pat1 allegherà poi dei file JPEG di esempio per la test suite.
NOME | Codice |
---|---|
RICCIONE (IAL RICCIONE) | 1 |
VALVERDE (IAL CESENATICO) | 2 |
PRESTIGE | 3 |
CESENATICO (B&B SOLEE) | 4 |
MARINA DI RAVENNA (BAGNO MARISOL) | 5 |
LIDO DI SPINA (BAGNO MARRAKESH) | 6 |
MARINA ROMEA (BAGNO NETTUNO) | 7 |
LIDO DI VOLANO (BAGNO CORMORANO) | 8 |
ST rappresenta il codice telecamera
Allego immagini di esempio. innagini.zip I metadati contenuti di livello e timerange non hanno contenuto sostanziale corretto ma formalmente si. Questi i metadati:
for file in [innagini.zip](https://github.com/ARPA-SIMC/arkimet/files/14102836/innagini.zip); do printf "\nExif info fron file: $file"; exiv2 -p a -u $file; done
Exif info fron file: RECSH_1_20240129_1200.jpgWarning: Directory Photo has an unexpected next pointer; ignored.
Warning: Directory GPSInfo has an unexpected next pointer; ignored.
Exif.Image.ExifTag Long 1 38
Exif.Photo.UserComment Undefined 224 charset=Unicode {% {"timerange": [205, 0, 900], "level": [264, null, null, null], "camera_pan": 40, ...
Exif.Image.GPSTag Long 1 276
Exif.GPSInfo.GPSLatitudeRef Ascii 2 North
Exif.GPSInfo.GPSLatitude Rational 3 43deg 59' 20"
Exif.GPSInfo.GPSLongitudeRef Ascii 2 East
Exif.GPSInfo.GPSLongitude Rational 3 12deg 41' 2"
Exif.GPSInfo.GPSTimeStamp Rational 3 12:00:00
Exif.GPSInfo.GPSDateStamp Ascii 11 2024:01:29
Exif info fron file: RECTM_1_20240129_1200.jpgWarning: Directory Photo has an unexpected next pointer; ignored.
Warning: Directory GPSInfo has an unexpected next pointer; ignored.
Exif.Image.ExifTag Long 1 38
Exif.Photo.UserComment Undefined 224 charset=Unicode {% {"timerange": [205, 0, 900], "level": [264, null, null, null], "camera_pan": 40, ...
Exif.Image.GPSTag Long 1 276
Exif.GPSInfo.GPSLatitudeRef Ascii 2 North
Exif.GPSInfo.GPSLatitude Rational 3 43deg 59' 20"
Exif.GPSInfo.GPSLongitudeRef Ascii 2 East
Exif.GPSInfo.GPSLongitude Rational 3 12deg 41' 2"
Exif.GPSInfo.GPSTimeStamp Rational 3 12:00:00
Exif.GPSInfo.GPSDateStamp Ascii 11 2024:01:29
Exif info fron file: SNAPSHOT_1_20240129_1200.jpgWarning: Directory Photo has an unexpected next pointer; ignored.
Warning: Directory GPSInfo has an unexpected next pointer; ignored.
Exif.Image.ExifTag Long 1 38
Exif.Photo.UserComment Undefined 220 charset=Unicode {% {"timerange": [254, 0, 0], "level": [264, null, null, null], "camera_pan": 40, "c ...
Exif.Image.GPSTag Long 1 272
Exif.GPSInfo.GPSLatitudeRef Ascii 2 North
Exif.GPSInfo.GPSLatitude Rational 3 43deg 59' 20"
Exif.GPSInfo.GPSLongitudeRef Ascii 2 East
Exif.GPSInfo.GPSLongitude Rational 3 12deg 41' 2"
Exif.GPSInfo.GPSTimeStamp Rational 3 12:00:00
Exif.GPSInfo.GPSDateStamp Ascii 11 2024:01:29
Exif info fron file: T1STK_1_20240129_1200.jpgWarning: Directory Photo has an unexpected next pointer; ignored.
Warning: Directory GPSInfo has an unexpected next pointer; ignored.
Exif.Image.ExifTag Long 1 38
Exif.Photo.UserComment Undefined 224 charset=Unicode {% {"timerange": [205, 0, 900], "level": [264, null, null, null], "camera_pan": 40, ...
Exif.Image.GPSTag Long 1 276
Exif.GPSInfo.GPSLatitudeRef Ascii 2 North
Exif.GPSInfo.GPSLatitude Rational 3 43deg 59' 20"
Exif.GPSInfo.GPSLongitudeRef Ascii 2 East
Exif.GPSInfo.GPSLongitude Rational 3 12deg 41' 2"
Exif.GPSInfo.GPSTimeStamp Rational 3 12:00:00
Exif.GPSInfo.GPSDateStamp Ascii 11 2024:01:29
Exif info fron file: TIMEX_1_20240129_1200.jpgWarning: Directory Photo has an unexpected next pointer; ignored.
Warning: Directory GPSInfo has an unexpected next pointer; ignored.
Exif.Image.ExifTag Long 1 38
Exif.Photo.UserComment Undefined 220 charset=Unicode {% {"timerange": [0, 0, 900], "level": [264, null, null, null], "camera_pan": 40, "c ...
Exif.Image.GPSTag Long 1 272
Exif.GPSInfo.GPSLatitudeRef Ascii 2 North
Exif.GPSInfo.GPSLatitude Rational 3 43deg 59' 20"
Exif.GPSInfo.GPSLongitudeRef Ascii 2 East
Exif.GPSInfo.GPSLongitude Rational 3 12deg 41' 2"
Exif.GPSInfo.GPSTimeStamp Rational 3 12:00:00
Exif.GPSInfo.GPSDateStamp Ascii 11 2024:01:29
Exif info fron file: TMXSH_1_20240129_1200.jpgWarning: Directory Photo has an unexpected next pointer; ignored.
Warning: Directory GPSInfo has an unexpected next pointer; ignored.
Exif.Image.ExifTag Long 1 38
Exif.Photo.UserComment Undefined 224 charset=Unicode {% {"timerange": [205, 0, 900], "level": [264, null, null, null], "camera_pan": 40, ...
Exif.Image.GPSTag Long 1 276
Exif.GPSInfo.GPSLatitudeRef Ascii 2 North
Exif.GPSInfo.GPSLatitude Rational 3 43deg 59' 20"
Exif.GPSInfo.GPSLongitudeRef Ascii 2 East
Exif.GPSInfo.GPSLongitude Rational 3 12deg 41' 2"
Exif.GPSInfo.GPSTimeStamp Rational 3 12:00:00
Exif.GPSInfo.GPSDateStamp Ascii 11 2024:01:29
visti i dati forniti dalla rete Camera propongo i seguenti adattamenti alle specifiche di codifica:
distinzione canale visibile tra RGB eBW nella tabella per camera_band:
aggiunta del metadato "postproc" nel json del UserComment con i seguenti valori:
Correzioni da apportare alla codifica di UserComment:
Valorizzare se possibile:
Timerange:
Level:
Allego la versione 1.0 delle specifiche Progetto camERa - specifiche EXIF tag v1.0.pdf
Con i file allegati nello zip a: https://github.com/ARPA-SIMC/arkimet/issues/277#issuecomment-1917673672 è quindi possibile procedere con i primi test in attesa dei file definitivi
As discussed in other fora, arkimet capabilities should be extended for archiving and indexing image file formats (i.e.: webcam outputs).
As a starting point it shoud support:
A minimal set of metadata to index could be:
Sample image: test.tar.gz
It would be nice if the resulting scanner could be accompanied by some documentation, to facilitate independence in metadata extensions / edits.
(this is a working draft, open to suggestions)