Filmulator Quarantine Dev Log

My day job is closed for two weeks, so I’m dedicating all of my new free time to improving Filmulator.

My goal for this period is to get Lensfun working. Figuring out the API is one matter, but the first thing I did was to open up some space in the UI for the user to select the camera and lens they’re using.

Here’s the old UI:

To open up space, I finally took the time to create some icons, and also bunched up a bit of the exposure information on the top left.

I bet that eventually, I’ll wonder how I ever got by without making icons…

7 Likes

Lensfun is a bit challenging. I finally made my implementation “full”, with a choice of interpolators. In fact, I was able to reuse the interpolators I’d already included for resizing. Studying lenstool was a big help.

Database maintenance is also “fun”, so to speak. I ended up writing my own update library using libcurl and libarchive, so I could point it all at the directory of my choosing, and include the interface in the rawproc menus. I respected the version_x convention the library maintainers established, as the ABI difference between 0.3.2 and nascent 4.0.0 crosses version_1 and version_2, and there are distro packages out there at both versions.

Finally, lens nomenclature is a real pain. I think a lot of the misses folk bring to the forum have to do with aperture, where f/4.3 and F4.3 are different enough to bollox the match, and there are lensid files out there that use both in the same file version. I’m probably going to incorporate exiv2 just to anchor that somewhere that the lensfun database can also respect…

FWIW you can always inspect my code for one person’s implementation;

and surrounding code…

1 Like

That makes me think it would be easier to sanitize the database to use one convention somehow…

https://exiftool.org/TagNames/Nikon.html

Why oh why does Nikon have such an awful way of encoding what lens it used?

Do I have to keep checking back to update this list?

Even worse, those names don’t match up with the lensfun names. What am I supposed to do?

It’s worse than you think. Here’s what Rawtherapee uses:

rtexif/nikonattribs.cc, grep for “NALensDataInterpreter::lenses”

exiv2: src/nikonmn_int.cpp, grep for “FMntLens”. This one is instructive, scroll up a bit and you’ll find a description of the source, and a link, http://www.rottmerhusen.com/objektives/lensid/thirdparty.html, but the site isn’t active.

It’s Nikon’s doing only because they apparently until recently have not included lens nomenclature in their NEF metadata. This Lens ID scheme is a hack to cross-reference home-made nomenclature to an amalgam of metadata tags. Of note is Nikon’s recent cameras communicate a lens nomenclature, in the EXIF group no less…

Here’s the Lens* metadata from a D7000:

glenn@caliente:~/Photography/rawproc$ exiftool -n -G -*Lens* DSG_3111.NEF
[MakerNotes]    Lens Type                       : 14
[MakerNotes]    Lens                            : 18 200 3.5 5.6
[MakerNotes]    Lens Data Version               : 0204
[MakerNotes]    Lens ID Number                  : 139
[MakerNotes]    Lens F Stops                    : 5.33333333333333
[Composite]     Lens ID                         : 8B 40 2D 80 2C 3C FD 0E
[Composite]     Lens Spec                       : 18 200 3.5 5.6 14

Here’s the same from a Z6:

glenn@caliente:~/Photography/rawproc$ exiftool -n -G -*Lens* DSZ_4168.NEF
[MakerNotes]    Lens Type                       : 0
[MakerNotes]    Lens                            : 24 70 4 4
[MakerNotes]    Lens F Stops                    : 5
[MakerNotes]    Lens Data Version               : 0800
[MakerNotes]    Lens ID                         : 1
[EXIF]          Lens Info                       : 24 70 4 4
[EXIF]          Lens Make                       : NIKON
[EXIF]          Lens Model                      : NIKKOR Z 24-70mm f/4 S
[EXIF]          Lens Serial Number              : 20078247
[Composite]     Lens Spec                       : 24 70 4 4 0

EXIF:LensModel - yay.

The only reliable way I can think of to handle this is 1) use exiv2 as a first-cut source, and 2) have a robust manual lookup of the Lensfun database to let the user pick one. For rawproc, I wrote a list control that lets one filter the list based on a text box, like, as you type, the list in real-time cuts the members to those that match. Works pretty well to find a lens.

After spending the entire morning thinking about it, I decided that I’m going to display what information I can without having to maintain a lookup table.

For example, on older Canons I’ll display the lens name (they don’t have focal ranges or max apertures) and on Nikons I’ll display focal ranges and max aperture (they don’t have names), and attempt to auto-match… but when the user actually processes images, I’ll store the info that shouldn’t change image-to-image in a database together with what camera and lens model pairs they selected from lensfun.

That way the user gets perfect matching accuracy once they’ve gone through all of their lenses, and for future imports it’ll remember which of the three fixes (CA, distortion, vignetting) they prefer to apply for each lens.

1 Like

I’ve been struggling to identify Nikon lenses, even using the makernote lensID from LibRaw and this page from exiftool.

First off, the focal length and apertures as they’re recorded are weird. 50mm lenses are recorded as 80? 45mm lenses are recorded as 76? 35mm lenses are recorded as 68? I just made a huge spreadsheet of all the stuff and it’s a mess. It’s gonna end up having to be a lookup table, but at least it won’t change often.

Secondly, LibRaw’s lensID borks on a lot of Nikon files (not all though!) so I can’t rely on it; I reported a bug. Maybe I’ll have to do this in exiv2 and see if it’s better.

About Nikon Apterture values:

            switch (EffectiveMaxApertureValue) {
                case 0x8:
                    EffectiveMaxApertureString = "1.2";
                    break;

                case 0xc:
                    EffectiveMaxApertureString = "1.4";
                    break;

                case 0x14:
                    EffectiveMaxApertureString = "1.8";
                    break;

                case 0x18:
                    EffectiveMaxApertureString = "2.0";
                    break;

                case 0x20:
                    EffectiveMaxApertureString = "2.5";
                    break;

                case 0x24:
                    EffectiveMaxApertureString = "2.8";
                    break;

                case 0x2a:
                    EffectiveMaxApertureString = "3.3";
                    break;

                case 0x2c:
                    EffectiveMaxApertureString = "3.5";
                    break;

                case 0x30:
                    EffectiveMaxApertureString = "4.0";
                    break;

                case 0x34:
                    EffectiveMaxApertureString = "4.5";
                    break;

                case 0x38:
                    EffectiveMaxApertureString = "5.0";
                    break;

                case 0x3c:
                    EffectiveMaxApertureString = "5.6";
                    break;

                case 0x40:
                    EffectiveMaxApertureString = "6.3";
                    break;

                case 0x44:
                    EffectiveMaxApertureString = "7.1";
                    break;

                case 0x48:
                    EffectiveMaxApertureString = "8.0";
                    break;

                case 0x4e:
                    EffectiveMaxApertureString = "9.5";
                    break;

                case 0x54:
                    EffectiveMaxApertureString = "11.0";
                    break;

                case 0x5a:
                    EffectiveMaxApertureString = "13.0";
                    break;

                case 0x5e:
                    EffectiveMaxApertureString = "15.0";
                    break;

                case 0x60:
                    EffectiveMaxApertureString = "16.0";
                    break;

                case 0x66:
                    EffectiveMaxApertureString = "19.0";
                    break;

                case 0x6c:
                    EffectiveMaxApertureString = "22.0";
                    break;

                default  :
                    EffectiveMaxApertureString = "";
            }
1 Like

There are some f/2.4, f/2.7, f/3.8, and f/7.2 lenses lurking in the list, so I would have a few more cases.

I don’t want to encode for every lens individually, I just want to represent the lens specs correctly to help the user pick it from the list the first time.

The cases I quotet where the ones I could evaluate by using my lenses stopped down to the aperture values in the quote. Can’t do more :frowning:

Ah, I just combed through the Exiftool list.

The values above I evaluated from my old MF Nikon lenses, for which I can dial in the max aperture into my Nikon D700 and just read them out from metadata. No chance for Aptertures like 3.8 or so to evaluate exactly :frowning:

Great news, LibRaw fixed the bug with LensID already. Now I don’t have to fuss around with grabbing a dozen different exif fields and concatenating them myself.

3 Likes

I’ve just learned that Nikon isn’t the only brand to hide the lenses behind lens IDs… and other brands are even more inscrutable, with just a number to associate with lenses. Ugh.

Turns out Exiv2’s command-line application can interpret these makernotes and tell you straight up what the lens is, which is nice!

But I can’t figure out if that’s something the API is capable of at all, which stinks.

I don’t wanna have to maintain a list of lenses myself… we need more data sharing of this sort of thing.

@ggbutcher when you say you use exiv2 as a primary source, are you doing it via the API or via CLI?

I’m not doing it yet; still thinking through how to transition out of my home-grown metadata logic. The code today uses whatever Libraw provides; for Nikon lenses I have a copy of the Rottmerhusen nikonlensid.h. For my three cameras and lenses, works fine. :smiley:

Moving toward a version 1.0 others might use, I’m going to use the exiv2 API.

With regard to lens identification, I’m pondering the following: 1) look for a match from the Libraw data. If that fails; 2) look for a match in the exiv2-extracted metadata. If that fails; 3) prompt the user to select a lens from the Lensfun database. if #3, I’ll add the lensfun nomenclature to the tool parameters for that image so the user doesn’t have to relook it up ever time they open the source image to re-apply processing.

It’s a bit of a mess, when the camera doesn’t provide definitive lens nomenclature.

Step 2 is the sticking point, because Exiv2 gives you wonderful things like 4 252 0 for Pentax PEFs. At least it’s possible to decode the Nikon data into focal length range and apertures…

If I am going to have to maintain a lens ID decoding list for the brands that don’t have anything useful from libraw (even if copied from RawTherapee or Exiv2) then I’d rather share it a la librtprocess.

Maybe just a single header file with a function for each camera brand that returns a lens name when given the ID? I could call it lensjoy, because it goes with lensfun.

I feel your pain, but it’s really a question of, “where’s the best place to do that?”. My vote would be in the metadata library.

One question I’d like to explore is the state of maintenance with respect to the file Robert Rotterhusen started for Nikkor and 3rd-party F mount lenses. To all my digging, it doesn’t appear he’s maintaining it anymore as of sometime in 2018; if anyone here knows better, please post…

With that, though, there’s a second question, would the lens ID scheme he uses to divine a lens nomenclature from the available metadata extend to Pentax and other brands/mounts? I’m guessing not, based on what you reported and what Phil Harvey does in exiftool:

https://exiftool.org/TagNames/Pentax.html#LensRec

and what exiv2 contains in src/pentaxmn_int.cpp:

Actually, from the above, there should be a lens nomenclature somewhere in the exiv2 assemblage of Pentax metadata. What do you get when you run this:

exiv2 -pa <rawfilename> |grep Lens

For my Nikon D7000/Nikkor 18-200mm F3.5-5.6 I get:

glenn@caliente:~/Photography/rawproc$ exiv2 -pa DSG_3111.NEF |grep Lens
Exif.Nikon3.LensType                         Byte        1  D G VR
Exif.Nikon3.Lens                             Rational    4  18-200mm F3.5-5.6
Exif.Nikon3.LensFStops                       Undefined   4  5.33333
Exif.NikonLd3.LensIDNumber                   Byte        1  Nikon AF-S DX VR Zoom-Nikkor 18-200mm f/3.5-5.6G IF-ED II
Exif.NikonLd3.LensFStops                     Byte        1  F5.3

The metadata libraries do all this heavy lifting; I don’t see a compelling need to duplicate it in librtprocess…

The library doesn’t do the heavy lifting.

exiv2 the application has the translations for the tags, but for some reason exiv2 the library does not (or if it does, I just haven’t figured it out). That’s the problem.

Ouch, sorry… hmmm, I just went back to my experimentation with the exiftool C++ interface, and found the same thing.

Still, do you want to take on maintaining lens lookup tables? I’m going to look at the exiv2 code that does it, and see if there’s already exposed somewhere in the classes to compel that. If not, I’d rather ask the exiv2 developers to expose something we could use.

I would not want to maintain lens tables, I’d rather have exiv2 expose the data that the CLI is able to access.

I’m just treading lightly because I know they’ve had troubles with maintainership recently.