2017年2月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28        

Amazonウィジェット

  • miniPC
  • 最近買った本
  • Raspberry Pi
  • クアッドコプター
  • 書籍ランキング

AdSense

  • 広告
無料ブログはココログ

Python

2016年11月20日 (日)

python小技 map関数の小技

map関数を使うと、リストの各要素に対して同じ操作を行うことができます。
もっともよく使いそうなのは、CSVから数字を読んでその内容を処理したいとき。
for文で一個ずつint関数に突っ込んでもいいのですけど、内包表記とかmap関数を使うと下記のようにコンパクトに書けます。

たとえばファイルからCSVを一行読み込んだ、こんなリストaがあるとする。
a = ['12','13','14','15','16']

数値の左右にシングルクォーテーションがあるのは、ファイルから数字を読み取ったままだと文字列があるから。それをintに直したいとしたら、直した結果をnに入れていくようにして

n = [ ]
for t in a:
  n.append(int(t))
というようなことを書くこともできるが、map関数を使えば

map(int, a)
とすることもできる。
これは、第一引数が処理関数の指定。第二引数がリストで、リストの要素一個ずつを処理関数に渡してリストの内容を更新していくということ。
C言語で言うところの関数へのポインタを使っているのに近い。

map関数に加えて、lambda式を使えたらこんなこともできる。

map(lambda x: chr(x), range(0x30,0x30+10))
これは、
0x30から10個分のintのリスト要素それぞれを、ASCII文字に変換する。

処理した結果はこうなる。
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

ASCIIで0x30は数字の0という文字になるので、1個目が0で9まで続いている。

lambda x
というのがラムダ式というもので、引数xをとるlambdaという名前の関数があると考えればうまくいく。HPからコピペするだけだったり、丸覚えしようとするとうまくいかなかった。

確かタプルのリストを作ってそれをsort関数でソートしようとしたときに覚えて、
それから手になじむようになった。使い道が無いのに覚えようとすると、これはなかなかに難しい。


2016年10月30日 (日)

Python lsコマンドからファイルのリストを受け取るやりかた

ファイルのリストを受け取ってpythonで処理しようとするときに、lsでファイルのリストを一旦ファイルに作ってから、それを読ます方法がありますが、ちょっと面倒なので直接やる方法を考えていました。

subprocessというのを使うと、外部のコマンドやプログラムを走らせることができる。

しかしlsからの結果を受け取ろうとして、
a = subprocess.call("ls -l")
とやってしまうと何も受け取れない。

これをやるくらいならpythonで用意されている、
import glob
files = glob.glob("*.JPG")

を使ったほうが速いし覚えやすい。
globのimportのやり方を間違うと少し嵌りそう。

次はパイプを使ってやる方法。


from subprocess import *

output = Popen( ["ls","-l"],stdout=PIPE)

while True:
    line = output.stdout.readline()
    if not line:
        break
    print line,

ちなみに、"ls -1"とすれば、ファイル名のリストが一行ずつで出力される。

インタラクティブシェルでいろいろ試せば見えてくる。

from subprocess import *
でとりあえずインポートしたら、

output = Popen(["ls","-l"],stdout=PIPE)
をつかって出力を受け取る。
ただし、ここまでだとstdoutとstderrが混ざったオブジェクトの状態なので、
stdoutだけを取り出すようにする。

output.stdout.read()
を使えば、すべての中身を読みだせる。
これを何かで受け取って、

a = output.stdout.read()
としたあと、
lines = a.split('\n')
とすれば、
簡単に行ごとの中身が手に入る。

ほかにも、aからそのままの状態で、
a.count(".py")
とすれば、この単語が何個あるか数えられたり、

len(lines)
とすれば何行出力されたかわかる。ただしls -lの一行目は、ファイル名ではない。




2016年5月18日 (水)

Raspberry PiにWebカメラをつないで遊ぶ Pythonを使ったお手軽プログラミング

Pythonを一通り使えるようになったので、まとまった作品を作ってみました。
RaspberryPiの特徴は、やっぱりGPIOの使えるLinuxだということで、ボタンを押すとWebカメラの画像を撮影するビデオカメラを作ってみることにしました。

openCVのパッケージをインストールします。これはlinux上であればapt-getがあるので簡単にできます。

$ sudo apt-get install libopencv-dev
$ sudo apt-get install python-opencv

カメラの画像を動画として保存するにはこんな風にします。

import cv2

class CameraWriter():
  def __init__(self,filename):
    self.camera = cv2.VideoCapture(0)
    self.fps = 10
    self.size = (640,480)
    self.codec = cv2.cv.CV_FOURCC('I','4','2','0')
    self.writer = cv2.VideoWriter(filename, self.codec, self.fps, self.size, True)
    
  def process(self):
    for i in range(50):
      f,img = self.camera.read()
      self.writer.write(img)
  
if __name__ == '__main__':
  cw = CameraWriter("tameshi.avi")
  cw.process()

codecのところで形式を色々指定できるのですが、raspberry pi では"I420"という指定で動きました。撮影した画像はaviファイルで保存されます。FPSはカメラによって違うようですが、手持ちのカメラ「UCAM-C0113FBBK」ではこの数値がしっくりくるようでした。30FPSとかいくらでも入れられるのですが、PCで再生したときむちゃくちゃ早送りになります。

あとはcameraからreadして、imageをwriterで書き出す。ここが肝心になっています。このループの途中にGPIOの状態を読ませて、ボタンが押下されていなかったらループを出る。つまり撮影を終了するようにすれば簡単そうです。

  def process(self):
    for i in range(50):
      f,img = self.camera.read()
      self.writer.write(img)

次に、raspberry piのGPIOをいじってみましょう。GPIOはboardモードとBCMモードが選べるのですが、BCMモードにすると、ここに書いてあるようなGPIO何番という表記に沿った形になります。モードとピン配置の関係を間違えると迷宮入りするので、GPIOを使うときは必ずBCMモードで使っています。

import RPi.GPIO as GPIO
import time

GPIO.setmode( GPIO.BCM )
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_UP)

while 1 :
	if GPIO.input(4):
		print 'Input was High'
	else:
		print 'Input was Low'

上の例では内部プルアップを使っています。GPIO.setupの中でpull_up_downというやつです。これをつかうことで、外部にプルアップ抵抗をチマチマつける必要が無くなり簡素化できます。忘れたくない技です。

ちなみにこのソースを実行すると、GPIO4につないだボタンを押したときだけInput was Lowというメッセージになります。こういう基本動作をちょこちょこ書いて分野別に残しておくと、あとあと役に立ちます。

ここまでこればピンと来たひとは、ソースを書いているかもしれませんね。スレッドを使ってもいいし、シリアルで特定のコマンドを受けたときに撮影を開始させたり、TCP、UDPを活用してネットワークでやってみたり、なにをトリガにするかを考えるだけでも応用が広がります。とりあえずGPIOでやったときの、ボタンを押したときにLEDが点いて、撮影開始⇒ボタンを離すと撮影終了。という処理を書いてみました。カメラ画像書き出しループのところでGPIOを呼んで、条件によって終了させるだけです。

import cv2
import RPi.GPIO as GPIO

class CameraWriter():
  def __init__(self,filename):
    self.SW = 4
    self.LED = 17
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(self.SW, GPIO.IN, pull_up_down = GPIO.PUD_UP)
    GPIO.setup(self.LED, GPIO.OUT)

    self.camera = cv2.VideoCapture(0)
    self.fps = 10
    self.size = (640,480)
    self.codec = cv2.cv.CV_FOURCC('I','4','2','0')
    self.writer = cv2.VideoWriter(filename, self.codec, self.fps, self.size, True)
    
  def process(self):
    GPIO.output(self.LED,GPIO.LOW)
    while not GPIO.input(self.SW):
      GPIO.output(self.LED,GPIO.HIGH)
      f,img = self.camera.read()
      self.writer.write(img)
  
if __name__ == '__main__':
  cw = CameraWriter("tameshi.avi")
  cw.process()

このソースを土台にして、色々ためしてみてください。このソースではボタンを一回押して離すと、プロセスが終了します。また撮影したければもういちどpythonで起動しないといけなくなっています。これを、プロセスを終了するコマンドを送るまで何回でも撮影できるようにするとか、出力ファイル名にタイムスタンプをつけたり、画像の中になにか情報を書き込んだり。openCVなんで、顔認識とか色々できますよ。

2016年1月29日 (金)

お手軽なPythonのはじめ方

ROS(Robot Operating System)ではC++とPythonの2種類を使ってプログラミングできるので、ためしにPythonを勉強してみることにした。

Ardroneでも一度操縦用のライブラリを使うためにさわったことがあった。しかし、そのころはあまり便利とも思わず、インデントでブロックを作るなんてなんて堅苦しいんだろうという感想しか持たなかった。

今はやりの機械学習はPythonで書かれていることが多いらしく、ためしに買った本も中々面白かったので、立て続けにPython本を買った。



ちょっと読んだだけで色々試したくなってしまい、Windows環境で手軽に始められて、パッケージが最初から全部入っているソフトを探していた。

環境を整えて、早速作ってみたのがこのGUIだった。
ツールというような立派なものではないが、スクロールバーやボタンに連動するラベルなど、C#ではちょっとしたサイズになるものが、Pythonなら50行程度で書ける。しかも全部入りのインストーラならパッケージを入れる必要は無い。

Ws000061

実践編

Windows環境ではじめるならば、WinPythonが便利だった。
インストーラを実行するだけで、Matlabのような記述ができるnumpiや科学技術計算用のscipiなどが入った状態で付いてくる。さらにUSBに入れて環境を持ち歩ける。という強みを持っている。GUIの開発環境でデバッグも行える。

ここから公式サイトへ


色々バージョンがあってよくわからないのだが、Python2.7というのがライブラリがあって普及しているらしかったのでとりあえずPython2.7の64bitを選んでおいた。

インストールが終わったらSpyder.exeを立ち上げる。
※のっそり立ち上がるので、気長に待つこと。

Ws000062

これが画面。
左のペインにソースを書き込み、上の緑の三角を押すと実行される。

色々いじっているうちに、おかしくなってこんなワーニングが出ることがある。

Warning: No IPython console is currently available to run hogehoge.py.
Please open a new one and try again.


そんなときは、右下のペインで右クリックし、新規コンソールを立ち上げると書いたソースの実行が可能になる。