Pythonはじめてひと月、標準ライブラリの充実ってやっぱりいいなとか

Python歴は今の時点でだいたい1ヶ月くらい。

本当は1年くらい前に、PythonでCSV読み込んでタイムスタンプのフォーマットを変えて、みたいな簡単なスクリプトを組んでたんだけど、それはもうそれっきりで、文法とかももうすっかり忘れて、1ヶ月前くらいから、また一からリファレンス読みながらのスクリプティングをしてきた。

これまでにやってきた言語といえばC、Java,C++。スクリプト言語だとweb系でPHP、Perlくらいなので、Pythonはコマンドラインから動かすことを考えたら始めてのスクリプト言語。

あんまり大きな声じゃ言えないけど、try-catchとかのエラー処理とか、よくわからないレベルの超ライトユーザなので、突っ込んだ話はできないけど、ここまでPythonに触れてきて「いいな、Python」と思ったことをちらほらと書いていく。だいたいがC++に比べて、って感じだけど…

見返してみると、「いいなPython」って言うより「いいなスクリプト言語」って感じ

コード量が少ない

同じ働きをするコードを書くと、C++と比べてPythonは30%くらいの行数になるんじゃないか、ってくらいのイメージ。

コード量が少ないと読むのにかかる時間がだいぶ違ってくる。プログラムを読む時って「この変数がここで使われてて…」とコード内を何度も往復して読んでるから、読むのにかかる時間はきっとコード量の2乗くらいで効いてくる。コード量が2倍なら理解に掛かる時間は4倍。根拠はないけど。

これなら標準ライブラリの実装とかも眺められるんじゃないかと思ってスレッド周りのライブラリをチラ見してみたけど案の定のカオスっぷり&英語コメント読めないで諦めた。

僕のスキルなんてまあ、こんなもの。

標準ライブラリの充実さ

CSV読むのも標準ライブラリで一発だし、スレッドも簡単に使えるし。Cとかだとboostである程度標準化されてる気がするけど、でもこういうプログラムで一般的に使われる要素がPythonだと「標準」として組み込まれていて、この辺が強いんじゃないかなと。

C++11だとboostがsdtに組み込まれてsdt::threadとかで使えるんだっけ

「標準」の安心感って初心者にはとても心強い。リファレンスも多そうだし、なによりPythonの仕様とか実装を決めてるコミュニティの人たちが煮詰めて煮詰めて作ったんでしょ、みたいな根拠は薄いけどとりあえずいい感じのパフォーマンスを発揮してくれるんだろう、みたいな安心感がある。

もっと書こうと思ったんだけど

もっと書こうと思ったけど書きづらい。Python、すごく使いやすいけど他の言語と比べて具体的にどうこう、とかは自分のレベルじゃあんまり具体的に思いつかない。

どういう要素が働いているか解らないけれど、なぜか作りたいものが作りたいときに「ぱっと」作れるようになってるんだな、ってことぐらいしか、今はまだ書けない。

よくわからないけど、Python、よくできてる気がする。

Advertisement

PythonでOpenCVのwaitKey()はメインスレッドじゃないと動かない?

マルチスレッドとOpenCVの勉強を同時進行でやろうと、PythonでOpenCVをマルチスレッドで動かそうとした時にちょっとハマったのでメモ。

初めのコード

やりたかったのは、描画するウィンドウ関係の処理は全部それ用のスレッドに投げてしまって、メインスレッドはスレッドを起動するだけ、みたいなこと。どうせスレッドたくさん立てる事態になったらこういうことしたくなるんだろうな、と。

import threading
import cv2

# 描画スレッド
class ImageProcessing(threading.Thread):

	def __init__(self):

		threading.Thread.__init__(self)

		self.windowname = "ImageProcessing"
		cv2.namedWindow(self.windowname)
		self.capture = cv2.VideoCapture(-1)

	def run(self):

		while True:
			ret, frame = self.capture.read()
			cv2.imshow(self.windowname, frame)

			if cv2.waitKey(10) == 27: # ESC
				break

# メインスレッド
if __name__ == "__main__":

	ip = ImageProcessing()
	ip.start()

	ip.join()

で、動きませんでした。初めの画像が映るだけで画像が更新されない静止画状態。ついでにwaitKey() も反応しない。ウィンドウが完全にフリーズしたような状態。

そして当のスレッドは走りっぱなしなのでターミナルを強制終了したり立ち上げたりが本当に面倒だった。

何が悪いのか

取得した frame を適当にターミナルに出力してみると値自体は更新されているようなので、問題はウィンドウの更新らへんにありそう。でもその辺りのことはあまり詳しくない。 試行錯誤の途中、スレッドを走らせる際の start() を run() に書き換えると画像も更新されてwaitKey()も反応するようになった。

if __name__ == "__main__":
    ip = ImageProcessing()
    ip.run()
    ip.join()

ただこれだと、スレッディングではなくメイン文の中で描画ループを回しているだけ。

で、検索してみた結果、C++だけど似たような報告があったので、どうやらwaitKey()はメインスレッドじゃないと動かないってことでいいのかな。不便だけど、もしそうなら他の人はどうしてるんだろう。

imshow() and waitkey() from within a thread –> not updating the display

結局処理をメインスレッドに

というわけで描画ウィンドウの生成と waitKey() はメインスレッドに移した。ついでに終了処理を渡したりするのが面倒なのでデーモンスレッドに

import threading
import cv2

class ImageProcessing(threading.Thread):

	# 描画ウィンドウ名を受け取るように
	def __init__(self, windowname):

		threading.Thread.__init__(self)

		# デーモンスレッドに
		threading.Thread.daemon = True

		self.windowname = windowname
		self.capture = cv2.VideoCapture(-1)

	def run(self):

		while True:
			ret, frame = self.capture.read()
			cv2.imshow(self.windowname, frame)

if __name__ == "__main__":

	# 描画ウィンドウ生成をメインスレッド内に
	windowname = "ImageProcessing"
	cv2.namedWindow(windowname)

	ip = ImageProcessing(windowname)
	ip.start()

	# waitKey() をメインスレッド内に
	while True:
		if cv2.waitKey(10) == 27: # ESC
			break

これで画像も更新されて waitKey() も動作するようになった。imshow() はメインスレッドじゃなくても動きそう。 でもこれだと、結局何がしたかったんだか…ってことに。メイン文が太るのはあんまり好きじゃない。何かいい方法はないものか。

  • Mac OS X 10.9
  • Python 2.7.4
  • OpenCV 2.4.4