このPythonのコードがUnboundLocalErrorと出てしまう。


卒業研究で画像解析をしてその結果を送信することやらないといけなくて事前に用意された画像解析の行うコードに送信処理を書いたのですがface_recognition_scoreというものに数値が入っておりそれが0.6未満でifに分岐するようにしたいのですが条件式のところのface_recognition_scoreがUnboundLocalErrorと出てしまいます。同じ関数内に処理を書き込んでいるからローカルにはなっていると思うのですが、Pythonのことを全く理解していないのでどなたか詳しい方がいらしたら分かりやすく教えていただけると嬉しいです。

[code]

    import os
    import cv2
    import numpy as np
    import time
    import tensorflow as tf
    import mediapipe as mp
    import serial
    
    # モデルファイル名
    FACE_MODEL_NAME = "../models/face_model.tflite"
    
    # 登録画像ファイルパス
    DATA_PATH = '../data'
    
    def read_registface(model):
        # 画像を推論して特徴量のリストを作成する
        regist_list = []
        file_list = []
        for file in os.listdir(DATA_PATH):
            # 画像読み込み
            img = cv2.imread(os.path.join(DATA_PATH, file))
            # 前処理
            img_preprocessing = preprocessing(img)
            # 特徴量を取得
            predict = predict_model(model, img_preprocessing)
            # 特徴量を保持
            regist_list.append(predict[0])
            # 画像ファイル名を保持
            file_list.append(file)
        return np.array(regist_list), np.array(file_list)
    
    def preprocessing(img):
        # 画像の前処理
        img_preprocessing = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img_preprocessing = cv2.resize(img_preprocessing, (112, 112))
        img_preprocessing = img_preprocessing.astype(np.float32) / 255.
        if len(img_preprocessing.shape) == 3:
            img_preprocessing = np.expand_dims(img_preprocessing, 0)
        return img_preprocessing
    
    def predict_model(model, img):
        # TensorFlow Liteモデルの場合
        # モデルの入出力形状取得
        input_details = model.get_input_details()
        output_details = model.get_output_details()
        # 入力画像設定
        model.set_tensor(input_details[0]['index'], img)
        # 画像を推論
        model.invoke()
        # 推論結果取得
        embeds = model.get_tensor(output_details[0]['index'])
        
        return embeds
    
    def recognition(model, img, list):
        # 前処理
        img_preprocessing = preprocessing(img)
        # 計測開始
        time_start = time.perf_counter()
        # 画像を推論
        predict = predict_model(model, img_preprocessing)
        # 計測終了
        time_end = time.perf_counter()
        # 推論時間算出
        predict_time = time_end - time_start
        # 類似度算出
        max_score = 0
        max_score_index = 0
        # 特徴量をベクトルと見立てて絶対値を算出
        predict = predict / np.linalg.norm(predict)
        list = list / np.linalg.norm(list, axis=1).reshape(-1, 1)
        # 内積からcos類似度を算出
        vector_list = np.inner(predict, list)
        # 類似度が最大の値を取得
        max_score_index = np.argmax(vector_list)
        # 類似度が最大のインデックスを取得
        max_score = np.amax(vector_list)
    
        return max_score, max_score_index, predict_time
    
    def main():
        print('準備中')
        # カメラ設定
        vid = cv2.VideoCapture(0)
        vid.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y', 'U', 'Y', 'V'))
        vid.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        vid.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)
        vid.set(cv2.CAP_PROP_BUFFERSIZE, 1)
        vid.set(cv2.CAP_PROP_FPS, 20)
        ser = serial.Serial('/dev/ttyUSB0', 9600)
        # 顔検出モデル
        mp_face_detection = mp.solutions.face_detection
        face_detection = mp_face_detection.FaceDetection()
        # TensorFlow Liteモデルの場合
        face_model = tf.lite.Interpreter(model_path=FACE_MODEL_NAME)
        face_model.allocate_tensors()
        # 登録画像読み込み
        regist_list, file_list = read_registface(face_model)
        # 結果表示用画像
        img_result = np.zeros((950, 380, 3))
        result_cnt = 0
        # 顔認証フラグ
        recog_flag = False
        print('準備完了')
    
        while True:
            recog_flag = False
            start_time = time.perf_counter()
            # カメラから画像読み込み
            return_value, cap = vid.read()
            # カメラから画像読み込み失敗時リトライする
            if not return_value:
                continue
            # 推論用にカメラ画像をコピー
            img = cap.copy()
            # 画面表示用にカメラ画像をコピー
            img_show = cap.copy()
            fd_s = time.perf_counter()
            # 顔検出
            result = face_detection.process(img)
            bboxsize_check = 0
            face_bbox = [0, 0, 0, 0]
            if result.detections is not None:
                for detection in result.detections:
                    bbox = detection.location_data.relative_bounding_box
                    # 顔のサイズが一番大きい人を抽出
                    if bboxsize_check < int(bbox.width * img.shape[1]) * \
                                        int(bbox.height * img.shape[0]):
                        bboxsize_check = int(bbox.width * img.shape[1]) * \
                                         int(bbox.height * img.shape[0])
                    else:
                        continue
                    # 検出した顔の枠を更新
                    face_bbox[0] = int(bbox.xmin * img.shape[1])
                    face_bbox[1] = int(bbox.ymin * img.shape[0])
                    face_bbox[2] = face_bbox[0] + int(bbox.width * img.shape[1])
                    face_bbox[3] = face_bbox[1] + int(bbox.height * img.shape[0])
    
            fd_e = time.perf_counter()
            print('fd', fd_e-fd_s)
    
            face_img = []
            if face_bbox[2] > 0 and face_bbox[3] > 0:
                # 表示用画像に顔検知結果を描画
                cv2.rectangle(img_show, (face_bbox[0], face_bbox[1]),
                              (face_bbox[2], face_bbox[3]), (22, 22, 250), 2)
                # 顔を切り取り
                face_img = img[int(face_bbox[1]):int(face_bbox[3]),
                               int(face_bbox[0]):int(face_bbox[2])]
            # 顔認証
            if len(face_img) > 0 and len(regist_list) > 0 and \
               face_img.shape[0] > 0 and face_img.shape[1] > 0:
                # 顔認証結果を取得
                fr_s = time.perf_counter()
                face_recognition_score, index, predict_time = \
                    recognition(face_model, face_img, regist_list)
                #スコア送信
                if face_recognition_score < 0.6:
                    ser.write(str(face_recognition_score))
                    ser.close()
                # 結果表示用画像生成
                img_tmp = cv2.imread(os.path.join(DATA_PATH, file_list[index]))
                img_tmp = cv2.resize(img_tmp, (190, 190))
                # 類似度を描画
                cv2.putText(img_tmp, str(face_recognition_score),
                            (0, 30), cv2.FONT_HERSHEY_SIMPLEX,
                            1, (0, 0, 255), 2, cv2.LINE_AA)
                # 顔の画像を表示用にリサイズ
                face_img_tmp = cv2.resize(face_img, (190, 190))
                # 認証時の画像と登録画像を横並びに結合
                img_tmp = cv2.hconcat([face_img_tmp, img_tmp])
                # 初回認証時は1枚だけ表示
                if result_cnt == 0:
                    img_result = img_tmp
                result_cnt = result_cnt + 1
                # 5枚以下は、黒画像を追加
                if result_cnt < 5:
                    black = np.zeros((190, 380, 3))
                    black = black.astype('uint8')
                    img_result = img_result[:(result_cnt)*190, :]
                    # 過去の画像と最新の認証画像を結合
                    img_result = cv2.vconcat([img_result, img_tmp])
                    for l in range(5 - result_cnt):
                        # 下に黒い画像を結合
                        img_result = cv2.vconcat([img_result, black])
                else:
                    # 直近4枚の画像と最新の認証画像を結合
                    img_result = img_result[190:950, :]
                    img_result = cv2.vconcat([img_result, img_tmp])
                fr_e = time.perf_counter()
                recog_flag = True
                print('fr', fr_e-fr_s)
    
            end_time = time.perf_counter()
            fps = 1.0/(end_time-start_time)
            # 処理速度描画
            if recog_flag:
                cv2.putText(img_show, 'FPS:' + str(fps),
                            (500, 30), cv2.FONT_HERSHEY_SIMPLEX,
                            1, (0, 255, 0), 2, cv2.LINE_AA)
            else:
                cv2.putText(img_show, 'FPS:',
                            (500, 30), cv2.FONT_HERSHEY_SIMPLEX,
                            1, (0, 255, 0), 2, cv2.LINE_AA)
            cv2.putText(img_show, 'RecognitionMode',
                        (375, 350), cv2.FONT_HERSHEY_SIMPLEX,
                        1, (0, 255, 0), 2, cv2.LINE_AA)
            # 画像表示
            cv2.imshow('FaceRecognition', img_show)
            cv2.imshow('Result', img_result)
            
            # OpenCVのGUIイベントを処理するためのウェイトかつ押下キーを取得
            key_code = cv2.waitKey(1)
            # Escキー押下でループを抜けてアプリを終了する
            if key_code == 27:
                break
    
        return
    
    
    if __name__ == '__main__':
        main()
    
    
[/code]




考えられる原因としては、実際には「スコア送信」のブロックのインデントが「顔認証」のブロックと同じレベルになっていることでしょうか。念の為、ソースコードを確認してみて下さい。

[code]

            # 顔認証
            if len(face_img) > 0 and len(regist_list) > 0 and \
               face_img.shape[0] > 0 and face_img.shape[1] > 0:
                # 顔認証結果を取得
                fr_s = time.perf_counter()
                face_recognition_score, index, predict_time = \
                    recognition(face_model, face_img, regist_list)
    
            #スコア送信
            if face_recognition_score < 0.6:
                ser.write(str(face_recognition_score))
                ser.close()
    
[/code]

以下の単純なスクリプトでは `face_recognition_score = 1`
は実行されません。つまり、`face_recognition_score` が未定義なので `print(face_recognition_score)`
で `UnboundLocalError` が発生することになります。 ~~質問文に掲示されているコードには`face_recognition_score`
が見当たりませんが、~~ おそらく条件式が偽(`False`)になるブロック内で `face_recognition_score`
が定義されているものと思わまれます。

[code]

    def test_function():
        if False:
            face_recognition_score = 1
    
        print(face_recognition_score)
    
    if __name__ == '__main__':
        test_function()
    
    # Error occurred
    Traceback (most recent call last):
      File "test.py", line 9, in <module>
        test_function()
      File "test.py", line 6, in test_function
        print(face_recognition_score)
              ^^^^^^^^^^^^^^^^^^^^^^
    UnboundLocalError: cannot access local variable 'face_recognition_score' where it is not associated with a value
    
[/code]




考えられる原因としては、実際には「スコア送信」のブロックのインデントが「顔認証」のブロックと同じレベルになっていることでしょうか。念の為、ソースコードを確認してみて下さい。

[code]

            # 顔認証
            if len(face_img) > 0 and len(regist_list) > 0 and \
               face_img.shape[0] > 0 and face_img.shape[1] > 0:
                # 顔認証結果を取得
                fr_s = time.perf_counter()
                face_recognition_score, index, predict_time = \
                    recognition(face_model, face_img, regist_list)
    
            #スコア送信
            if face_recognition_score < 0.6:
                ser.write(str(face_recognition_score))
                ser.close()
    
[/code]

以下の単純なスクリプトでは `face_recognition_score = 1`
は実行されません。つまり、`face_recognition_score` が未定義なので `print(face_recognition_score)`
で `UnboundLocalError` が発生することになります。 ~~質問文に掲示されているコードには`face_recognition_score`
が見当たりませんが、~~ おそらく条件式が偽(`False`)になるブロック内で `face_recognition_score`
が定義されているものと思わまれます。

[code]

    def test_function():
        if False:
            face_recognition_score = 1
    
        print(face_recognition_score)
    
    if __name__ == '__main__':
        test_function()
    
    # Error occurred
    Traceback (most recent call last):
      File "test.py", line 9, in <module>
        test_function()
      File "test.py", line 6, in test_function
        print(face_recognition_score)
              ^^^^^^^^^^^^^^^^^^^^^^
    UnboundLocalError: cannot access local variable 'face_recognition_score' where it is not associated with a value
    
[/code]

