Two photos with different created times considered variants

Subject, mainly. I have a test folder I’m using from an event I attended in 2020. It’s a combination of Canon 7D and iPhone shots, including some live photos and a large video. In total I have 52 separate assets and it’s displaying as 44 assets in Photostructure.

I’m trying to parse through all the reasons why one at a time, and the first I noticed (when posting on Discord about a separate question re: bind mount removal) is that PS seemed to consider two different photos with different subsecond creation times as variants. Here is the info output below as well as a snippet of the datetime.

image

Is there an advanced value I can set to split these apart? PS_STRICT_DEDUPING="true"? That one seems to have other implications with regard to RAW/JPG pairs, etc. so not sure if that’s the best course.

Thanks!

      localCentiseconds: 2020091818154894,
      precisionMs: 10,
      src: 'tags:SubSecDateTimeOriginal'

      localCentiseconds: 2020091818154923,
      precisionMs: 10,
      src: 'tags:SubSecDateTimeOriginal'

docker exec -ti photostructure sh -c './photostructure info /photos/2020/2020-09-18/IMG_2706.JPG /photos/2020/2020-09-18/IMG_2707.JPG'

{
  fileComparison: 'These two files will be aggregated into a single asset.',
  variant: true,
  imageHashComparison: {
    imageCorr: 0.94,
    aRotation: 0,
    colorCorr: 0.99,
    meanCorr: 0.96,
    greyscale: false
  },
  a: {
    _PhotoStructureVersion: '1.1.0',
    cameraId: '["SerialNumber:2671204554","InternalSerialNumber:S1166639A"]',
    capturedAt: {
      date: ExifDateTime {
        year: 2020,
        month: 9,
        day: 18,
        hour: 18,
        minute: 15,
        second: 48,
        millisecond: 940,
        tzoffsetMinutes: -480,
        rawValue: '2020:09:18 18:15:48.94',
        zoneName: 'UTC-8'
      },
      localCentiseconds: 2020091818154894,
      precisionMs: 10,
      src: 'tags:SubSecDateTimeOriginal'
    },
    dimensions: { height: 3456, width: 5184 },
    errors: [],
    exposureSettings: {
      aperture: 2.8,
      focalLength: '17.0 mm',
      iso: 500,
      shutterSpeed: '1/500'
    },
    filters: {
      accepted: [
        'exifExtFilter',
        'fileSizeFilter',
        'notHiddenCheap',
        'noMediaFilter',
        'hasMimeType',
        'supportedMimeTypeFilter',
        'notRejected',
        'minDimensionsFilter',
        'minVideoDurationFilter',
        'shaBlocklistFilter'
      ],
      rejected: []
    },
    ignoredBecause: [],
    imageHash: {
      dominantColors: 'Jet (#343434), Black olive (#3B3C36), Black (#000000), Licorice (#1A1110), Ebony (#555D50)',
      isGreyscale: false,
      meanHash: 'HLw4OHzC/wgEADl/PBweP/n7AoDD8//+',
      modes: [
        690, 694, 658,
        662, 914, 918,
        219
      ]
    },
    lensId: 'LensSerialNumber:0000050bc2',
    lensInfo: '17-55mm f/2.8',
    lensMake: 'Canon',
    lensModel: 'EF-S 17-55mm f/2.8 IS USM',
    Make: 'Canon',
    mimetype: 'image/jpeg',
    Model: 'EOS 7D',
    nativePath: '/photos/2020/2020-09-18/IMG_2706.JPG',
    needsTranscoding: false,
    pathsInLibrary: [],
    priorAssetFile: {
      '$ctor': 'models.AssetFile',
      aperture: 2.8,
      assetId: 35,
      cameraId: '["SerialNumber:2671204554","InternalSerialNumber:S1166639A"]',
      capturedAtLocal: 2020091818154894,
      capturedAtOffset: -480,
      capturedAtPrecisionMs: 10,
      capturedAtSrc: 'tags:SubSecDateTimeOriginal',
      createdAt: 1651258664361,
      fileSize: 9431696,
      focalLength: '17.0 mm',
      height: 3456,
      id: 71,
      iso: 500,
      lensId: 'LensSerialNumber:0000050bc2',
      make: 'Canon',
      meanHash: 'HLw4OHzC/wgEADl/PBweP/n7AoDD8//+',
      mimetype: 'image/jpeg',
      mode0: 690,
      mode1: 694,
      mode2: 658,
      mode3: 662,
      mode4: 914,
      mode5: 918,
      mode6: 219,
      model: 'EOS 7D',
      mountpoint: '/photos',
      mtime: 1600487481000,
      rotation: 0,
      sha: '4wT2swQwaLcSuMVOfudHDJVWbVTFEksH',
      shown: false,
      shutterSpeed: '1/500',
      updateCount: 5,
      updatedAt: 1651265750329,
      uri: 'psfile://2H119wZ3D/2020/2020-09-18/IMG_2706.JPG',
      version: 11,
      width: 5184
    },
    priorIsInSync: true,
    rotation: 0,
    sha: '4wT2swQwaLcSuMVOfudHDJVWbVTFEksH',
    tags: [
      [ 'Camera', 'Canon', 'EOS 7D' ],
      [ 'Lens', 'Canon', 'EF-S 17-55mm f/2.8 IS USM' ],
      [
        'When',
        { name: '2020', ordinal: 7980 },
        { displayName: 'Sep', name: '9', ordinal: 4 }
      ],
      [ 'Type', 'Image', 'JPEG' ],
      [
        'fs',
        { displayName: 'photos', name: '2H119wZ3D' },
        '2020',
        '2020-09-18'
      ]
    ],
    tz: 'UTC-08',
    tzSource: 'offsetMinutesToZoneName from TimeZone',
    uri: 'psfile://2H119wZ3D/2020/2020-09-18/IMG_2706.JPG',
    validFile: 'OK',
    variantSortCriteria: {
      count: 0,
      fileSize: 11,
      isBrowserSupported: true,
      isCover: false,
      mtime: 13337396,
      resolution: 12,
      schemeIdx: 2,
      uri: 'psfile://2H119wZ3D/2020/2020-09-18/IMG_2706.JPG'
    }
  },
  b: {
    _PhotoStructureVersion: '1.1.0',
    cameraId: '["SerialNumber:2671204554","InternalSerialNumber:S1166639A"]',
    capturedAt: {
      date: ExifDateTime {
        year: 2020,
        month: 9,
        day: 18,
        hour: 18,
        minute: 15,
        second: 49,
        millisecond: 230,
        tzoffsetMinutes: -480,
        rawValue: '2020:09:18 18:15:49.23',
        zoneName: 'UTC-8'
      },
      localCentiseconds: 2020091818154923,
      precisionMs: 10,
      src: 'tags:SubSecDateTimeOriginal'
    },
    dimensions: { height: 3456, width: 5184 },
    errors: [],
    exposureSettings: {
      aperture: 2.8,
      focalLength: '17.0 mm',
      iso: 500,
      shutterSpeed: '1/500'
    },
    filters: {
      accepted: [
        'exifExtFilter',
        'fileSizeFilter',
        'notHiddenCheap',
        'noMediaFilter',
        'hasMimeType',
        'supportedMimeTypeFilter',
        'notRejected',
        'minDimensionsFilter',
        'minVideoDurationFilter',
        'shaBlocklistFilter'
      ],
      rejected: []
    },
    ignoredBecause: [],
    imageHash: {
      dominantColors: 'Jet (#343434), Black olive (#3B3C36), Black (#000000), Licorice (#1A1110), Ebony (#555D50)',
      isGreyscale: false,
      meanHash: 'HLw4OHzC/wgGADh9PBweP/n7goLD0//+',
      modes: [
         690, 694, 658,
         914, 662, 918,
        1097
      ]
    },
    lensId: 'LensSerialNumber:0000050bc2',
    lensInfo: '17-55mm f/2.8',
    lensMake: 'Canon',
    lensModel: 'EF-S 17-55mm f/2.8 IS USM',
    Make: 'Canon',
    mimetype: 'image/jpeg',
    Model: 'EOS 7D',
    nativePath: '/photos/2020/2020-09-18/IMG_2707.JPG',
    needsTranscoding: false,
    pathsInLibrary: [],
    priorAssetFile: {
      '$ctor': 'models.AssetFile',
      aperture: 2.8,
      assetId: 35,
      cameraId: '["SerialNumber:2671204554","InternalSerialNumber:S1166639A"]',
      capturedAtLocal: 2020091818154923,
      capturedAtOffset: -480,
      capturedAtPrecisionMs: 10,
      capturedAtSrc: 'tags:SubSecDateTimeOriginal',
      createdAt: 1651258665058,
      fileSize: 9471040,
      focalLength: '17.0 mm',
      height: 3456,
      id: 72,
      iso: 500,
      lensId: 'LensSerialNumber:0000050bc2',
      make: 'Canon',
      meanHash: 'HLw4OHzC/wgGADh9PBweP/n7goLD0//+',
      mimetype: 'image/jpeg',
      mode0: 690,
      mode1: 694,
      mode2: 658,
      mode3: 914,
      mode4: 662,
      mode5: 918,
      mode6: 1097,
      model: 'EOS 7D',
      mountpoint: '/photos',
      mtime: 1600487482000,
      rotation: 0,
      sha: 'C0YjNzjPzn9cNbMw05WoP4M96cxr/z+A',
      shown: true,
      shutterSpeed: '1/500',
      updateCount: 4,
      updatedAt: 1651265750329,
      uri: 'psfile://2H119wZ3D/2020/2020-09-18/IMG_2707.JPG',
      version: 11,
      width: 5184
    },
    priorIsInSync: true,
    rotation: 0,
    sha: 'C0YjNzjPzn9cNbMw05WoP4M96cxr/z+A',
    tags: [
      [ 'Camera', 'Canon', 'EOS 7D' ],
      [ 'Lens', 'Canon', 'EF-S 17-55mm f/2.8 IS USM' ],
      [
        'When',
        { name: '2020', ordinal: 7980 },
        { displayName: 'Sep', name: '9', ordinal: 4 }
      ],
      [ 'Type', 'Image', 'JPEG' ],
      [
        'fs',
        { displayName: 'photos', name: '2H119wZ3D' },
        '2020',
        '2020-09-18'
      ]
    ],
    tz: 'UTC-08',
    tzSource: 'offsetMinutesToZoneName from TimeZone',
    uri: 'psfile://2H119wZ3D/2020/2020-09-18/IMG_2707.JPG',
    validFile: 'OK',
    variantSortCriteria: {
      count: 0,
      fileSize: 11,
      isBrowserSupported: true,
      isCover: false,
      mtime: 13337396,
      resolution: 12,
      schemeIdx: 2,
      uri: 'psfile://2H119wZ3D/2020/2020-09-18/IMG_2707.JPG'
    }
  }
}

Thanks for reporting, and sorry for the glitch: I believe I’ve fixed this in v2.1. if you could email me a couple of the mis-aggregated filesi can verify that the new code is doing the right thing.

I’m seeing the following now when running info:

fileComparison: 'These files represent different assets: captured-at 2020091818153093±10ms != 2020091818153122±10ms',
  primary: undefined,
  imageHashComparison: {
    imageCorr: 0.97,
    aRotation: 0,
    colorCorr: 0.95,
    meanCorr: 0.96,
    greyscale: false

This seems good, however I’m still seeing (on a totally fresh import of the same 51 assets) 44 total in the UI. I’m slowly trying to iterate through comparing the UI to the folder locally to see where the differential is happening.

Edit: When I view by folder, I see 38 and 11. The actual folders contain 39 and 12. However when I view ‘home’ or by date I see 44. Still looking.

Okay, here are the results from an image and a movie that are being aggregated.

{
  fileComparison: 'These two files will be aggregated into a single asset.',
  primary: '/photos/2020/2020-09-18/IMG_1527.jpg',
  imageHashComparison: {
    imageCorr: 0.86,
    aRotation: 270,
    colorCorr: 0.98,
    meanCorr: 0.9,
    greyscale: false
  },
  a: {
    _PhotoStructureVersion: '2.1.0-alpha.1',
    capturedAt: {
      date: {
        day: 18,
        hour: 18,
        millisecond: 0,
        minute: 18,
        month: 9,
        rawValue: '2020:09:18 18:18:44-07:00',
        second: 44,
        tzoffsetMinutes: -420,
        year: 2020,
        zoneName: 'America/Los_Angeles'
      },
      localCentiseconds: 2020091818184400,
      precisionMs: 1000,
      src: 'tags:CreationDate',
      toLocal: 2020091818184400
    },
    dimensions: { height: 1920, width: 1440 },
    dirFilters: {
      accepted: [ 'notInHiddenPhotoStructureDir', 'neverIgnored' ],
      notApplicable: [],
      rejected: []
    },
    duration: 3.025,
    errors: [],
    fileFilters: {
      accepted: [
        'isPhotoOrVideoExtension',
        'notHiddenPosix',
        'notInHiddenPhotoStructureDir',
        'neverIgnored',
        'notFileMissing',
        'notFileTooSmall',
        'notFileTooBig',
        'notMissingMimeType',
        'supportedMimeType',
        'notDimensionsTooSmall',
        'notVideoTooShort',
        'notRejectedRating',
        'notExcludedKeyword',
        'isValidFile'
      ],
      notApplicable: [ 'notMissingMakeAndModelTags', 'notVideoTooLong' ],
      rejected: []
    },
    geohash: '9q9p4e',
    geohashNumeric: 325375117,
    imageHash: {
      dominantColors: 'Moss green (#8A9A5B), Pesto (#7C7631), Dark olive green (#556B2F), Turtle green (#2A380B), Antique bronze (#665D1E)',
      isGreyscale: false,
      meanHash: 'mOAADpg8t/8AAwL///4QAP///QAAQOP/',
      modes: [
        2713, 957, 2717,
         953, 922,  926,
         952
      ],
      nativePath: '/photos/2020/2020-09-19/IMG_1526.mov'
    },
    inferred: {},
    Make: 'Apple',
    mimetype: 'video/quicktime',
    Model: 'iPhone 11 Pro',
    nativePath: '/photos/2020/2020-09-19/IMG_1526.mov',
    needsTranscoding: false,
    original: { Make: 'Apple', Model: 'iPhone 11 Pro' },
    pathsInLibrary: [],
    rotation: 90,
    sha: 'rUb+JKtp6c/7OgLn8k8Go/dv0aMwJRWQ',
    tags: [
      [ 'Camera', 'Apple', 'iPhone 11 Pro' ],
      [
        'When',
        { name: '2020', ordinal: 7980 },
        { displayName: 'Sep', name: '9', ordinal: 4 }
      ],
      [ 'Type', 'Video', 'QuickTime' ],
      [ 'fs', 'Library', '2020', '2020-09-19' ]
    ],
    tz: 'America/Los_Angeles',
    tzSource: 'from Lat/Lon',
    uri: 'pslib:/2020/2020-09-19/IMG_1526.mov',
    validFile: 'OK',
    variantSortCriteria: {
      count: 0,
      fileSize: 10,
      isBrowserSupported: false,
      isCover: false,
      mtime: 5334928,
      resolution: 9,
      schemeIdx: 3,
      uri: 'pslib:/2020/2020-09-19/IMG_1526.mov'
    }
  },
  b: {
    _PhotoStructureVersion: '2.1.0-alpha.1',
    capturedAt: {
      date: {
        day: 18,
        hour: 18,
        millisecond: 176,
        minute: 18,
        month: 9,
        rawValue: '2020:09:18 18:18:44.176-07:00',
        second: 44,
        tzoffsetMinutes: -420,
        year: 2020,
        zoneName: 'America/Los_Angeles'
      },
      localCentiseconds: 2020091818184417,
      precisionMs: 10,
      src: 'tags:SubSecDateTimeOriginal',
      toLocal: 2020091818184417
    },
    dimensions: { height: 4032, width: 3024 },
    dirFilters: {
      accepted: [ 'notInHiddenPhotoStructureDir', 'neverIgnored' ],
      notApplicable: [],
      rejected: []
    },
    errors: [],
    exposureSettings: {
      aperture: 1.8,
      focalLength: '4.2 mm',
      iso: 32,
      shutterSpeed: '1/130'
    },
    fileFilters: {
      accepted: [
        'isPhotoOrVideoExtension',
        'notHiddenPosix',
        'notInHiddenPhotoStructureDir',
        'neverIgnored',
        'notFileMissing',
        'notFileTooSmall',
        'notFileTooBig',
        'notMissingMimeType',
        'supportedMimeType',
        'notDimensionsTooSmall',
        'notRejectedRating',
        'notExcludedKeyword',
        'isValidFile'
      ],
      notApplicable: [
        'notMissingMakeAndModelTags',
        'notVideoTooShort',
        'notVideoTooLong'
      ],
      rejected: []
    },
    geohash: '9q9p4e',
    geohashNumeric: 325375117,
    imageHash: {
      dominantColors: 'Dark olive green (#556B2F), Pesto (#7C7631), Moss green (#8A9A5B), Middle green (#4D8C57), Dark moss green (#4A5D23), Turtle green (#2A380B)',
      isGreyscale: false,
      meanHash: 'AxMXHQ9HQ8vY/DwcHBw8GMPHweHB4+fj',
      modes: [
         953,  957, 2713,
        2717, 2699,  925,
         922
      ],
      nativePath: '/photos/2020/2020-09-18/IMG_1527.jpg'
    },
    imageId: '{"RunTimeValue":173670058785000}',
    inferred: {},
    lensId: '{"mli":"apple/1.54-6mm f/1.8-2.4"}',
    lensInfo: '1.54-6mm f/1.8-2.4',
    lensMake: 'Apple',
    lensModel: 'iPhone 11 Pro back triple camera 4.25mm f/1.8',
    Make: 'Apple',
    mimetype: 'image/jpeg',
    Model: 'iPhone 11 Pro',
    nativePath: '/photos/2020/2020-09-18/IMG_1527.jpg',
    needsTranscoding: false,
    original: { Make: 'Apple', Model: 'iPhone 11 Pro' },
    pathsInLibrary: [],
    rotation: 90,
    sha: 'MQQsX35dXpqWu+9mFq1ueyLVpF1vAxYu',
    tags: [
      [ 'Camera', 'Apple', 'iPhone 11 Pro' ],
      [
        'Lens',
        'Apple',
        'iPhone 11 Pro back triple camera 4.25mm f/1.8'
      ],
      [
        'When',
        { name: '2020', ordinal: 7980 },
        { displayName: 'Sep', name: '9', ordinal: 4 }
      ],
      [ 'Type', 'Image', 'JPEG' ],
      [ 'fs', 'Library', '2020', '2020-09-18' ]
    ],
    tz: 'America/Los_Angeles',
    tzSource: 'from Lat/Lon',
    uri: 'pslib:/2020/2020-09-18/IMG_1527.jpg',
    validFile: 'OK',
    variantSortCriteria: {
      count: 0,
      fileSize: 10,
      isBrowserSupported: true,
      isCover: false,
      mtime: 5334934,
      resolution: 12,
      schemeIdx: 3,
      uri: 'pslib:/2020/2020-09-18/IMG_1527.jpg'
    }
  }
}

I’m not sure why that is occurring. Thanks!

Edit: If I sort by file type, I actually see 13 results, including 1 JPG that is not attached as a variant to any movies, so that seems unusual, too.

Oh, good catch!

The (incorrect!) reason why the current code is thinking they’re the same is that the captured-at time of the video doesn’t include millisecond precision, so PhotoStructure figures that the ~170 milliseconds is “close enough” (RAW and JPG pairs also have this missing-millisecond-precision issue).

In this specific case, I believe I can kick the files into different assets by looking at the content UUIDs, though: I’ll add that quickly right now.

Got it. Should I wait for the next update and rebuild before continuing to look for variant matches that shouldn’t match?

Yes please!

And before rebuilding, if you can re-run that last info command, we can verify that it worked correctly.

Can you actually email me those two files so I can verify before I cut the next alpha build?