Study Blog

自分の興味関心が向いたものを、好きな時好きなだけ気分で勉強したことを記すブログ

Raspberry Pi4 画像認識 ~⑧独自画像学習 RPi上で推論~

①~⑦までで行った、セットアップから学習まで行ってきました。
学習モデルが完成したので、そのモデルをエッジデバイスとするラズパイに移行してリアルタイム推論を行ってシリーズは終了です。

1. google driveからラズパイへ.tfliteモデルを移行する

windows <-> ラズパイ間のファイルのやり取りを行うために、「samba」というファイルサーバーを入れます。
ここは、ラズパイのターミナル上で行います。

1-1. sambaをインストール

sudo apt install samba -y

1-2. 設定ファイルをconfファイルに追記

バックアップを取っておきます。

sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_backup

nanoというエディタで編集します。

sudo nano /etc/samba/smb.conf 
[pi]
comment = pi
path = /home/pi
force user = pi
read only = no
browsable = yes
public = yes

sambaサービスの再起動

sudo systemctl restart smbd

windowsエクスプローラーの「ネットワーク」を開いて
¥¥(ラズパイのIPアドレス)を入力すると接続できます。

そしたら、以前作成した.tfliteファイルをラズパイ上の適当なフォルダに移行してあげます。

2. 推論プログラム作成

基本的に以前作成したプログラムを使用しますが、一部映像をリアルタイムで推論できるように変更します。

2-1. ライブラリのインポート

まず、必要なライブラリをインポートします。

from picamera2.picamera2 import *
import time

import cv2
import numpy as np
import matplotlib.pyplot as plt

import tensorflow as tf
from tflite_support import metadata

2-2. 準備

MODEL_PATH = "model.tfliteの絶対パス"
SAVE_PATH = "撮影した画像の保存ディレクトリの絶対パス"

# パイカメラの準備(bullseye用)
camera = Picamera2()
camera.start_preview()
camera.configure(camera.preview_configuration())
camera.start()

# tfliteのメタデータ(グー/チョキ/パー)の取得
displayer = metadata.MetadataDisplayer.with_model_file(MODEL_PATH)
for i, file_name in enumerate(displayer.get_packed_associated_file_list()):
    displayer.get_associated_file_buffer(file_name)

label = str(displayer.get_associated_file_buffer(file_name))[2:]
label_list = label.split('\\n')

classes = label_list[:-1]

2-3. 映像をテンソルに変換する関数

コメントのように、映像をnumpy配列として読み込むためそれをそのままtensor型へ変更します。

def preprocess_image(image_path, input_size):
    """Preprocess the input image to feed to the TFLite model"""
    
    """
    # 画像を1枚ずつ読み込む場合
    img = tf.io.read_file(image_path)
    img = tf.io.decode_image(img, channels=3)
    img = tf.image.convert_image_dtype(img, tf.uint8)
    """

 # 映像をnumpy配列として読み込むので、そのままtensorへ変更する
    img = tf.convert_to_tensor(image_path) 

 # 変更なし
    original_image = img
    resized_img = tf.image.resize(img, input_size)
    resized_img = resized_img[tf.newaxis, :]
    resized_img = tf.cast(resized_img, dtype=tf.uint8)
    return resized_img, original_image

2-4. オブジェクト(手)を探す関数

変更ありません

def detect_objects(interpreter, image, threshold):
    """Returns a list of detection results, each a dictionary of object info."""

    signature_fn = interpreter.get_signature_runner()

    # Feed the input image to the model
    output = signature_fn(images=image)

    # Get all outputs from the model
    count = int(np.squeeze(output['output_0']))
    scores = np.squeeze(output['output_1'])
    classes = np.squeeze(output['output_2'])
    boxes = np.squeeze(output['output_3'])

    results = []
    for i in range(count):
        if scores[i] >= threshold:
            result = {
            'bounding_box': boxes[i],
            'class_id': classes[i],
            'score': scores[i]
            }
            results.append(result)
    return results

2-5.推論実行関数

def run_odt_and_draw_results(image_path, interpreter, threshold=0.6):
    """Run object detection on the input image and draw the detection results"""
    # Load the input shape required by the model
    _, input_height, input_width, _ = interpreter.get_input_details()[0]['shape']

    # Load the input image and preprocess it
    preprocessed_image, original_image = preprocess_image(
        image_path,
        (input_height, input_width)
    )

    # Run object detection on the input image
    results = detect_objects(interpreter, preprocessed_image, threshold=threshold)

    # Plot the detection results on the input image
    original_image_np = original_image.numpy().astype(np.uint8)
    for obj in results:
        # Convert the object bounding box from relative coordinates to absolute
        # coordinates based on the original image resolution
        ymin, xmin, ymax, xmax = obj['bounding_box']
        xmin = int(xmin * original_image_np.shape[1])
        xmax = int(xmax * original_image_np.shape[1])
        ymin = int(ymin * original_image_np.shape[0])
        ymax = int(ymax * original_image_np.shape[0])

        # Find the class index of the current object
        class_id = int(obj['class_id'])

        # Draw the bounding box and label on the image
        color = [int(c) for c in COLORS[class_id]]
        cv2.rectangle(original_image_np, (xmin, ymin), (xmax, ymax), color, 2)
        # Make adjustments to make the label visible for all objects
        y = ymin - 15 if ymin - 15 > 15 else ymin + 15
        label = "{}: {:.0f}%".format(classes[class_id], obj['score'] * 100)
        cv2.putText(original_image_np, label, (xmin, y),
        cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

    # Return the final image
    original_uint8 = original_image_np.astype(np.uint8)
    return original_uint8

2-6. ラズパイカメラからの映像をrgbへ変更する関数

この部分は要改良の余地ありです。
ラズパイからの映像をpicamera2モジュールで読み込むと、rgbaという形式になっていました。
numpy配列をtensorとして読み込むためには、rgba -> rgbへ次元を変更する必要があります。
そのため、以下の関数を追加しました。

def rgba2rgb( rgba, background=(255,255,255) ):
    # reference(https://stackoverflow.com/questions/50331463/convert-rgba-to-rgb-in-python)
    row, col, ch = rgba.shape

    if ch == 3:
        return rgba

    assert ch == 4, 'RGBA image has 4 channels.'

    rgb = np.zeros( (row, col, 3), dtype='float32' )
    r, g, b, a = rgba[:,:,0], rgba[:,:,1], rgba[:,:,2], rgba[:,:,3]

    a = np.asarray( a, dtype='float32' ) / 255.0

    R, G, B = background

    rgb[:,:,0] = r * a + (1.0 - a) * R
    rgb[:,:,1] = g * a + (1.0 - a) * G
    rgb[:,:,2] = b * a + (1.0 - a) * B

    return np.asarray( rgb, dtype='uint8' )

2-7.メイン実行プログラム

上記で作成した関数を使用して実行関数を作成して終了です。

if __name__ == '__main__':
    # 画像を撮影した際の番号
    count = 1
    # 推論の際の四角の色を指定
    COLORS = np.random.randint(0, 255, size=(len(classes), 3), dtype=np.uint8)

    # 推論と映像表示
    while True:
        image = camera.capture_array()
        image = rgba2rgb(image)    # rgba を rgb へ変更

        # 映像表示を終了する際のキー指定
        key = cv2.waitKey(1)
        if key == 27: # when ESC key is pressed break
            break

        # 推論
        interpreter = tf.lite.Interpreter(model_path=str(MODEL_PATH))
        interpreter.allocate_tensors()
        result = run_odt_and_draw_results(image, interpreter=interpreter)

        # 撮影をする際のキー指定
        if key == ord('c'):    # when "c" key is pressed capture image as "SAVE_PATH/(count).png"
            cv2.imwrite(SAVE_PATH + str(count) + '.png', result)
            count += 1

        cv2.imshow('View', result)
        
    # 終了する際のプログラム
    camera.close()
    cv2.destroyAllWindows()

3. 推論実行

上記で準備したプログラムをラズパイ上で実行すると、このようになりました。
パー

チョキ

グー

まず、全体的に画像が青みがかっています。
これは、「rgba2rgb」関数の部分で生じている問題です。今後調査をして改良しようと思います。

次に、推論精度が全体的に低めです。
これは、モデル作成段階である程度分かっていたことで、画像の枚数を増加させることで改善できると思います。

おおざっぱではありますが、0(ラズパイのセットアップ)~10(オリジナルモデルの作成・推論)までを解説してまいりました。
これで簡単なPoC程度を行うことはできるかと思います。
さらなる改善のためには、機械学習自体を深く学んだり、問題そのものへの深い理解が必要になると思います。

実際に準備から推論することを経験する人はなかなかいないと思います。
また、セットアップ->オリジナルモデルの作成->推論までを一挙に解説している記事などがなかったため作成してみました。

情報は"生もの"で時間経過と共に、各ライブラリのアップデートやサポート終了等によって使えなくなってしまいます。
可能な限り最新の情報を得ながら実践してみてください。

お疲れさまでした。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~⑦独自画像学習 推論~

独自の画像を使って学習モデルを作るところまで完了しました。
実際にcolab上で学習に使用していない新しい画像を用いて、推論を行ってみましょう。

1. 下準備

!pip install tflite-support
from pathlib import Path
import cv2
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

import tensorflow as tf
from tflite_support import metadata
MODEL_PATH = Path("※model.tfliteのパス")
IMAGE_PATH = Path("※新たな画像のパス")

IMAGE_LIST = list(IMAGE_PATH.glob('*'))

今回は、学習で使用していない「新たな画像」をどこかから入手してgoogle driveに保存します。
手っ取り早いのはスマホで撮影した画像でよいかと思います。
ただし、iPhoneで撮影した画像は「.HEIC」という形式のため、「.jpg/.png」に変換する必要がありますので注意してください。

2. tfliteモデル内の情報を抜き出す

公式のプログラムをそのまま上から実行していけば、推論までたどり着きますが、
ラズパイへ移行した後に、tfliteのメタデータを取得する方法が記載されていなかったため、
ここでは、別プログラムとして推論を行います。

displayer = metadata.MetadataDisplayer.with_model_file(MODEL_PATH)

print("Associated file(s) populated:")
for file_name in displayer.get_packed_associated_file_list():
  print("file name: ", file_name)
  print("file content:")
  print(displayer.get_associated_file_buffer(file_name))
Associated file(s) populated:
file name:  labelmap.txt
file content:
b'label\nScissors\nrock\npaper\n'

学習したtfliteモデルで推論した結果から、ラベルデータや、推論値、bbox値等を取得しなければなりません。
ラベルデータ以外は公式プログラムをそのまま参照できるので、ラベルデータを探します。

label = str(displayer.get_associated_file_buffer(file_name))
label = label[2:]
label_list = label.split('\\n')

classes = label_list[:-1]
print(len(classes))
print(classes)

ラベル出力のリスト中に、'label'を含ませる必要があります。

3. 推論用関数の定義

def preprocess_image(image_path, input_size):
    """Preprocess the input image to feed to the TFLite model"""
    img = tf.io.read_file(image_path)
    img = tf.io.decode_image(img, channels=3)
    img = tf.image.convert_image_dtype(img, tf.uint8)
    original_image = img
    resized_img = tf.image.resize(img, input_size)
    resized_img = resized_img[tf.newaxis, :]
    resized_img = tf.cast(resized_img, dtype=tf.uint8)
    return resized_img, original_image

「.jpg/.png」形式のデータを、学習モデル.tfliteが読めるように変換する関数です。

def detect_objects(interpreter, image, threshold):
    """Returns a list of detection results, each a dictionary of object info."""

    signature_fn = interpreter.get_signature_runner()

    # Feed the input image to the model
    output = signature_fn(images=image)

    # Get all outputs from the model
    count = int(np.squeeze(output['output_0']))
    scores = np.squeeze(output['output_1'])
    classes = np.squeeze(output['output_2'])
    boxes = np.squeeze(output['output_3'])

    results = []
    for i in range(count):
        if scores[i] >= threshold:
            result = {
            'bounding_box': boxes[i],
            'class_id': classes[i],
            'score': scores[i]
            }
            results.append(result)
    return results

画像の中の物体を推論するための関数です。
ここで、推論値やbboxの値がわかります。
結果は、辞書として出力されてきます。

def run_odt_and_draw_results(image_path, interpreter, threshold=0.5):
    """Run object detection on the input image and draw the detection results"""
    # Load the input shape required by the model
    _, input_height, input_width, _ = interpreter.get_input_details()[0]['shape']

    # Load the input image and preprocess it
    preprocessed_image, original_image = preprocess_image(
        image_path,
        (input_height, input_width)
    )

    # Run object detection on the input image
    results = detect_objects(interpreter, preprocessed_image, threshold=threshold)

    # Plot the detection results on the input image
    original_image_np = original_image.numpy().astype(np.uint8)
    for obj in results:
        # Convert the object bounding box from relative coordinates to absolute
        # coordinates based on the original image resolution
        ymin, xmin, ymax, xmax = obj['bounding_box']
        xmin = int(xmin * original_image_np.shape[1])
        xmax = int(xmax * original_image_np.shape[1])
        ymin = int(ymin * original_image_np.shape[0])
        ymax = int(ymax * original_image_np.shape[0])

        # Find the class index of the current object
        class_id = int(obj['class_id'])

        # Draw the bounding box and label on the image
        color = [int(c) for c in COLORS[class_id]]
        cv2.rectangle(original_image_np, (xmin, ymin), (xmax, ymax), color, 2)
        # Make adjustments to make the label visible for all objects
        y = ymin - 15 if ymin - 15 > 15 else ymin + 15
        label = "{}: {:.0f}%".format(classes[class_id], obj['score'] * 100)
        cv2.putText(original_image_np, label, (xmin, y),
        cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

    # Return the final image
    original_uint8 = original_image_np.astype(np.uint8)
    return original_uint8

上記2つの関数を使って、物体検出を行う関数です。

4. 推論

image_path = str(IMAGE_LIST[0])
interpreter = tf.lite.Interpreter(model_path=str(MODEL_PATH))
interpreter.allocate_tensors()

COLORS = np.random.randint(0, 255, size=(len(classes), 3), dtype=np.uint8)

detection_result_image = run_odt_and_draw_results(image_path=image_path, interpreter=interpreter)
# Show the detection result
Image.fromarray(detection_result_image)

実際に推論をしてみた画像がこちら

チョキ単体の場合、「チョキ:86%」という結果に。

一方、すべての手が1枚に移っている画像では、
グーは検出されず、パーは「チョキ:66%」と誤認識され、チョキは「チョキ:54%」となっています。

後者のように誤認識されてしまう理由として、
「学習画像内に手が一つしかなかったこと」「画像いっぱいに手が写っていたこと」などが考えられると思います。
2枚目の写真のように、複数手がある画像を学習しておらず、かつ手が小さいため推論制度が低下した可能性があります。

次回は、このモデルをラズパイへ移してカメラから推論します。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~⑥独自画像学習 独自画像の学習~

アノテーションCSVを変更し、Tensorflow model makerの物体検出で使用できる形に変更しました。
今回は、この変更したCSVを用いてモデルを学習させます。

1.下準備

基本的に、Tensorflowの公式ドキュメント
Object Detection with TensorFlow Lite Model Maker
に沿って行います。

!pip install -q --use-deprecated=legacy-resolver tflite-model-maker
!pip install -q pycocotools
!pip install -q opencv-python-headless==4.1.2.30

google colabにtflite model maker / pycocotools / opencvをインストール

import numpy as np
from pathlib import Path

from tflite_model_maker.config import QuantizationConfig
from tflite_model_maker.config import ExportFormat
from tflite_model_maker import model_spec
from tflite_model_maker import object_detector

import tensorflow as tf
assert tf.__version__.startswith('2')

tf.get_logger().setLevel('ERROR')
from absl import logging
logging.set_verbosity(logging.ERROR)

ライブラリインポート

ANNO_CSV = Path("※アノテーションdataset.csvのパス")
SAVE_PATH = Path("※今回制作するmodelの保存パス")

パスの指定

spec = model_spec.get('efficientdet_lite0')

ここで、物体検出モデルを指定します。ここでは、EfficientNetというニューラルネットワークモデルをtfliteで利用できるように変換したものを指定しています。
公式ではefficientdet_lite0~4をサポートしているようで、数字が大きくなるほど精度が高くなり、推論速度が遅くなるようです。

train_data, validation_data, test_data = object_detector.DataLoader.from_csv(ANNO_CSV)

前回修正したCSVファイルを使って、訓練データ、評価データ、テストデータを作成

model = object_detector.create(train_data, model_spec=spec, batch_size=8, train_whole_model=True, validation_data=validation_data)

ここで、学習モデルを作成します。
画像枚数によりますが、じゃんけん画像の場合20~30分程度時間がかかります。
メモリ不足になる場合は、「batch_size=」の部分の数字を小さくするとうまくいこことが多いです。

batch_size=8は、8枚の画像を1セットとして学習させることをさしています。
batch_sizeを大きくすれば、まとめてたくさんの画像を学習でき、batch_sizeを小さくすれば、少量ずつ画像を学習させることができます。
画像が多い場合、batch_sizeを大きくすることで学習時間を短縮することもできます。
適宜変更して対応してみてください。

Epoch 1/50
16/16 [==============================] - 73s 3s/step - det_loss: 1.6946 - cls_loss: 1.1217 - box_loss: 0.0115 - reg_l2_loss: 0.0633 - loss: 1.7579 - learning_rate: 0.0090 - gradient_norm: 1.3597 - val_det_loss: 1.5367 - val_cls_loss: 1.0551 - val_box_loss: 0.0096 - val_reg_l2_loss: 0.0633 - val_loss: 1.6001
Epoch 2/50
16/16 [==============================] - 40s 2s/step - det_loss: 1.3411 - cls_loss: 0.9364 - box_loss: 0.0081 - reg_l2_loss: 0.0633 - loss: 1.4044 - learning_rate: 0.0100 - gradient_norm: 1.7222 - val_det_loss: 1.1773 - val_cls_loss: 0.8345 - val_box_loss: 0.0069 - val_reg_l2_loss: 0.0633 - val_loss: 1.2406
Epoch 3/50
16/16 [==============================] - 39s 2s/step - det_loss: 0.9503 - cls_loss: 0.6632 - box_loss: 0.0057 - reg_l2_loss: 0.0634 - loss: 1.0137 - learning_rate: 0.0099 - gradient_norm: 1.8717 - val_det_loss: 0.9387 - val_cls_loss: 0.5932 - val_box_loss: 0.0069 - val_reg_l2_loss: 0.0634 - val_loss: 1.0021
Epoch 4/50
16/16 [==============================] - 40s 2s/step - det_loss: 0.7808 - cls_loss: 0.5625 - box_loss: 0.0044 - reg_l2_loss: 0.0634 - loss: 0.8442 - learning_rate: 0.0099 - gradient_norm: 1.9342 - val_det_loss: 0.9141 - val_cls_loss: 0.4919 - val_box_loss: 0.0084 - val_reg_l2_loss: 0.0634 - val_loss: 0.9775
Epoch 5/50
16/16 [==============================] - 46s 3s/step - det_loss: 0.6327 - cls_loss: 0.4590 - box_loss: 0.0035 - reg_l2_loss: 0.0634 - loss: 0.6961 - learning_rate: 0.0098 - gradient_norm: 2.4829 - val_det_loss: 0.6877 - val_cls_loss: 0.4158 - val_box_loss: 0.0054 - val_reg_l2_loss: 0.0634 - val_loss: 0.7511
Epoch 6/50
16/16 [==============================] - 40s 2s/step - det_loss: 0.5148 - cls_loss: 0.3654 - box_loss: 0.0030 - reg_l2_loss: 0.0634 - loss: 0.5782 - learning_rate: 0.0097 - gradient_norm: 2.0064 - val_det_loss: 0.6624 - val_cls_loss: 0.3615 - val_box_loss: 0.0060 - val_reg_l2_loss: 0.0634 - val_loss: 0.7258
Epoch 7/50
16/16 [==============================] - 39s 2s/step - det_loss: 0.4151 - cls_loss: 0.2857 - box_loss: 0.0026 - reg_l2_loss: 0.0634 - loss: 0.4786 - learning_rate: 0.0096 - gradient_norm: 1.8357 - val_det_loss: 0.5232 - val_cls_loss: 0.3218 - val_box_loss: 0.0040 - val_reg_l2_loss: 0.0634 - val_loss: 0.5866
Epoch 8/50
16/16 [==============================] - 40s 3s/step - det_loss: 0.4025 - cls_loss: 0.2825 - box_loss: 0.0024 - reg_l2_loss: 0.0635 - loss: 0.4659 - learning_rate: 0.0094 - gradient_norm: 2.3049 - val_det_loss: 0.6151 - val_cls_loss: 0.3453 - val_box_loss: 0.0054 - val_reg_l2_loss: 0.0635 - val_loss: 0.6786
Epoch 9/50
16/16 [==============================] - 40s 3s/step - det_loss: 0.3461 - cls_loss: 0.2444 - box_loss: 0.0020 - reg_l2_loss: 0.0635 - loss: 0.4096 - learning_rate: 0.0093 - gradient_norm: 2.0001 - val_det_loss: 0.4147 - val_cls_loss: 0.2451 - val_box_loss: 0.0034 - val_reg_l2_loss: 0.0635 - val_loss: 0.4782
Epoch 10/50
16/16 [==============================] - 41s 3s/step - det_loss: 0.3328 - cls_loss: 0.2338 - box_loss: 0.0020 - reg_l2_loss: 0.0635 - loss: 0.3963 - learning_rate: 0.0091 - gradient_norm: 1.9760 - val_det_loss: 0.3180 - val_cls_loss: 0.2151 - val_box_loss: 0.0021 - val_reg_l2_loss: 0.0635 - val_loss: 0.3815

実際の学習過程が出力されていて、学習が正常に行われているかを確認することができます。
val_lossの数値が徐々に小さくなっていることが確認できれば大方うまくいってると思って大丈夫です。

うまく学習できていない場合、val_loss部分が初めから「0.000」で変化しない場合が多いと思います。
その場合は、アノテーションCSV部分で誤りがあることが大半だと思います。
アノテーションCSVのx/yの数字を見直したり、画像パスを見直したりしましょう。

model.evaluate(test_data)
1/1 [==============================] - 6s 6s/step

{'AP': 0.91557753,
 'AP50': 1.0,
 'AP75': 1.0,
 'AP_/Scissors': 0.9158746,
 'AP_/label': -1.0,
 'AP_/paper': 0.93646866,
 'AP_/rock': 0.89438945,
 'APl': 0.91557753,
 'APm': -1.0,
 'APs': -1.0,
 'ARl': 0.9261905,
 'ARm': -1.0,
 'ARmax1': 0.91952384,
 'ARmax10': 0.9261905,
 'ARmax100': 0.9261905,
 'ARs': -1.0}

モデルを評価して確認

model.export(export_dir=SAVE_PATH)
model.evaluate_tflite(str(SAVE_PATH) + '/model.tflite', test_data)
18/18 [==============================] - 38s 2s/step

{'AP': 0.9018482,
 'AP50': 1.0,
 'AP75': 1.0,
 'AP_/Scissors': 0.87204623,
 'AP_/label': -1.0,
 'AP_/paper': 0.93646866,
 'AP_/rock': 0.8970297,
 'APl': 0.9018482,
 'APm': -1.0,
 'APs': -1.0,
 'ARl': 0.91190475,
 'ARm': -1.0,
 'ARmax1': 0.91190475,
 'ARmax10': 0.91190475,
 'ARmax100': 0.91190475,
 'ARs': -1.0}

学習モデルをgoogle driveに保存して、テストデータを使ってtfliteモデルを最終評価します。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~⑤独自画像学習 アノテーションデータ変更~

前回はじゃんけんの手をアノテーションしました。
今回はそれを「Tensorflow model maker」というTensorflowが作成したツールに読み込める様、変更していきます。

コードはgoogle colaboratoryで共有していますので、適宜変更して頂けると使用できます。
コードの解説を簡単に行っていきます。

1. 下準備

#必要なライブラリをインポートする
import pandas as pd
import numpy as np
import cv2

pandasはアノテーションcsvを確認、編集するため
numpyはアノテーションcsvの数値を変更・計算するため
cv2(opencv)は画像を表示、確認するため
に使用します。

# MIN_DIR,CSVのパスは適宜変更してください
MAIN_DIR = "/content/drive/MyDrive/ML/Tensorflow/dataset_janken/"
CSV = MAIN_DIR + "janken_dataset-export.csv"

アノテーションcsvの格納されているディレクトリを「MAIN_DIR」に指定
csvのパスを「CSV」で指定

# pandasでcsvを確認
df = pd.read_csv(CSV)
df


	image	xmin	ymin	xmax	ymax	label
0	choki_01.jpg	68.710074	15.982533	236.703522	221.397380	Scissors
1	IMG_0728.JPG	62.420147	35.371179	245.090090	195.458515	rock
2	IMG_0729.JPG	65.565111	21.222707	256.097461	193.362445	rock
3	IMG_0731.JPG	73.951679	24.104803	217.047502	205.938865	rock
4	IMG_0730.JPG	84.434889	26.724891	239.848485	211.441048	rock
...	...	...	...	...	...	...
162	IMG_0890.JPG	102.780508	51.615721	237.489762	192.576419	rock
163	IMG_0892.JPG	48.267813	26.200873	208.136773	189.694323	rock
164	IMG_0891.JPG	91.773137	41.659389	235.917281	195.458515	rock
165	IMG_0893.JPG	89.152334	27.510917	248.759214	200.174672	rock
166	IMG_0894.JPG	47.481572	24.890830	213.116298	195.982533	rock

pandasの説明はここでは省きます。csvの中身が確認できます。

2. csvファイルの変更

2-1. 画像名を画像パスに変更する

# imageの値をパスに変更する
for idx, col in enumerate(df.image):
    df.image[idx] = MAIN_DIR + col

df.head()


image	xmin	ymin	xmax	ymax	label
0	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	68.710074	15.982533	236.703522	221.397380	Scissors
1	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	62.420147	35.371179	245.090090	195.458515	rock
2	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	65.565111	21.222707	256.097461	193.362445	rock
3	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	73.951679	24.104803	217.047502	205.938865	rock
4	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	84.434889	26.724891	239.848485	211.441048	rock

2-2. xmin/ymin/xmax/ymaxの値を正規化する

img = cv2.imread(df.image[0])
y, x, _ = img.shape
for idx, col in enumerate(df.xmin):
    df.xmin[idx] = col / x
for idx, col in enumerate(df.ymin):
    df.ymin[idx] = col / y
for idx, col in enumerate(df.xmax):
    df.xmax[idx] = col / x
for idx, col in enumerate(df.ymax):
    df.ymax[idx] = col / y
df.head()


image	xmin	ymin	xmax	ymax	label
0	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	0.214719	0.066594	0.739699	0.922489	Scissors
1	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	0.195063	0.147380	0.765907	0.814410	rock
2	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	0.204891	0.088428	0.800305	0.805677	rock
3	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	0.231099	0.100437	0.678273	0.858079	rock
4	/content/drive/MyDrive/ML/Tensorflow/dataset_j...	0.263859	0.111354	0.749527	0.881004	rock

今回は、すべての画像が同じ大きさなので、1枚の画像を参照しています。
1枚の画像の縦・横のpx数を取得し、xmin/xmaxをxで、ymin/ymaxをyで割ることで、0.0-1.0の間の数値に正規化します。

2-3. 新たな列を追加して、列を並べ替える

df["type"] = ""
df["dummy_1"] = ""
df["dummy_2"] = ""
df["dummy_3"] = ""
df["dummy_4"] = ""
df = df.reindex(columns=["type","image","label","xmin","ymin","dummy_1","dummy_2","xmax","ymax","dummy_3","dummy_4"])
df.head()


	type	image	label	xmin	ymin	dummy_1	dummy_2	xmax	ymax	dummy_3	dummy_4
0		/content/drive/MyDrive/ML/Tensorflow/dataset_j...	Scissors	0.214719	0.066594			0.739699	0.922489		
1		/content/drive/MyDrive/ML/Tensorflow/dataset_j...	rock	0.195063	0.147380			0.765907	0.814410		
2		/content/drive/MyDrive/ML/Tensorflow/dataset_j...	rock	0.204891	0.088428			0.800305	0.805677		
3		/content/drive/MyDrive/ML/Tensorflow/dataset_j...	rock	0.231099	0.100437			0.678273	0.858079		
4		/content/drive/MyDrive/ML/Tensorflow/dataset_j...	rock	0.263859	0.111354			0.749527	0.881004		

tensorflow model makerの物体検出ツールではcsvの読み込み形式が決まっており、ダミーの列を追加し、既定の場所に数値が入っていなければうまく動作してくれません。

2-4. 列typeにtrain/validation/testを割り振る

tmp = df[df.label == "rock"].index.tolist()
train_index = tmp[0:int(len(tmp)*0.8)]
validation_index = tmp[int(len(tmp)*0.8):int(len(tmp)*0.9)]
test_index = tmp[int(len(tmp)*0.9):len(tmp)]

for idx in train_index:
    df["type"][idx] = "TRAIN"
for idx in validation_index:
    df["type"][idx] = "VALIDATION"
for idx in test_index:
    df["type"][idx] = "TEST"
tmp = df[df.label == "Scissors"].index.tolist()
train_index = tmp[0:int(len(tmp)*0.8)]
validation_index = tmp[int(len(tmp)*0.8):int(len(tmp)*0.9)]
test_index = tmp[int(len(tmp)*0.9):len(tmp)]

for idx in train_index:
    df["type"][idx] = "TRAIN"
for idx in validation_index:
    df["type"][idx] = "VALIDATION"
for idx in test_index:
    df["type"][idx] = "TEST"
tmp = df[df.label == "paper"].index.tolist()
train_index = tmp[0:int(len(tmp)*0.8)]
validation_index = tmp[int(len(tmp)*0.8):int(len(tmp)*0.9)]
test_index = tmp[int(len(tmp)*0.9):]

for idx in train_index:
    df["type"][idx] = "TRAIN"
for idx in validation_index:
    df["type"][idx] = "VALIDATION"
for idx in test_index:
    df["type"][idx] = "TEST"

次に、type列にtrain/validation/testという割り振りをします。
機械学習では、データを分割して、「学習用/検証用/試験用」として学習の時に、学習用画像を学習してモデルを作り、検証用画像でその正確性を評価します。
最終的に試験用画像で、最終的な学習モデルを評価します。

2-5. 保存

df.to_csv(MAIN_DIR + "dataset.csv", index=False)

以上までで行った処理したデータをcsvとして保存して終了です。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~④独自画像学習 アノテーション~

0.初めに

Raspberry Pi4 リモートで初期設定 Raspberry Pi OS/OS Lite」、「Raspberry Pi4でTensorflow Lite 環境を構築してみる」、「Raspberry Pi 4で物体検出してみる」の3記事にわたって、Raspberry Pi4のセットアップとtensorflow・tensorflow Liteの動作環境を準備し、動作の確認を行ってきました。

ただし、使用した学習モデルは一般で気に出回っているモノを検出するモデルで、「自分が検出したいモノ」を検出できるようになっているわけではありません。
「自分が検出したいモノ」の画像、もしくは動画から検出したいモノを四角で囲う作業(アノテーション)を行ってまいりますので、画像を用意してください。

今回は、karaage0703さんのjanken_datasetを用いて検出してみます。

1.datasetをダウンロード

上記のデータセットを自分のPCにダウンロードします。
code部分からDownload ZIPでダウンロードし、解凍します。

2.Vottのインストール

アノテーション作業を行うためのアプリは様々ありますが、ここでは「Vott」というアプリを使用していきます。
まず、こちらからVottをインストールします。
github.com

3.アノテーション作業

インストールが完了し、アプリを起動するとこのようになります。

まず、新規プロジェクトを作成します。

次に、表示名、ソース接続、ターゲット接続を記入していきます。
表示名はお好みでつけてください。ここではtflite_testとしました。


ソース接続、ターゲット接続の設定はそれぞれ右側にある「Add Connection」から設定します。
「Add Connection」を押すと次のような画面になります。


プロバイダーというところをクリックするとどこから画像を引っ張ってくるかを選択することができます。
「Azure Blob strage」や「bing 画像検索」などがありますが、今回は「ローカルファイルシステム」でPCに入っている画像を使用するので、その画像が入っているフォルダを指定します。

そして、「ソース接続」「ターゲット接続」のプルダウンから、今作成したパスを選択すれば完了なので、プロジェクトを保存をおします。

するとフォルダー内にある画像すべてが表示されます。
まず、「手」をタグ付けするために、右上「TAG」の横にあるプラスマークをおしてタグの名前を必要なだけ用意します。
その後、上部にある四角を押すことで、囲うことができます。
それぞれ、検出する「手」に対応したタグをつけることで、アノテーションができます。


4.アノテーションしたデータのエクスポート

この後行うモデルの学習で必要なデータ形式に変更する必要があります。
今回は、model makerで行うため、excelで出力するように設定をします。
また、「アセットの状態」は必ずタグ付きアセットのみにしてください。
エクスポート設定が終了したら、赤枠部分のエクスポートを実行すると出力されます。


今回は以上で終わります。
お疲れさまでした。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~③物体検出 動作確認~

初めに
使用するのは、「Raspberry Pi4でTensorflow Lite 環境を構築してみる」<-「Raspberry Pi4 リモートで初期設定 Raspberry Pi OS/OS Lite」で設定したRaspberry Pi4を使用します。

melostark.hatenablog.com
melostark.hatenablog.com

「Raspberry Pi4でTensorflow Lite環境を構築してみる」で環境構築はできたので、Tensorflow公式のexampleで動作確認をしてみます。

1. Tensorflow 公式ページを見てみる

Tensroflow Liteサンプル | 機械学習モバイルアプリ」というページを見てみると、

いろいろあって面白そうですが、とりあえずオブジェクト検出をやってみましょ。
オリンピックのピクトグラムで話題になった「Tokyo2020-Pictogram-using-MediaPipe」はおそらく「姿勢推定」を使用したアプリのようですね!

アイディアとプロトタイプ実装までのスピードが速くて、陰ながら尊敬しておりますし、ほかにも面白いアプリを作成されているので、ご覧になってみてください。

はなしが脱線してしまいましたが、オブジェクト検出に戻りましょう。
先ほどのページの「オブジェクト検出」の「Raspberry Piで試してみる」からgithubに移行するので、READMEの通りに実行していきます。
github.com

2. githubからリポジトリをクローンして動かしてみる

まずは、READMEの通りに進めていきます。

2-1. Set up your hardware

こちらは、以前の記事の方で行っているので、特に何もしなくても問題ありません。

2-2. Download the example files

ここも、以前の記事で行った設定をもとに行っていきます。
設定を行っていない場合、READMEの通りに行えばテストできると思いますが、こちらでは検証しておりません。

pi@raspberrypi:~ $ cd workspace/tflite
pi@raspberrypi:~/workspace/tflite $ source venv-tflite-v1/bin/activate
(venv-tflite-v1) pi@raspberrypi:~/workspace/tflite $
(venv-tflite-v1) pi@raspberrypi:~/workspace/tflite $ git clone https://github.com/tensorflow/examples --depth 1
(venv-tflite-v1) pi@raspberrypi:~/workspace/tflite $ cd examples/lite/examples/object_detection/raspberry_pi

2-3. Run the example

あとは、事前に用意されているプログラムを実行するだけでPicameraで見ている映像のなかでオブジェクト検出してくれます。

(venv-tflite-v1) pi@raspberrypi:~/workspace/tflite $ python3 detect.py \
  --model efficientdet_lite0.tflite

なんだか検出してくれていそうですね!
カップは全身が写っていますが、人やキーボードは半分程度しか映っていないにもかかわらず、検出してくれいています。

これでRaspbrry Piで物体検出ができることを確認することができました。
では、つぎはなんだかわからない学習済みのモデルではなく、自分で分類したいものを学習したモデルを作成してみることにします!

今回はここで終了します。
お疲れさまでした。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~②Tensorflow Lite 環境構築~

2022/6/4 更新
2021/10/18 更新

初めに

使用するのは「Raspberry Pi4 リモートで初期設定 Raspberry Pi OS/OS Lite」で構築したデスクトップ環境のラズパイ4で行います。
melostark.hatenablog.com

1. Tensorflow Liteの環境準備 -作業用フォルダの作成-

これからこのラズパイで様々な実験を行っていくことを考慮して、作業用フォルダと仮想環境を準備します。

仮想環境を作る理由としては、pythonのパッケージバージョンの違いで様々なエラーが出ることがあり、
独立した環境の方がそういったエラーが出なくて済むためです。

pi@raspberrypi:~ $ mkdir workspace
pi@raspberrypi:~ $ cd workspace
pi@raspberrypi:~/workspace $ mkdir tflite
pi@raspberrypi:~/workspace $ cd tflite
pi@raspberrypi:~/workspace/tflite $ 

これからプログラムを書くなどの作業するのは基本「~/workspace」というディレクトリで行い、
Tensorflow Liteを動かすのは「~/workspace/tflite」で行います。

では、pythonの仮想環境を作ります。

pi@raspberrypi:~/workspace/tflite $ python3 -V
Python 3.7.3
pi@raspberrypi:~/workspace/tflite $ python3 -m venv venv-tflite-v1
pi@raspberrypi:~/workspace/tflite $ source venv-tflite-v1/bin/activate
(venv-tflite-v1) pi@raspberrypi:~/workspace/tflite $ 

python 3.3から導入されたvenvで仮想環境を作りました。
pythonに標準で入っているパッケージのため、python事態のバージョン管理はできません。

2. Tensorflowをインストールする

PINTO0309さんという方が用意してくださっているTensorflow-binというリポジトリのお力をお借りしてインストールしたいと思います。
github.com

基本、上記READMEの通りに進めれば何も問題がありません。
この後行う物体検出のモデル作成に使用するTensorflowのバージョンと合わせておくのが良いでしょう。
また別途更新する予定ですが、tflite形式の物体検出モデルを作成するのであれば、「TFlite Model Maker」が最も直接的で煩わしくないと思います。
www.tensorflow.org

※2022/6/4 テスト段階 Tensorflow == 2.8.0
※2021/10/18テスト段階 Tensorflow==2.5.0

では、Tensorflow 2.8.0をTensorflow-binリポジトリからインストールします。
必要に応じて「previous_versions」から

sudo apt-get install -y libhdf5-dev libc-ares-dev libeigen3-dev gcc gfortran \
                          libgfortran5 libatlas3-base libatlas-base-dev \
                          libopenblas-dev libopenblas-base libblas-dev \
                          liblapack-dev cython3 libatlas-base-dev openmpi-bin \
                          libopenmpi-dev python3-dev python-is-python3
sudo pip3 install pip --upgrade
sudo pip3 install keras_applications==1.0.8 --no-deps
sudo pip3 install keras_preprocessing==1.1.2 --no-deps
sudo pip3 install numpy==1.22.1
sudo pip3 install h5py==3.6.0
sudo pip3 install pybind11==2.9.2
pip3 install -U --user six wheel mock

./previous_version/download_tensorflow-2.8.0-cp39-none-linux_aarch64_numpy1221.sh
sudo -H pip3 install tensorflow-2.8.0-cp39-none-linux_aarch64.whl

念のためpython3でインポートできるか確認

$ python3
>>> import tensorflow as tf
>>> print(tf.__version__)
2.8.0
>>>exit()
$ 
$ cd ../
$ rm -rf Tensorflow-bin
$

以上で、Tensorflow==2.8.0のインストールは完了です。

3. Tensorflow Liteを使うためのライブラリインストール

colabで用いたものをそのまま使用したらうまくいきました。

pip3 install tflite-support

念のため、python3でインポートできるかを確認

$ python3
>>> from tflite_runtime.interpreter import Interpreter
>>>

エラーが出なければ完了です。
これで、TensorflowLiteの環境設定は完了しました。

あと、画像解析ライブラリでよく使われる「Pillow」と「OpenCV」をインストールしておきます。

$ pip3 install Pillow==5.4.1
$ pip3 install opencv-python

以上で、必要なものはそろいました。
お疲れさまでした。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Raspberry Pi4 画像認識 ~①リモートで初期設定 Raspberry Pi OS/OS Lite~

0. 初めに

Raspberry Pi(以下ラズパイ)で物体検出をテストするためにセットアップを行っていきます。
物体検出のテストを行うなら基本は「Raspberry Pi OS」で動作させると思いますが、「Raspberry Pi OS Lite」でプログラムを動かしてリモート接続したPCから遠隔で確認するなどの使い方もあります。

両方のOSに対応できる様にリモート接続して行う初期設定を備忘録として記録しておきます。

1. Raspberry pi4のセットアップ - ラズパイ一式とOSの準備 -

1-1. ラズパイ4とPi cameraの購入

何はともあれ、まずはラズパイとカメラを用意します。
前提として、OSを書き込む等に使用するデスクトップPC/ノートPC を持っているとして話を進めます。
今回はwindowsでセットアップを行います。


まずラズパイ4本体、自分は下記を購入しました。

ラズパイ4は性能が大きく向上したため、普段使いなどでもヒートシンクなどを付けた方がいいようです。
無論、CPUで機械学習モデルを動かすなんてことをするならなおさら必要です。
microSDカードやスイッチ付きの電源コードなどがすべてまとまっているキットを購入するのが一番楽でお金もかからないように思います。

次にラズパイに接続するカメラです。

Pi cameraだけでなく、USBカメラで利用することができますが、ここでは扱いません。

以上を購入すればとりあえず必要なものはそろいました。

組み立てたラズパイとPi camera

1-2. OSのインストール

ラズパイを動かすためのOSをmicroSDカードに入れていきます。
ご自分のPCとSDカードリーダー、上で購入したセットに同封されているmicroSDカードとSDカードリーダーを用意してください。


1. まず、「Raspberry Pi Imager」をご自分のPCにインストールします。
www.raspberrypi.com


2. ダウンロードしたimagerを起動すると下記の様な画像が表示されます。
「CHOOSE OS」をクリックします。


3. まずmicroSDカードをフォーマットするために、「ERASE」を選択します。


4. 「CHOOSE STORAGE」からカードリーダーで読み込んだSDカードを選択します。


5. 「WRITE」をクリックすれば、SDカードがフォーマットされます。


6. 今度は、「CHOOSE OS」から、OSを選択します。今回は「Raspberry Pi OS(32-bit)」を入れます。


7. 再度「WRITE」をクリックすればSDカードにOSイメージが書き込まれます。


ここから、入れたOS毎に若干設定が異なるので「Raspbery Pi OS」と「Raspberry Pi OS Lite」で設定の方法が異なるので、共通の設定方法を書いていきます。

2. ラズパイのリモート設定 - 共通設定方法 -

Desktop OSであれば、モニターなどをつないでGUIで設定ができますが、デスクトップ環境でないOS Liteの場合、リモートで設定しなければなりません。
Desktop OSの場合でもLite OSの場合でもCUI環境から設定を行うことができるので、共通してCUIで設定を行います。

ここからSDカードにリモートでセットアップするための設定を2つ行っていきます。

2-1. sshファイル作成

まず、「Raspberry Pi Imager」で書き込んだ後、SDカードが認識されていないので、SDカードをさしなおします。

エクスプローラーからSDカードの「boot」に「ssh」というファイルを作成します。
bootフォルダ上で右クリックで 新規作成->テキスト ドキュメント を選び、「ssh」と記入して「.txt」部分を削除すれば完了です。

2-2. Wifi接続するための設定ファイル作成

2-1. sshファイル作成と同様に bootフォルダ上で右クリックで 新規作成->テキスト ドキュメント を選び、「wpa_supplicant.conf」と記入して「.txt」部分を削除します。

今度は、「wpa_supplicant.conf」をメモ帳などのエディタで開いて下記内容を書き込みます。

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=JP

network={
    ssid="<SSID名>"       # 接続したいwifiの名称
    psk="<パスワード>"     # 上で選択したwifiのパスワード
}

2-3. microSDカードをラズパイに挿入して起動する

以上で事前の設定が終了です。このmicroSDカードをラズパイにセットし電源を入れればラズパイが起動します。
緑色のLEDと赤色のLEDが光ると思いますが、緑が消えて赤だけついている状態が起動完了の合図になります。

3. ラズパイにssh接続

2で行った設定でラズパイはWifiに接続されているはずなので、Teratermを使ってラズパイにssh接続します。
teratermをインストールしましょう。
forest.watch.impress.co.jp

まず、windowsPCからコマンドプロンプトを使ってラズパイがWifiに接続されているかを確認してみます。

ping -4 raspberrypi.local

これで応答が返ってこない場合、ラズパイがWifiに接続できていないことが考えられます。
WifiSSIDやパスワードが間違っているのが一番考えられるため、もう一度SDカードを設定しなおしてください。

Teratermを起動してラズパイに接続してみます
ホスト(T)に「raspberrypi.local」と入力してOKを押します。

セキュリティ警告が出てきますがそのまま「続行」を押して大丈夫です。

ユーザー名は「pi」
パスフレーズは「raspberry」でOKを押します。

するとこのような画面に移ります。

これで、接続が完了しました。

4. ラズパイの各種設定

4-1. ログインパスワードの変更(任意)

一応パスワードを変更しておくと安心です。

passwd

4-2. Wifiの接続パス暗号化(任意)

やっておいた方が安心です。

sudo sh -c 'wpa_passphrase SSID PASSPHRASE >> /etc/wpa_supplicant/wpa_supplicant.conf'

上記を行った後、/etc/wpa_supplicant/wpa_supplicant.conf には新たにWifi設定が書かれるので、1-3で記入したWifi設定とコメントアウトされているpsk部分を削除します。

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

4-3. IPアドレスの固定

ラズパイが接続するWifiIPアドレスを固定します。
この後VNC接続でラズパイのデスクトップ画面をPCから操作するためにも必要がありますので行います。

sudo nano /etc/dhcpcd.conf

これで出てきたファイル内の一番下に下記を追加します。

# *の部分はWifiのIPアドレス設定状況によって異なりますので適宜変更してください。

interface wlan0
static ip_address=192.168.*.**/24
static routers=192.168.*.*
static domain_name_servers=192.168.*.*

4-4. Localisation変更

sudo raspi-config

上記を実行すると下記の様な画面が出てきます。

1. [5 Localisation Options] -> [L1 Locale]
「en_us.UTF-8」「ja_jp.UTF8」「ja_jp.EUC-JP」を追加して、default system localを「ja_jp.UTF8」に変更します。
2. [5 Localisation Options] -> [L2 Timezone]
「Asia」→「Tokyo」を選択します。
3. [3 Interface Options] -> [P1 Camera]
Pi Camera I/Fを使いますのでEnabelにして下さい。
4. [3 Interface Options] -> [P3 VNC]
Raspberry Pi OSの場合、モニター画面をリモートで接続しているPCから閲覧、操作できるようにします。

以上で、「Raspberry Pi OS」「Raspberry Pi OS Lite」両方で基本設定が終わりました。

5.windowsPCからラズパイにVNC接続する

基本的にCUI画面で操作を行っていきますが、ラズパイカメラの画像をラズパイ上で確認したいときなどに使用します。

Windows PC上の操作になります。
VNC接続するために「VNC Viewer」をダウンロード/インストールします。
VNC viewerを起動すると下記の様な画面が表示されるので、1-5-3で設定したIPアドレスを入力します。

「Username」欄、「Password」欄にそれぞれ「pi」、「1-5-1で変更したパスワード」を入力し、「OK」をクリックします。

そうすると「Raspberry Pi OS」のデスクトップ画面が操作できるようになります。

以上で、ラズパイのデスクトップ画面にVNC接続できるようになりました。


以上で、ラズパイの初期設定は終了です。
お疲れさまでした。

          • 関連記事-----

melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com
melostark.hatenablog.com

Pythonコーディング練習 : 4日目

Pythonコーディング練習 : 4日目
Practice Python Exercise 11 ~ 18
勉強時間 : 30分×10 = 5時間

www.practicepython.org

Practice Pythonの折り返し地点まで来ましたー。
これ初めはいいと思っていたんですが、答えがちょこちょこ間違っていることがありますね。
日本語版Practice Pythonはあるのかな?
問題と答えを日本語にすると多少需要がありそうなので気が向いたらやります。

ちなみに突然練習問題17でスクレイピングの問題が出てきたけどめんどくさいので飛ばしました。
Webサイトなんて毎回更新されてデータ構造も変わるから問題としてはいわゆる悪問になってしまいますよね。
やらせるなら自分で作成したサイトを使う必要がありますよね。

では折り返し、残り半分頑張ります。

Pythonコーディング練習 : 3日目

Pythonコーディング練習 : 3日目
Practice Python Exercise 9 ~ 10
勉強時間 : 30分×3 = 1.5時間

melostark.hatenablog.com

で参考にさせていただいた

qiita.com

何ですが、いまいちコードテストがこのPython Practiceで上手に使えずにいます。。。
ユニットコードテストの有用性はなんとなく理解していますが、任意の値(ランダムな値)特に、数値を入力するような問題であれば使用できるが、言語の場合テスト方法がわからず、現在ユニットコードテストは使用していません。

問題で解いた関数内で乱数生成して、プログラム内でテストしてしまっています。
ただし、乱数のためにその乱数を表示して自分で確認しない限り、正解不正解がわからないのでやっぱりコードテストした方が圧倒的にいいですよね。。。
Practice Pythonが一通り終わったらコードテストを徐々に取り入れていこうと思います。
jsonファイルとかどういうものかちゃんと理解してないので、自分で使ってみるとためになりますしね。