4d Systems uCam-IIをpythonで動かす


このエントリーをはてなブックマークに追加

最初Arduinoでやっていたが

4D Systems uCam-IIをArduinoでまずはSYNCさせる | ぬわーーーーーーー!!!

Pythonで動かしてるサンプルをgithubで見つけた

nichhk/ucam-pyserial

ただし、python2系だったのでpython3系で動くように書き換えてみた

コードはgithubに置いた


自分はMacOS Sierraで、python3.6.0 で動かした


動かす時は

コードをダウンロードしてきて、ucam.py内の19行目あたり、シリアルデバイス名を自分の環境のものに書き換えて

ディレクトリ内で $ python main.py をして、うまく動けば test.jpg ファイルが生成する

あとはpython3で動かすためにいろいろ変更した箇所があるのでメモがてら記載していく


byteの扱いが2と3で色々と違うので注意

Python 2.7.x と 3.x の決定的な違いを例とともに | プログラミング | POSTD

がひとまず参考になる


が、いろいろとつまづいたのでメモがてら記載していく


string.decode(‘hex’)が動かない

python3だと動かなかったので、 from binascii import hexlify, unhexlify しておいて

string.decode('hex') ではなく unhexlify(string) にしたら動いた

具体的には、def _get_picture(self) のところで

img_size = unpack('<I', hexlify(data[-3:]).decode('hex') + '\x00')[0] から

img_size = unpack('<I', hexlify(data[-3:]).decode() + '\x00')[0]

に変更した

これを動かすと

1
TypeError: a bytes-like object is required, not 'str'

が発生した

そもそも hexlify(data[-3:]).decode() じゃなくてただの data[-3:] でいいのでは?

ということでやってみると新しいエラーが発生

1
TypeError: can't concat bytearray to str

bytearrayとstringは一緒にまとめられないとな

結局下記のようにした(‘00’じゃなくて’\x00’の誤植もあった・・・)

1
img_size = unpack('<I',(unhexlify(hexlify(data[-3:])).decode() + '\x00').encode())[0]


ひとまず先に進めたが、さらにエラーが出た

1
TypeError: 'float' object cannot be interpreted as an integer

packagesのサイズがfloatで小数点になってるので整数にしてやればいいのかな

  • というわけで import math して num_pkgs = math.floor(img_size / (512 - 6)) としてやった
  • _get_picture 関数と _write_picture 関数 の二箇所にあるので注意


先に進めたが

さらにエラーが出た

1
TypeError: sequence item 3: expected str instance, bytes found

stringが予想されるがbytesが渡されたよってでた

どうやら _write_picture 関数のところっぽい

たしかに、hex_idx = hexlify(pack('H', i)) で bytes が返ってくるので

hex_idx = hexlify(pack('H', i)).decode() でやってみた

これで一応動いた!


が、たまにまだエラーがでる

1
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte

どうも96行目あたりの img_size = unpack('<I',(unhexlify(hexlify(data[-3:])).decode() + '\x00').encode())[0]のところ

うまく動く時と動かない時があって、出て来るデータによってはうまくdecode出来ていないのが問題っぽい

python2のコードだと hex 型でdecodeされるようになっていたので無理やり合わせてやってみる

codecs をimportしておいて、codecs.decode(hogehoge, 'hex') みたいにしてやることで対応した

1
2
3
4
5
6
import codecs
...
img_size = unpack('<I', (codecs.decode(codecs.encode(unhexlify(hexlify(data[-3:])), 'hex'), 'hex') + b'\x00'))[0]

一応動くようにはなったが、やたら汚いコードなのでなんとかしないと…


追記

もしかしたら下記でよかったのかも

1
2
# img_size = unpack('<I', (codecs.decode(codecs.encode(unhexlify(hexlify(data[-3:])), 'hex'), 'hex') + b'\x00'))[0]
img_size = unpack('<I', (unhexlify(hexlify(data[-3:])) + b'\x00'))[0]

それどころか下記で良さそう…

1
unpack('<I', (data[-3:] + b'\x00'))[0]

バイト列の扱い難しい


このエントリーをはてなブックマークに追加