Forum

Author Topic: Error: type object 'datetime.datetime' has no attribute 'datetime'  (Read 6861 times)

Costas

  • Jr. Member
  • **
  • Posts: 70
  • Aerial Mapping
    • View Profile
Hello all.

I processed some data in different chunks and merged them together. The merged chunk has all the initial photos x3 times. So from initial 2057 photos the merged chunk has 6171 photos.

I try to use the "Remove duplicated photos" script found on Agisoft - Github https://github.com/agisoft-llc/metashape-scripts/tree/master/src/contrib but i get an error:

Error: type object 'datetime.datetime' has no attribute 'datetime'

how can i fix that?

Code: [Select]
import datetime
import Metashape


"""
Script for removing duplicated photos, Metashape (v 1.8)
Matjaz Mori, CPA, May 2022
The script will remove all duplicated photos (photos referenced to the same file) from Metashape project.
"""

compatible_major_version = "2.1"
found_major_version = ".".join(Metashape.app.version.split('.')[:2])
if found_major_version != compatible_major_version:
    raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version))


def remove_duplicated_photos():
    print (datetime.datetime.now())

    doc = Metashape.app.document
    chunk = doc.chunk
    lenght = len(chunk.cameras)

    message = 'Removing duplicates...'
    print (message)

    paths = set()
    photos = list()
    for camera in list(chunk.cameras):
        if not camera.type == Metashape.Camera.Type.Regular: #skip camera track, if any
            continue

        if camera.photo.path in paths:
            photos.append(camera)
        else:
            paths.add(camera.photo.path)

    chunk.remove(photos)
    lenght_after = len(chunk.cameras)
    nr_removed = lenght-lenght_after
    message_end = 'Success, ' + str(nr_removed) + ' cameras removed.'
    print (message_end)

label = "Scripts/Remove duplicated photos"
Metashape.app.addMenuItem(label, remove_duplicated_photos)
print("To execute this script press {}".format(label))

Costas

  • Jr. Member
  • **
  • Posts: 70
  • Aerial Mapping
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #1 on: January 31, 2024, 03:20:21 PM »
I also get the above error when i try to run the "Remove disabled photos" script from the same link.

Code: [Select]
import datetime
import shutil
import Metashape
import os
import sys
from pathlib import Path

"""
Script for moving disabled photos, Metashape (v 1.7)
Matjaz Mori, CPA, October 2019

The script will create a new subdirectory in the photos directory,
move all the photos from the project marked "Disabled" into it and remove "Disabled" cameras prom Metashape project.
When using, it is advisable to monitor the Console (View -> Console).

"""

compatible_major_version = "2.1"
found_major_version = ".".join(Metashape.app.version.split('.')[:2])
if found_major_version != compatible_major_version:
    raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version))


def remove_disabled_photos():
    print (datetime.datetime.now())

    doc = Metashape.app.document
    chunk = doc.chunk
    counter = 0
    counter_fail = 0
    counter_not_moved = 0
    counter_errors = 0
    counter_cameras = 0
    lenght = len(chunk.cameras)

    message = 'Starting to evaluate ' + str(lenght) + ' photos...'
    print (message)

    for camera in chunk.cameras:
        if not camera.type == Metashape.Camera.Type.Regular: #skip camera track, if any
            continue

        if camera.enabled is True:
            counter_not_moved = counter_not_moved + 1
            continue # skipping enabled cameras

        photo_path = Path(camera.photo.path)
        photo_name = str(camera.label)
        destination_dir = photo_path.parent / 'Disabled'
        destination = destination_dir / photo_path.name

        if not destination_dir.exists():
            try:
                destination_dir.mkdir()
                print ("Successfully created the directory %s " % destination_dir)
            except OSError:
                print ('Error creating %s' % destination_dir)
                counter_errors = counter_errors + 1
                continue # we can't create directory - thus we can't move photo - thus we shouldn't delete it

        try:
            if photo_path.is_file():
                print ('Moving %s ...' % photo_name)
                shutil.move(str(photo_path), str(destination))

                counter = counter + 1
                counter_cameras = counter_cameras + 1
            else:
                print ('Photo %s does not exist!' % photo_name)
                counter_cameras = counter_cameras + 1
                counter_fail = counter_fail + 1

            chunk.remove(camera)

        except OSError:
            counter_errors = counter_errors + 1
            print ('Error %s!' % photo_name)

    message_end = 'Success, ' + str(counter) + ' photos moved, ' + str(counter_not_moved) + ' photos not moved.\nNumber of files unable to move: ' + str(counter_fail) + '\nNumber of cameras removed: ' + str(counter_cameras) + '\nNumber of unknown errorrs: '+ str(counter_errors)
    print (message_end)


label = "Scripts/Remove disabled photos"
Metashape.app.addMenuItem(label, remove_disabled_photos)
print("To execute this script press {}".format(label))

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 15168
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #2 on: January 31, 2024, 04:59:14 PM »
Hello Costas,

What version of Metashape you are using?

Can you try to execute the following lines (one by one) in Metashape Console pane and check if it also ends with an error:
Code: [Select]
import datetime
datetime.datetime.now()
print(datetime.datetime.now())

As a possible solution you can just remove print(datetime.datetime.now()) lines from your scripts, as they seem to be just auxiliary information.

But the error as you are observing could be observed, for example, if in the beginning instead of the following line
Code: [Select]
import datetimeanother one is used:
Code: [Select]
from datetime import datetime
Best regards,
Alexey Pasumansky,
Agisoft LLC

Costas

  • Jr. Member
  • **
  • Posts: 70
  • Aerial Mapping
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #3 on: January 31, 2024, 05:52:11 PM »
Thank you for your help Alexey.

I'm running Metashape Pro 2.1.0 build 17532

When i enter the following code in the console i get no error and i get the answer 2024-01-31 16:38:22 2024-01-31 16:38:22.099720
Code: [Select]
import datetime
datetime.datetime.now()
print(datetime.datetime.now())


I modified the scripts and removed the lines
Code: [Select]
import datetimeand
Code: [Select]
print(datetime.datetime.now())
Now the scripts run fine.

BUT now i have a different problem that i see after removing the duplicate photos. Removing the duplicate photos deletes photos that have depth maps and leaves photos with no depth maps randomly.

So from 6171 photos it deletes 4114 photos and now i have 2057 remained in the chunk which is correct BUT i only have 694 Depth Maps instead of 2057.

Is there a way to have the script check the pictures before delete the duplicate and if they have depth maps to keep them and delete the ones that do not have?


Chunk 1 has 642 Depth maps
Chunk 2 has 813 Depth maps
Chunk 3 has 630 Depth maps

Total 2085 Depth maps. There are 28 more Depth maps from total pictures probably due to same pictures are used again in the seams/overlap of the chunks.
« Last Edit: January 31, 2024, 05:57:21 PM by Costas »

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 15168
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #4 on: February 01, 2024, 01:43:22 PM »
Hello Costas,

Here is the way to check, if the camera has a depth map:

Code: [Select]
for camera in chunk.cameras:
    if camera in chunk.depth_maps.keys():
        print(camera.label + " has a depth map")
    else:
        print(camera.label + " does not have a depth map")
Best regards,
Alexey Pasumansky,
Agisoft LLC

Costas

  • Jr. Member
  • **
  • Posts: 70
  • Aerial Mapping
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #5 on: February 01, 2024, 02:08:15 PM »
OK. Thank you again Alexey.

I do not know how to make scripts and i only use ones i find in Agisoft GitHub.

So how do i input the code you say to the script so the script only selects duplicates for deletion that do not have depth maps?

The script that runs and deletes the duplicates is:

Code: [Select]
import Metashape


"""
Script for removing duplicated photos, Metashape (v 1.8)
Matjaz Mori, CPA, May 2022
The script will remove all duplicated photos (photos referenced to the same file) from Metashape project.
"""

compatible_major_version = "2.1"
found_major_version = ".".join(Metashape.app.version.split('.')[:2])
if found_major_version != compatible_major_version:
    raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version))


def remove_duplicated_photos():


    doc = Metashape.app.document
    chunk = doc.chunk
    lenght = len(chunk.cameras)

    message = 'Removing duplicates...'
    print (message)

    paths = set()
    photos = list()
    for camera in list(chunk.cameras):
        if not camera.type == Metashape.Camera.Type.Regular: #skip camera track, if any
            continue

        if camera.photo.path in paths:
            photos.append(camera)
        else:
            paths.add(camera.photo.path)

    chunk.remove(photos)
    lenght_after = len(chunk.cameras)
    nr_removed = lenght-lenght_after
    message_end = 'Success, ' + str(nr_removed) + ' cameras removed.'
    print (message_end)

label = "Scripts/Remove duplicated photos"
Metashape.app.addMenuItem(label, remove_duplicated_photos)
print("To execute this script press {}".format(label))

sorry for all this requests but where do i put the code
Code: [Select]
for camera in chunk.cameras:
    if camera in chunk.depth_maps.keys():
        print(camera.label + " has a depth map")
    else:
        print(camera.label + " does not have a depth map")
and will it work as is or does it need any additional code?

I do not want only to remove cameras that do not have depth maps but to delete all duplicates but to keep the set with depth maps in them and delete the ones that do not have.
« Last Edit: February 01, 2024, 02:10:50 PM by Costas »

Alexey Pasumansky

  • Agisoft Technical Support
  • Hero Member
  • *****
  • Posts: 15168
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #6 on: February 01, 2024, 03:05:32 PM »
Hello Costas,

Do I understand you correctly, that you need to remove only those duplicates that do not have associated depth maps and to keep those that do have the depth maps, even, if they are duplicated? Or to remove all the duplicates and to keep only one camera with the depth map for each duplicate set?
Best regards,
Alexey Pasumansky,
Agisoft LLC

Costas

  • Jr. Member
  • **
  • Posts: 70
  • Aerial Mapping
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #7 on: February 01, 2024, 03:43:42 PM »
I do a test project to establish a methodology for a coming project that will have about 40.000~50.000 photos and i will not be able to process them all at once in one chunk.

The test setup of the project is as following:

2057 photos.

1) Align all of them together in one chunk.
2) Gradual selection to delete points that i do not need and Optimise.
3) Using the script "Split in Chunks" to split the project in 3 Chunks. (i keep all initial Tie Points from step 1 and all photos (2057) in every new Chunk)
4) Process the 3 new chunks to produce Point Cloud, DEM and Orthophoto
5) Merge the 3 new Chunks. I merge all the assets (Depth Maps, Point Clouds, DEMs, Orthophotos)

The new Merged Chunk has:
6171 photos
2085 Depth maps (they come from Chunk 1 642 Depth maps - Chunk 2 813 Depth maps - Chunk 3 630 Depth maps)


I want to delete ALL duplicate photos.
If i use the script
Code: [Select]
import Metashape


"""
Script for removing duplicated photos, Metashape (v 1.8)
Matjaz Mori, CPA, May 2022
The script will remove all duplicated photos (photos referenced to the same file) from Metashape project.
"""

compatible_major_version = "2.1"
found_major_version = ".".join(Metashape.app.version.split('.')[:2])
if found_major_version != compatible_major_version:
    raise Exception("Incompatible Metashape version: {} != {}".format(found_major_version, compatible_major_version))


def remove_duplicated_photos():


    doc = Metashape.app.document
    chunk = doc.chunk
    lenght = len(chunk.cameras)

    message = 'Removing duplicates...'
    print (message)

    paths = set()
    photos = list()
    for camera in list(chunk.cameras):
        if not camera.type == Metashape.Camera.Type.Regular: #skip camera track, if any
            continue

        if camera.photo.path in paths:
            photos.append(camera)
        else:
            paths.add(camera.photo.path)

    chunk.remove(photos)
    lenght_after = len(chunk.cameras)
    nr_removed = lenght-lenght_after
    message_end = 'Success, ' + str(nr_removed) + ' cameras removed.'
    print (message_end)

label = "Scripts/Remove duplicated photos"
Metashape.app.addMenuItem(label, remove_duplicated_photos)
print("To execute this script press {}".format(label))
It Randomly deletes the duplicates and i lose too many Depth Maps. (only about 694 left from 2057 photos)


So what i need is:

1) The script must Check for ALL duplicate photos.
2) Choose to keep only 1 picture from it's set of duplicates but to keep the one that has the depth map and delete the ones that do not have.
3) If a set of duplicates have more than one photo that has a Depth map then choose one of them to keep and delete the rest.
4) If a list of duplicates does not have a picture with a Depth map then choose one to keep and delete the rest.


So i need to keep ONLY ONE photo from each duplicate set.
As a result the amount of photos will be no more than total initial photos (2057) but all of them will have depth maps. (or at least most of them)
The Merged chunk should be as if i processed all data in one chunk.
« Last Edit: February 05, 2024, 03:22:56 PM by Costas »

Costas

  • Jr. Member
  • **
  • Posts: 70
  • Aerial Mapping
    • View Profile
Re: Error: type object 'datetime.datetime' has no attribute 'datetime'
« Reply #8 on: February 06, 2024, 06:07:36 PM »
Hello Costas,

Do I understand you correctly, that you need to remove only those duplicates that do not have associated depth maps and to keep those that do have the depth maps, even, if they are duplicated? Or to remove all the duplicates and to keep only one camera with the depth map for each duplicate set?


Alexey,
I would like to remove ALL duplicates and keep only one camera with depth map for each duplicate set. (as stated in the previous post)

So is this possible?