[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