openCV cap.read() -> NoneType

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
m.g.o.d
User
Beiträge: 75
Registriert: Samstag 4. April 2020, 13:17

Hallo Zusammen,

ich habe ein Problem, was schwierig zu lösen ist. Folgendes Programm wirft diesen Traceback:
File "d:\python_dev\GRAPHIC_ALARMING_MACHINE\SOURCECODE\GraphicAlarmMachine.py", line 302, in run
vid_cropped = vid[asset_data[roi_amount][4]: asset_data[roi_amount][4]+asset_data[roi_amount][6], asset_data[roi_amount][3]:asset_data[roi_amount][3]+asset_data[roi_amount][5]]
TypeError: 'NoneType' object is not subscriptable

Ich habe selbstverständlich den Pfad der Videodatei überprüft, der ist korrekt. Codecs usw. sind auch alle vorhanden und in Ordnung. Außerdem tritt dieser Fehler unregelmäßig auf. Ich habe die Vermutung, dass die dauerhafte Neubelegung mit dem cap = cv2.VideoCapture(get_latest_video) irgendwann zu einem internen overflow (?!) führt. Daher habe ich nach jedem iterationslauf ein cap.release() eingebaut. Wichtig ist noch, alles was hier zu sehen ist, ist ein Iterationsschritt mit jeweils unterschiedlichen Daten. Ich beoachte, dass der Traceback vorallem dann auftritt, wenn zwei Videos nacheinander analysiert werden. Wenn bei einem Video nix passiert und bei anderen etwas analysiert wird, tritt der Fehler weniger auf.

Da ich mir im Internet den Wolf gesucht habe und mein Problem dort nirgends in der Form auftritt, hoffe ich sehr, jemand kann mir helfen. Gerne erkläre ich das Programm, falls wichtige Dinge nicht aus dem Quellcode hervorgehen. Tausend Dank für jede Hilfestellung!

Code: Alles auswählen

 if self.pts_list_global[index][row_var[(temp_name)]][3] <= timestamp:           
                    
                    if asset_data != False:

                        # sleep for checkintervall 
                        sleep(asset_data[0][7])                                                      
                        
                        # updating GUI
                        status = "analyzing"
                        self.statuslog.emit(status)

                        # calculate milliseonds for getting fps
                        samplecheck = 1/asset_data[0][8] *1000
                        samplecheck = int(samplecheck)
    		   try:
                            # Load Video data
                            video_path_rebuild = self.init_videooperations.build_path(self.roi_channelconfig[index][1])
                            get_latest_video =  self.init_videooperations.get_latest_vid(video_path_rebuild)
                            
                            
                            # ctime = modifydate. Therefor substract delaytime xentaurix
                            get_ctime_video = self.init_videooperations.video_ctime(get_latest_video, self.delaytime_xentaurix)

                            # substract xentaurix delay to get the right SOM
                            requested_event_in = self.pts_list_global[index][row_var[(temp_name)]][3] - dt.timedelta(minutes=int(self.delaytime_xentaurix[3:5]))
                   
                            # Further progress: Add intervall length each time
                            start_frame_number = self.init_videooperations.calculate_som(get_ctime_video,  requested_event_in)
                           
                            # create cv2 videoobject
                            cap = cv2.VideoCapture(get_latest_video) 
                                
                            # Add delay for muxing. Different for SD/HD
                            delay_mux = self.roi_channelconfig[0][3] * 25
                            
                            # Add muxing delay 
                            start_frame_number_final = start_frame_number + delay_mux 

                            # Add frames to calculate further frames in vid. Start 0 , += Intervall length
                            _som = som_progress[temp_name] * 25
                            start_frame_number_final_som = start_frame_number_final + _som
                            som_progress[temp_name] += asset_data[0][11]
                        
                            # set correct start of the video
                            cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame_number_final_som)
    
                        except Exception as e:
                            self.logger.error('Failed to load video data', exc_info=True)

                        try:
                            # Perform calulation for every asset (secondary under the same ID as Logo)
                            for roi_amount in range(len(asset_data)):
                          
                          
                                while True:
                                    print(framecount[temp_name])
                                    print(self.frames)
                                    time_end = dt.datetime.now().replace(microsecond=0)

                                    if self.frames == 0:
                                        # Grap the time once fixed without changes over the loop
                                        time_start = dt.datetime.now().replace(microsecond=0)
                                       
                            
                                    # read frame by frame
                                    success, vid = cap.read() 

                                    # Wait for milliseconds to grap desired fps. formula (1/desired frames)*1000
                                    cv2.waitKey(samplecheck)                        
                                  
                                    # increase frames to prevent, that time_start will be changed
                                    self.frames +=1

                                    # eval framecount for later calculation in error_eval
                                    framecount[temp_name] += 1                    
                        
                                    # in case if an secondary with the same Asset ID is given -> more then one ROI 
                                    vid_cropped = vid[asset_data[roi_amount][4]: asset_data[roi_amount][4]+asset_data[roi_amount][6], asset_data[roi_amount][3]:asset_data[roi_amount][3]+asset_data[roi_amount][5]]
                                
                                    # Convert Source to gray
                                    gray = cv2.cvtColor(vid_cropped, cv2.COLOR_BGR2GRAY)

                                    # Template for calculation
                                    template = asset_data[roi_amount][10]
                                    height, width = template.shape[::]
                
                                    # cv2.TM_SQDIFF = Minimum Square Difference with Threshold
                                    res = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED)    
                                            
                                    #For TM_CCOEFF_NORMED, larger values means good fit
                                    threshold = asset_data[roi_amount][9]

                                    # Return Tuple
                                    loc = np.where( res >= threshold)

                                    # Final result
                                    if len(loc[0]) > 0:
                                        self.resultlog.emit("True")
                                    else:
                                        errors_var[temp_name] += 1
                                        self.resultlog.emit("false")

                  
                                    cap.release() 
                            
                                    if time_end >= time_start + timedelta(seconds=asset_data[0][11]):
                                        # write results in csv for later error evaluation

                                        with open(r"D:\python_dev\GRAPHIC_ALARMING_MACHINE\ALARMING\alarms.csv", mode='a', newline="") as csv_file_writedata:
                                            fieldnames = ['channelname', 'asset_id','framescount', 'false', 'timestamp', 'xentaurixdelay']
                                            writer = csv.DictWriter(csv_file_writedata, fieldnames=fieldnames)
                                            writer.writeheader()   
                                            writer.writerow({'channelname': temp_name , 'asset_id':asset_data[0][1], 'framescount': framecount[temp_name], 'false':errors_var[temp_name], 'timestamp':time_end, 'xentaurixdelay':self.roi_channelconfig[index][2]})
                                      
                                        # reset for getting fixed time
                                        self.frames = 0         

                                        # reset error variables
                                        errors_var[temp_name] = 0

                                        # reset framecount
                                        framecount[temp_name] = 0  

                                        self.row_false = 0

                                    
                                        cap.release()            

                                        # leave core calc loop
                                        break                                    
                                        
                        except Exception as e:
                            self.logger.error('Core Calculation failed for channel: '+temp_name, exc_info=True)
                            break
Sirius3
User
Beiträge: 18264
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Einrückungen sind fehlerhaft und die Funktion viel zu lange. Du solltest die unbedingt in einige kleinere Funktionen unterteilen.
Dass `asset_data` mal den Wert False und mal was komplexes enthalten soll, sieht nach einem Programmierfehler aus.
get_latest_video ist kein Name für eine Variable, ebensowenig get_ctime_video, das sollte wohl sowas wie creation_time heißen.
Benutze keine Abkürzungen, der Name pts_list_global ist sehr seltsam.

Über einen Index iteriert man nicht, sondern über asset_data direkt.
Dass Du in die csv-Datei ständig der Header geschrieben wird, ist auch komisch.
Und schließlich bei cap.read solltest Du auch prüfen, ob success wahr ist.
m.g.o.d
User
Beiträge: 75
Registriert: Samstag 4. April 2020, 13:17

Okay. Aber ich kann grundsätzlich verschiedene Videodaten nacheinander der cap = cv2.VideoCapture(get_latest_video) übergeben, oder? Muss ich dann cap.release() ausführen? Der "None"-Wert kommt definitiv nicht von asset_data, weil das aus einer Datenbank lädt, die richtig ist. Ich hab beim print(vid) auch Daten, aber am Ende steht da "None". Dann wieder Daten. Sehr merkwürdig.

Muss ich vielleicht die Variable "Cap" am Ende in einer finally Anweißung löschen um dann mit einem anderen Video weiterzumachen?
Antworten