Anhang zu dict-Liste in merkwürdiger Reihenfolge

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

Hi!

Ich bin absolut am verzweifeln und meine letzte Hoffnung seid ihr:

Mir liegen aus verschiedenen .json-Dateien Koordinaten von Objekten auf Bildern vor.
Diese möchte ich zusammenführen und eine große .json-Datei erstellen. Die .json-Files haben die Form. Den Key "annotations" mit Value der Koordinaten habe ich zur besseren Übersicht weggelassen:

Code: Alles auswählen

test_annotations_1 = [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 1}]

Code: Alles auswählen

test_annotations_2 = [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 2}]


Dabei kategorisiert 'id' den Objektindex auf einem Bild und 'image_id' den zugehörigen Bildpfad.
Man sieht, dass ids und image_ids in test_annotations_1 & 2 identisch sind, da die Bilder seperat gelabelt wurden. Was ich jetzt möchte ist folgendes:

annotations_kombiniert:

Code: Alles auswählen

 [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 1},  {'id': 4, 'image_id': 2}, {'id': 5, 'image_id': 2}, {'id': 6, 'image_id': 2}]


Ich habe mir folgendes Skript dazu geschrieben, um erstmal zu sehen ob die id's und image_id's richtig zugewiesen werden:

Code: Alles auswählen

class AnnotationsfileCreator:
    def __init__(self):
        
        self.images = []
        self.annotations = []        
        self.image_id = 1
        self.defect_id = 0   
           
        

    
    def add_annotations(self, extracted_annotations):
        
        
        for element in extracted_annotations:
            element['image_id'] = self.image_id
            element['id'] = self.defect_id
            print("element: ")
            print(element)
            self.defect_id += 1           

        self.image_id += 1     

        
annotationfile = AnnotationsfileCreator()

Versuche ich nun 2 annotations zu kombinieren:

Code: Alles auswählen

annotationfile.add_annotations(test_annotations_1)
annotationfile.add_annotations(test_annotations_2)
ergibt sich der folgende, richtige output:

Code: Alles auswählen

element: 
{'id': 0, 'image_id': 1}
element: 
{'id': 1, 'image_id': 1}
element: 
{'id': 2, 'image_id': 1}
element: 
{'id': 3, 'image_id': 2}
element: 
{'id': 4, 'image_id': 2}
element: 
{'id': 5, 'image_id': 2}


Nun ist für mich die logische Schlussfolgerung, "element" in jedem Durchlauf einer Liste zu appenden, was ich am Ende jedes for-Schleifen Durchlaufs einfüge.

Code: Alles auswählen

self.annotations.append(element)

Schau ich mir jetzt das Ergebnis an:

Code: Alles auswählen

print(annotationfile.annotations)

kommt absoluter Nonsense raus:

Code: Alles auswählen

[{'id': 3, 'image_id': 2}, {'id': 4, 'image_id': 2}, {'id': 5, 'image_id': 2}, {'id': 3, 'image_id': 2}, {'id': 4, 'image_id': 2}, {'id': 5, 'image_id': 2}]

Ich verstehe absolut nicht wie das vonstatten geht und habe zig Stunden verbracht eine Lösung zu finden. Kann mir BITTE jemand helfen?


Beste Grüße
Sirius3
User
Beiträge: 17846
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist das typische Problem, dass Du Wörterbücher veränderst, und gleichzeitig die selben Exemplare in einer Liste sammelst.
Das beste ist, niemals Wörterbücher zu verändern, sondern immer neue zu erzeugen.
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

okay, danke.

Kann das aber wer erklären, warum die Einträge 3-5 dann einfach verdoppelt werden und 0-2 gelöscht?

edit:
okay, so hat es geklappt jetzt, tausend dank mal wieder!
trotzdem weiterhin die Frage: Wieso?
narpfel
User
Beiträge: 646
Registriert: Freitag 20. Oktober 2017, 16:10

@G-Rizzle: Der Fehler liegt in dem Teil vom Code, den du nicht zeigst. Meine Vermutung ist, dass du `add_annotations` zwei Mal mit den selben Dicts aufrufst, zum Beispiel weil du irgendwo `test_annotations_2 = test_annotations1` stehen hast. Aber der Code, den du gezeigt hast, zeigt das Verhalten nicht:

Code: Alles auswählen

class AnnotationsfileCreator:
    def __init__(self):
        self.images = []
        self.annotations = []
        self.image_id = 1
        self.defect_id = 0

    def add_annotations(self, extracted_annotations):
        for element in extracted_annotations:
            element['image_id'] = self.image_id
            element['id'] = self.defect_id
            print("element: ")
            print(element)
            self.defect_id += 1
            self.annotations.append(element)

        self.image_id += 1


test_annotations_1 = [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 1}]
test_annotations_2 = [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 2}]

annotationfile = AnnotationsfileCreator()

annotationfile.add_annotations(test_annotations_1)
annotationfile.add_annotations(test_annotations_2)

print(annotationfile.annotations)

Code: Alles auswählen

$ python t.py
element: 
{'id': 0, 'image_id': 1}
element: 
{'id': 1, 'image_id': 1}
element: 
{'id': 2, 'image_id': 1}
element: 
{'id': 3, 'image_id': 2}
element: 
{'id': 4, 'image_id': 2}
element: 
{'id': 5, 'image_id': 2}
[{'id': 0, 'image_id': 1}, {'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 2}, {'id': 4, 'image_id': 2}, {'id': 5, 'image_id': 2}]
Bitte zeige also genau den Code, den du ausführst, damit man das Problem auch nachvollziehen kann und nicht unnötig Zeit mit Raten verschwendet.
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

narpfel hat geschrieben: Donnerstag 10. März 2022, 17:19 @G-Rizzle: Der Fehler liegt in dem Teil vom Code, den du nicht zeigst. Meine Vermutung ist, dass du `add_annotations` zwei Mal mit den selben Dicts aufrufst, zum Beispiel weil du irgendwo `test_annotations_2 = test_annotations1` stehen hast. Aber der Code, den du gezeigt hast, zeigt das Verhalten nicht:

Code: Alles auswählen

class AnnotationsfileCreator:
    def __init__(self):
        self.images = []
        self.annotations = []
        self.image_id = 1
        self.defect_id = 0

    def add_annotations(self, extracted_annotations):
        for element in extracted_annotations:
            element['image_id'] = self.image_id
            element['id'] = self.defect_id
            print("element: ")
            print(element)
            self.defect_id += 1
            self.annotations.append(element)

        self.image_id += 1


test_annotations_1 = [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 1}]
test_annotations_2 = [{'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 2}]

annotationfile = AnnotationsfileCreator()

annotationfile.add_annotations(test_annotations_1)
annotationfile.add_annotations(test_annotations_2)

print(annotationfile.annotations)

Code: Alles auswählen

$ python t.py
element: 
{'id': 0, 'image_id': 1}
element: 
{'id': 1, 'image_id': 1}
element: 
{'id': 2, 'image_id': 1}
element: 
{'id': 3, 'image_id': 2}
element: 
{'id': 4, 'image_id': 2}
element: 
{'id': 5, 'image_id': 2}
[{'id': 0, 'image_id': 1}, {'id': 1, 'image_id': 1}, {'id': 2, 'image_id': 1}, {'id': 3, 'image_id': 2}, {'id': 4, 'image_id': 2}, {'id': 5, 'image_id': 2}]
Bitte zeige also genau den Code, den du ausführst, damit man das Problem auch nachvollziehen kann und nicht unnötig Zeit mit Raten verschwendet.
Hi,
alles klar; anbei ursprüngliche Code mit besagtem Problem:

Code: Alles auswählen

import time


class AnnotationsfileCreator:
    def __init__(self):
        self.info = {'description': 'my-project-name'}
        self.images = []
        self.annotations = []
        
        self.categories = [{'id': 1, 'name': 'Particle'}, {'id': 2, 'name': 'LackOfFusion'}, {'id': 3, 'name': 'Balling'}]
        self.image_id = 1
        self.defect_id = 0   
        self.listeee = []
      
        
        
              
        
    def add_image(self, image_name):
        anhang = {'id': self.image_id, 'width': 1024, 'height': 1024, 'file_name': image_name}
        self.images.append(anhang)   
    
    
    
    
    def add_image_and_its_annotations(self, image_name, extracted_annotations):
        self.add_image(image_name)
        
        for element in extracted_annotations:
            element['image_id'] = self.image_id
            element['id'] = self.defect_id
            self.annotations.append(element)        
            
            self.defect_id += 1

            
        self.image_id += 1
        
        
        
    def make_dict(self):
        self.file = {}
        self.file['info'] = self.info
        self.file['images'] = self.images
        self.file['annotations'] = self.annotations
        self.file['categories'] = self.categories

            
        
annotationfile = AnnotationsfileCreator()
nächste Zelle

Code: Alles auswählen

annotationfile.add_image_and_its_annotations('2a.jpg', extracted2)
annotationfile.add_image_and_its_annotations('2b.jpg', extracted2)

extracted2:

Code: Alles auswählen

extracted2 = [{'id': 0, 'iscrowd': 0, 'image_id': 1, 'category_id': 1, 'segmentation': [[197.63730569948189, 305.0777202072539, 193.6580310880829, 375.37823834196894, 236.1036269430052, 409.8652849740933, 348.8497409326425, 400.580310880829, 399.2538860103627, 314.36269430051817, 400.580310880829, 217.5336787564767, 336.9119170984456, 191.00518134715026, 267.9378238341969, 214.88082901554404]], 'bbox': [193.6580310880829, 191.00518134715026, 206.9222797927461, 218.86010362694304], 'area': 34089.31160568068}, {'id': 1, 'iscrowd': 0, 'image_id': 1, 'category_id': 2, 'segmentation': [[376.70466321243526, 599.5440414507772, 375.37823834196894, 643.3160621761658, 527.9170984455959, 691.0673575129534, 628.7253886010363, 615.4611398963731, 631.3782383419689, 531.8963730569949, 513.3264248704663, 481.4922279792746, 441.699481865285, 496.08290155440415, 399.2538860103627, 534.5492227979274]], 'bbox': [375.37823834196894, 481.4922279792746, 255.99999999999994, 209.57512953367882], 'area': 38838.81983408951}, {'id': 2, 'iscrowd': 0, 'image_id': 1, 'category_id': 3, 'segmentation': [[680.4559585492228, 233.45077720207254, 657.9067357512954, 269.2642487046632, 672.4974093264249, 307.73056994818654, 815.7512953367876, 336.9119170984456, 880.7461139896374, 252.02072538860105, 829.0155440414508, 197.63730569948189, 753.4093264248705, 189.67875647668396]], 'bbox': [657.9067357512954, 189.67875647668396, 222.83937823834196, 147.23316062176164], 'area': 22147.3641708502}]
narpfel
User
Beiträge: 646
Registriert: Freitag 20. Oktober 2017, 16:10

@G-Rizzle: Also genau das Problem, das Sirius3 und ich schon vermutet haben.
Sirius3
User
Beiträge: 17846
Registriert: Sonntag 21. Oktober 2012, 17:20

`time` wird importiert, aber gar nicht benutzt.
Die vielen Leerzeilen machen den Code sehr schlecht lesbar. Mehr als zwei Leerzeilen am Stück machen nie Sinn.
Bei `listeee`, was bedeuten denn die drei `e`? Das sieht mir stark nach einem Schreibfehler aus.
In `add_image_and_its_annotations` änderst Du das übergebene Wörterbuch, was man nicht machen darf, weil es Seiteneffekte hat, statt dessen erzeugt man einfach ein neues Wörterbuch.
In `make_dict` wird ein neues Attribut eingeführt, was man nicht machen darf. Alle Attribute müsssen in `__init__` angelegt werden. Hier würde ich gar kein Attribut erwarten, sondern dass das Wörterbuch zurückgegeben wird.

Code: Alles auswählen

class AnnotationsfileCreator:
    def __init__(self):
        self.info = {'description': 'my-project-name'}
        self.categories = [
            {'id': 1, 'name': 'Particle'},
            {'id': 2, 'name': 'LackOfFusion'},
            {'id': 3, 'name': 'Balling'}
        ]
        self.images = []
        self.annotations = []
        self.image_id = 1
        self.defect_id = 0   


    def add_image(self, image_name):
        anhang = {
            'id': self.image_id,
            'width': 1024,
            'height': 1024,
            'file_name': image_name
        }
        self.images.append(anhang)   


    def add_image_and_its_annotations(self, image_name, annotations):
        self.add_image(image_name)
        
        for annotation in annotations:
            self.annotations.append(dict(
                annotation,
                image_id=self.image_id,
                id=self.defect_id
            ))
            self.defect_id += 1
        self.image_id += 1


    def make_dict(self):
        return {
            'info': self.info,
            'images': self.images,
            'annotations': self.annotations,
            'categories': self.categories,
        }


extracted2 = [{
    'area': 34089.31160568068,
    'bbox': [193.6580310880829,
           191.00518134715026,
           206.9222797927461,
           218.86010362694304],
    'category_id': 1,
    'id': 0,
    'image_id': 1,
    'iscrowd': 0,
    'segmentation': [[197.63730569948189,
                    305.0777202072539,
                    193.6580310880829,
                    375.37823834196894,
                    236.1036269430052,
                    409.8652849740933,
                    348.8497409326425,
                    400.580310880829,
                    399.2538860103627,
                    314.36269430051817,
                    400.580310880829,
                    217.5336787564767,
                    336.9119170984456,
                    191.00518134715026,
                    267.9378238341969,
                    214.88082901554404]]
    }, {
    'area': 38838.81983408951,
    'bbox': [375.37823834196894,
           481.4922279792746,
           255.99999999999994,
           209.57512953367882],
    'category_id': 2,
    'id': 1,
    'image_id': 1,
    'iscrowd': 0,
    'segmentation': [[376.70466321243526,
                    599.5440414507772,
                    375.37823834196894,
                    643.3160621761658,
                    527.9170984455959,
                    691.0673575129534,
                    628.7253886010363,
                    615.4611398963731,
                    631.3782383419689,
                    531.8963730569949,
                    513.3264248704663,
                    481.4922279792746,
                    441.699481865285,
                    496.08290155440415,
                    399.2538860103627,
                    534.5492227979274]]
    }, {
    'area': 22147.3641708502,
    'bbox': [657.9067357512954,
           189.67875647668396,
           222.83937823834196,
           147.23316062176164],
    'category_id': 3,
    'id': 2,
    'image_id': 1,
    'iscrowd': 0,
    'segmentation': [[680.4559585492228,
                    233.45077720207254,
                    657.9067357512954,
                    269.2642487046632,
                    672.4974093264249,
                    307.73056994818654,
                    815.7512953367876,
                    336.9119170984456,
                    880.7461139896374,
                    252.02072538860105,
                    829.0155440414508,
                    197.63730569948189,
                    753.4093264248705,
                    189.67875647668396]]
    }
]

annotationfile = AnnotationsfileCreator()
annotationfile.add_image_and_its_annotations('2a.jpg', extracted2)
annotationfile.add_image_and_its_annotations('2b.jpg', extracted2)
G-Rizzle
User
Beiträge: 90
Registriert: Donnerstag 18. Februar 2021, 12:26

Sirius3 hat geschrieben: Donnerstag 10. März 2022, 20:02 `time` wird importiert, aber gar nicht benutzt.
Die vielen Leerzeilen machen den Code sehr schlecht lesbar. Mehr als zwei Leerzeilen am Stück machen nie Sinn.
Bei `listeee`, was bedeuten denn die drei `e`? Das sieht mir stark nach einem Schreibfehler aus.
In `add_image_and_its_annotations` änderst Du das übergebene Wörterbuch, was man nicht machen darf, weil es Seiteneffekte hat, statt dessen erzeugt man einfach ein neues Wörterbuch.
In `make_dict` wird ein neues Attribut eingeführt, was man nicht machen darf. Alle Attribute müsssen in `__init__` angelegt werden. Hier würde ich gar kein Attribut erwarten, sondern dass das Wörterbuch zurückgegeben wird.

Code: Alles auswählen

class AnnotationsfileCreator:
    def __init__(self):
        self.info = {'description': 'my-project-name'}
        self.categories = [
            {'id': 1, 'name': 'Particle'},
            {'id': 2, 'name': 'LackOfFusion'},
            {'id': 3, 'name': 'Balling'}
        ]
        self.images = []
        self.annotations = []
        self.image_id = 1
        self.defect_id = 0   


    def add_image(self, image_name):
        anhang = {
            'id': self.image_id,
            'width': 1024,
            'height': 1024,
            'file_name': image_name
        }
        self.images.append(anhang)   


    def add_image_and_its_annotations(self, image_name, annotations):
        self.add_image(image_name)
        
        for annotation in annotations:
            self.annotations.append(dict(
                annotation,
                image_id=self.image_id,
                id=self.defect_id
            ))
            self.defect_id += 1
        self.image_id += 1


    def make_dict(self):
        return {
            'info': self.info,
            'images': self.images,
            'annotations': self.annotations,
            'categories': self.categories,
        }


extracted2 = [{
    'area': 34089.31160568068,
    'bbox': [193.6580310880829,
           191.00518134715026,
           206.9222797927461,
           218.86010362694304],
    'category_id': 1,
    'id': 0,
    'image_id': 1,
    'iscrowd': 0,
    'segmentation': [[197.63730569948189,
                    305.0777202072539,
                    193.6580310880829,
                    375.37823834196894,
                    236.1036269430052,
                    409.8652849740933,
                    348.8497409326425,
                    400.580310880829,
                    399.2538860103627,
                    314.36269430051817,
                    400.580310880829,
                    217.5336787564767,
                    336.9119170984456,
                    191.00518134715026,
                    267.9378238341969,
                    214.88082901554404]]
    }, {
    'area': 38838.81983408951,
    'bbox': [375.37823834196894,
           481.4922279792746,
           255.99999999999994,
           209.57512953367882],
    'category_id': 2,
    'id': 1,
    'image_id': 1,
    'iscrowd': 0,
    'segmentation': [[376.70466321243526,
                    599.5440414507772,
                    375.37823834196894,
                    643.3160621761658,
                    527.9170984455959,
                    691.0673575129534,
                    628.7253886010363,
                    615.4611398963731,
                    631.3782383419689,
                    531.8963730569949,
                    513.3264248704663,
                    481.4922279792746,
                    441.699481865285,
                    496.08290155440415,
                    399.2538860103627,
                    534.5492227979274]]
    }, {
    'area': 22147.3641708502,
    'bbox': [657.9067357512954,
           189.67875647668396,
           222.83937823834196,
           147.23316062176164],
    'category_id': 3,
    'id': 2,
    'image_id': 1,
    'iscrowd': 0,
    'segmentation': [[680.4559585492228,
                    233.45077720207254,
                    657.9067357512954,
                    269.2642487046632,
                    672.4974093264249,
                    307.73056994818654,
                    815.7512953367876,
                    336.9119170984456,
                    880.7461139896374,
                    252.02072538860105,
                    829.0155440414508,
                    197.63730569948189,
                    753.4093264248705,
                    189.67875647668396]]
    }
]

annotationfile = AnnotationsfileCreator()
annotationfile.add_image_and_its_annotations('2a.jpg', extracted2)
annotationfile.add_image_and_its_annotations('2b.jpg', extracted2)
Danke für deine Review! Time-import und listeee waren aus der Testphase davor und nur temporär genutzt. Die restlichen von dir angesprochenen Themen setze ich um. In der For-Schleife erstelle ich nun wie bereits gesagt und von dir vorgeschlagen in jedem Durchlauf ein neues dict mit den entsprechenden Werten und appende dieses (nicht "element") zur annotations-Liste. So funktioniert es nun einwandfrei
Antworten