multiprocessingで生成したプロセス同士でndarray配列を共有する必要があったのでメモ
ctypesの変数については以下の記事を参照
https://qiita.com/maiueo/items/b2093ba78cde988bb111
ライブラリの読み込み
import ctypes
import numpy as np
ndarray -> ctypes
n = np.zeros((3, 4)).astype(np.uint8) # ndarray型の3x4の配列を生成
n_h, n_w = n.shape # nのサイズを取得
c = n.ctypes.data_as(ctypes.POINTER((ctypes.c_uint8 * n_w) * n_h)).contents # ctypesの3x4の配列へと変換
np.uint8, ctypes.c_uint8の部分は配列に用いる型の指定
n
とc
はともに同じアドレスを参照しているので、片方を書き換えるともう片方にも書き換えが反映されます。
n.ctypes.data_as
はn
の配列の先頭ポインタを引数で指定したctypesのポインタにキャストしたものを返します。
ctypes -> ndarray
c = ((ctypes.c_uint8 * 4) * 3)() # ctypesの3x4の配列を生成
n = np.ctypeslib.as_array(c) # ndarray型の3x4の配列へと変換
ctypes.c_uint8の部分は配列に用いる型の指定
こちらも、c
とn
はともに同じアドレスを参照しているので、片方を書き換えるともう片方にも書き換えが反映されます。
サンプルプログラム
cv2で読み込んだ画像(ndarray型)をctypes型に変換し、それをまたndarray型に戻すプログラムです。
画像ファイルのパス
の箇所を適宜変更してください。
import ctypes
import numpy as np
import cv2
if __name__ == '__main__':
# 適当な画像からndarrayの生成
input_img = cv2.imread("画像ファイルのパス")
# uint8に変換
input_img = input_img.astype(np.uint8)
# input_imgのサイズ、チャンネル数を取得
img_h, img_w, img_ch = input_img.shape
# input_imgをctypesの配列に変換
input_img_c = input_img.ctypes.data_as(ctypes.POINTER(((ctypes.c_uint8 * img_ch) * img_w) * img_h)).contents
# ctypesの配列からndarrayを生成
output_img = np.ctypeslib.as_array(input_img_c)
# プレビュー
cv2.imshow("input", input_img)
cv2.imshow("output", output_img)
cv2.waitKey(0)
参考
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ctypes.html
https://docs.scipy.org/doc/numpy-1.15.1/reference/routines.ctypeslib.html
https://stackoverflow.com/questions/3195660/how-to-use-numpy-array-with-ctypes
https://stackoverflow.com/questions/4355524/getting-data-from-ctypes-array-into-numpy