image_transfer_raw_as_the_controller_device.py
# この作品はMITライセンスの下で提供されています。
# Copyright (c) 2013-2023 OpenMV LLC. 全著作権所有。
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# 画像転送 - コントローラーデバイスとして
#
# このスクリプトは、"image_transfer_raw_as_the_remote_device.py"を実行している別のOpenMV Camとペアで使用するよう作られています
#
# このスクリプトは、あるOpenMV Camから別のOpenMV Camへフレームバッファを転送する方法を示します。
import image
import omv
import rpc
import csi
import struct
import time
# 上記のRPCライブラリはOpenMV Camにインストールされており、以下のための複数のクラスを提供します
# OpenMV CamをCAN、I2C、SPI、UART、またはLAN/WLAN経由で制御できるようにします。
##############################################################
# OpenMV Camを制御するために使用するインターフェースを選択してください。
##############################################################
# 以下の行のコメントを外すと、OpenMV CamをCAN経由で制御するように設定できます。
#
# * message_id - CANバス上でのデータ転送に使用するCANメッセージ(11ビット)。
# * bit_rate - CANビットレート。
# * sample_point - Tseg1/Tseg2比。通常は75%。(50.0、62.5、75.0、87.5など)
#
# 注: マスターとスレーブのメッセージIDおよびCANビットレートは一致させる必要があります。マスターのCAN Highをスレーブの
# CAN Highに、マスターのCAN Lowをスレーブのcan loに接続してください。CANバスは120オームで終端する必要があります。
#
# interface = rpc.rpc_can_master(message_id=0x7FF, bit_rate=1000000, sample_point=75.0)
# 以下の行のコメントを外すと、OpenMV CamをI2C経由で制御するように設定できます。
#
# * slave_addr - I2Cアドレス。
# * rate - I2Cバスクロック周波数。
#
# 注: マスターとスレーブのアドレスは一致させる必要があります。マスターのsclをスレーブのsclに、マスターのsdaを
# スレーブのsdaに接続してください。外部プルアップ抵抗を使用する必要があります。最後に、両方のデバイスはグラウンドを共有する必要があります。
#
# interface = rpc.rpc_i2c_master(slave_addr=0x12, rate=1000000)
# 以下の行のコメントを外すと、OpenMV CamをSPI経由で制御するように設定できます。
#
# * cs_pin - スレーブセレクトピン。
# * freq - SPIバスクロック周波数
# * clk_polarity - アイドル時のクロックレベル(0または1)。
# * clk_phase - クロックの最初のエッジ(0)または2番目のエッジ(1)でデータをサンプリングします。
#
# 注: マスターとスレーブの設定は一致させる必要があります。CS、SCLK、MOSI、MISOをCS、SCLK、MOSI、MISOに接続してください。
# 最後に、両方のデバイスは共通のグラウンドを共有する必要があります。
#
interface = rpc.rpc_spi_master(cs_pin="P3", freq=20000000, clk_polarity=1, clk_phase=0)
# 以下の行のコメントを外すと、OpenMV CamをUART経由で制御するように設定できます。
#
# * baudrate - シリアルボーレート。
#
# 注: マスターとスレーブのボーレートは一致させる必要があります。マスターのtxをスレーブのrxに、マスターのrxを
# スレーブのtxに接続してください。最後に、両方のデバイスは共通のグラウンドを共有する必要があります。
#
# interface = rpc.rpc_uart_master(baudrate=7500000)
##############################################################
# コールバックハンドラ
##############################################################
def get_frame_buffer_call_back(pixformat, framesize, cutthrough, silent):
if not silent:
print("Getting Remote Frame...")
result = interface.call(
"raw_image_snapshot", struct.pack("<II", pixformat, framesize)
)
if result is not None:
w, h, pixformat, size = struct.unpack("<IIII", result)
img = image.Image(w, h, pixformat, copy_to_fb=True) # クリア済みのフレームバッファを確保します。
img_ba = img.bytearray()
if cutthrough:
# エラーチェックなしの高速カットスルーデータ転送。
# カットスルーデータ転送を開始する前に、マスターと
# スレーブの両方のデバイスを同期させる必要があります。戻ってきた時点で両デバイスは同期しています。
result = interface.call("raw_image_read")
if result is not None:
# GET BYTESは、遅延をほとんど置かずに直後に即座に実行される必要があります。
# 1回の非常に大きな転送で画像データをすべて読み取ります。
interface.get_bytes(img_ba, 5000) # タイムアウト
else:
# エラーチェック付きの低速なデータ転送。
# 32/8KB単位のチャンクで転送します。
chunk_size = (1 << 15) if omv.board_type() == "H7" else (1 << 13)
if not silent:
print("Reading %d bytes..." % size)
for i in range(0, size, chunk_size):
ok = False
for j in range(3): # 最大3回まで試行します。
result = interface.call(
"raw_image_read", struct.pack("<II", i, chunk_size)
)
if result is not None:
img_ba[i:i + chunk_size] = result # 画像データを書き込みます。
if not silent:
print("%.2f%%" % ((i * 100) / size))
ok = True
break
if not silent:
print("Retrying... %d/2" % (j + 1))
if not ok:
if not silent:
print("Error!")
return None
return img
else:
if not silent:
print("Failed to get Remote Frame!")
return None
clock = time.clock()
while True:
clock.tick()
# リモートデバイスから転送される画像のpixformatとframesizeは、
# 以下の引数を変更することで変更できます。
#
# cutthroughがFalseの場合、画像はRPCライブラリを通じてCRCと
# 再送保護付きですべてのデータが転送されます。より高速なデータ転送を行うには、cutthroughをTrueに設定し、
# RPC呼び出しの完了後にget_bytes()とput_bytes()を呼び出してデータを転送するようにします。
# これにより、ある画像バッファから別の画像バッファへより高速に転送されます。注: これが機能するのは、RPC呼び出しが
# 正常に完了すると、マスターとスレーブの両方のデバイスが完全に同期されるためです。
#
img = get_frame_buffer_call_back(
csi.RGB565, csi.QQVGA, cutthrough=True, silent=True
)
if img is not None:
pass # ここで画像を処理できます。
print(clock.fps())