[Qt-interest] New image metadata parser based on the Qt
Jason H
scorp1us at yahoo.com
Wed Jan 26 18:27:11 CET 2011
Odd that you bring this up. I had posted something in qt-mobility a bit ago...
I used Qt to parse DICOM files, in which the metadata is crucially important. I
actually came up with a tag "scanner" and "collector" paradigm. DICOM has nested
metadata, and can be several KB worth. I also had streaming requirements (no
ability to load whole file into memory).
So I created a tag scanner that emitted a "tag" and "value" The tags are defined
by DICOM, and are identifiers for discrete metadata elements like height, width,
etc. The value could be various types, but each tag has a defined type (date,
time, integer, etc) so QVariant was a natural choice. The tags were defined as
unsigned ints, since they took two 16-bit unsigned numbers (first is "group",
second is "element", where group is like "patient" or "image" to which the
element applies).
Anyway, the simplified scanner class (we're not talking nested data yet) has 3
signals, 1 function:
signal begin() - emitted after successful file open
signal tag(uint id, QVariant value) - emitted as a tag is found
signal end() - emitted when all tags are complete
function read() - starts reading
The simplified collector class has three slots:
begin()
tag(int uid, qvariant value)
end()
Now, in order to use the collector, you subclass it and override tag(..)
Here, you can "collect" them in a simple public QMap<uint, QVariant>, or do
something much more interesting.
For instance, I had to look at a directory of images, and update a database with
a filename and specific tag value. (Actually, it was a set of tags)
Creating a scanner, I then connected is signals to the slot of my sub-classed
collector, where in the tag(...) slot had the following:
if (captureList.contains(id)){
...
query.insert(filename, id, value.toString());
}
This approach has a couple advantages:
The scanner takes up a constant amount of memory.
The collector only collects the tags you want. (Or, to avoid re-scanning, all,
but that is your choice) so you get to handle the memory usage.
The scanner can be connected to multiple collectors, say a PrintCollector, which
lists it o the screen)
When hooked to an QIODevice, you get tags emitted/collected/processed as they
are available.
Then, probably my biggest benefit is that you can also connect them to a
TagWriter class, which can be used to write QMaps, XML, SQL, etc... and then you
have a file writer, or when coupled with a scanner, a format converter. I
personally used a QMap as internal storage format, but output in DICOM or XML as
needed. I was also able to interface to the offis DICOM toolkit and read/write
their XML format. Overall the effort was a huge success.
Now, I've simplified this a bit for not handling nested data. With the addition
of two signals/slots and a little code to handle a stack, you get nested data.
push(int id)
pop()
Then you can use recursive QMaps or XML (XQuery/Path) to query/modify data.
Example int main(){
QFile input("file.dcm");
TagScannerDICOM scanner(&input); //QIODevice
TagCollectorPrinter printer(&scanner); // overridden constructor
auto-connects
TagColllctorWriterXml xmlwriter(&scanner, "out.xml"); // overridden
constructor auto-connects
return scanner.read(); // both printer and xmlwriter do their thing.
}
The really nice thing (and yet slightly difficult) is coming up with the global
image tag dictionary. We should use a master (GUID?) dictionary or the standard
DICOM dictionary to start with (since it defines the most tags by far) and
either provide a mapping from the master to the file type. DICOM allows
"private" tags, so any tag not already found in DICOM (ie. geo tags) could map
to a private tag. The DICOM dictionary speifies the uint tag, data type, and
name. So that if you wanted a more formal interface you could do:
image->tag("Width")->toInt(); // Where "Width" is looked up in a dictionary and
mapped to a uint.
Which would ultimately be translated into (assuming all tags have been
collected):
imageTagMap[0x00340032].toInt();
While I mention DICOM several times, it is important to note that I am only
referencing it because it has the most complicated metadata structure, and the
largest tag dictionary.
In this way, to support a new tag, assuming the tag seralization is the same, we
only need to add an entry to a dictionary, we do not need an interface to be
updated. ie. image->height() (however any such interface is a trivial mapping)
If you got this far thanks for reading, and I look forward to your feedback.
----- Original Message ----
From: Sami Maisniemi <sami.maisniemi at katelabs.com>
To: Qt-interest at qt.nokia.com
Sent: Tue, January 25, 2011 3:20:36 PM
Subject: [Qt-interest] New image metadata parser based on the Qt
Hi all,
I have created a new image metadata parser with the Qt and I have released it
under the LGPL license. The parser supports TIFF and EXIF metadata. The support
for XMP and IPTC metadata will be added in the future. The source code can be
found from the following location:
http://www.gitorious.org/qimagemetadata
The following files are needed:
- QImageMetaData.h
- QImageMetaData.cpp
- QImageMetaDataRational.h
The source code includes also some additional files for debugging and testing,
but they are for development purposes only.
The parser supports both TIFF and JPEG images and it has been tested with unit
tests.
The following example shows how to use the parser to display the manufacturer
and the model of the camera:
#include "QImageMetaData.h"
QImageMetaData* metadata = new QImageMetaData();
QString test = "test.tiff";
if (!metadata->read(test)) {
qDebug() << metaData->errorMessage();
} else {
qDebug() << metaData->make();
qDebug() << metaData->model();
}
delete(metadata);
All comments and feedback is welcome. I was informed that the contribution of
the parser should wait until the new contribution process has been finished.
Meanwhile I intend to improve the quality of the parser. Please let me know if
you to participate the development. Naturally I will provide support if needed.
Regards Sami
P.S. When you send comments and feedback, please keep in mind that this is my
first open source project.
Sami Maisniemi | Imaging Specialist | Kate Labs Ltd
www.katelabs.com | +358 400 114 070
_______________________________________________
Qt-interest mailing list
Qt-interest at qt.nokia.com
http://lists.qt.nokia.com/mailman/listinfo/qt-interest
More information about the Qt-interest-old
mailing list