2011年09月25日

IronPythonでプロファイラ使って性能測定する方法

残念ながらIronPythonには[記事] のようなcProfileは無いので、別の方法で行う。

見つけた方法は、An IronPython Profiler。[Iron Curt
IronPython2.7で動作確認したけど、動くようだ。

ipy –X:EnableProfiler プログラム名

「type」で始まるのが.Netで、ModuleはPythonのコードらしい。

posted by MINE at 20:47 | Comment(0) | TrackBack(0) | IronPython | このブログの読者になる | 更新情報をチェックする | edit

2011年09月13日

[IronPython] 画像の縦横比を見て回転させ縮小するプログラム Ver2

PILでは扱えなかった[記事]が、IronPtyhonの.Netライブラリだと普通に扱えたので、更新しておく。

コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 引数で指定したフォルダの画像ファイルを
# 出力先フォルダに縮小・回転しながらコピーする

from __future__ import print_function
from __future__ import division
import os,sys,glob
import shutil

import clr
clr.AddReferenceByPartialName('System.Drawing')
from System.Drawing import *

# 出力先フォルダ指定。
TARGET_DIR = 'C:\\Photo'
#COWON A3向け
#max_size = (800, 480)
#PSP向け
#max_size = (480, 270)
#Ziio向け
max_size = (480, 800)
#対象拡張子
ext_dic = ['.jpg','.jpeg','.png','.bmp','.tiff']
#強制変換対象フォーマット
forceCompressFormat = [Imaging.ImageFormat.Bmp,Imaging.ImageFormat.Tiff]
#ファイル名のprefix
DEST_PREFIX = 's_'
#JPEG品質
JPEG_QUALITY = 75

def makeOutputDirectory(outputDirPath):
	if os.path.isdir(outputDirPath) == False:
		os.makedirs(outputDirPath)

def isTarget(ext):
	return True if ext.lower() in ext_dic else False

class ProgressBar:
	def __init__(self,totalNum):
		self.totalNum = totalNum
		self.counter = 0
		self.chr = u"*"
		self.width = 40
	def addCounter(self,incrementNum):
		self.counter += incrementNum
	def show(self):
		pbar_chrs = self.chr * (self.width * self.counter // self.totalNum)
		percentage = 100 * self.counter // self.totalNum
		meter = '\r|{0}{1}| {2}/{3}個 ({4}%)'.format(pbar_chrs,u' ' * (self.width - len(pbar_chrs)),self.counter,self.totalNum, percentage)
		sys.stdout.write(meter)
		sys.stdout.flush()
		
def createJpegEncoder():
	jpgEncoder = [codec for codec in Imaging.ImageCodecInfo.GetImageEncoders() if codec.FormatID == Imaging.ImageFormat.Jpeg.Guid][0]
	encParam = Imaging.EncoderParameter(Imaging.Encoder.Quality,JPEG_QUALITY)
	encParams = Imaging.EncoderParameters(1)
	encParams.Param[0] = encParam
	return (jpgEncoder,encParams)
	
def shrinkImage(srcFileName, dstFileName,jpgEncoder):
	srcImg = Bitmap.FromFile(srcFileName)
	
	if srcImg.Width > max_size[0] or srcImg.Height > max_size[1] or (srcImg.RawFormat in forceCompressFormat):
		# BMP/TIFFの場合、JPEGにする
		if srcImg.RawFormat in forceCompressFormat:
			format = Imaging.ImageFormat.Jpeg
			root,ext = os.path.splitext(dstFileName)
			dstFileName = root + '.jpg'
		else:
			format = srcImg.RawFormat
		
		srcWidth = srcImg.Width
		srcHeight = srcImg.Height
		if max_size[0] > max_size[1]:
			#横が長いディスプレイの場合は縦長の画像を回転させた絵を作る
			if srcImg.Width < srcImg.Height:
				srcWidth = srcImg.Height
				srcHeight = srcImg.Width		
				srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
		else:
			#縦が長いディスプレイの場合は横長の画像を回転させた絵を作る
			if srcImg.Width > srcImg.Height:
				srcWidth = srcImg.Height
				srcHeight = srcImg.Width		
				srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
		
		# 画面より画像が小さい場合はスケーリングしない
		if max_size[0] < srcWidth or max_size[1] < srcHeight:
			scalerate = min(max_size[0]/srcWidth,max_size[1]/srcHeight)
			destWidth = int(round(scalerate * srcWidth))
			destHeight = int(round(scalerate * srcHeight))
		else:
			destWidth = srcWidth
			destHeight = srcHeight
					
		destImg = Bitmap(destWidth,destHeight)
		grphics = Graphics.FromImage(destImg)
		grphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
		grphics.DrawImage(srcImg,0,0,destWidth,destHeight)
		if format  == Imaging.ImageFormat.Jpeg:
			destImg.Save(dstFileName,jpgEncoder[0], jpgEncoder[1])
		else:
			destImg.Save(dstFileName,format)
		destImg.Dispose()
	else:
		# 画面に収まらない or BMP/TIFF形式以外の場合は、再圧縮する必要ないので普通のコピーにする
		shutil.copy(srcFileName,dstFileName)
	srcImg.Dispose()
	
def copyImageTree(targetList,progress):

	jpgEncoder = createJpegEncoder()
	for target in targetList:
		srcname = target[0]
		dstname = target[1]
		try:
			makeOutputDirectory(os.path.dirname(dstname))
			shrinkImage(srcname,dstname,jpgEncoder)
			progress.addCounter(1)
			progress.show()
		except (IOError, os.error), why:
			print("Cant' copy",srcname,'to',dstname,':',str(why))

def createTargetImagePath( path,targetBaseDirectory ):

	targetPath = []
	names = os.listdir(path)
	targetDirectory = targetBaseDirectory

	for name in names:
		srcname = os.path.join(path, name)
		try:
			if os.path.isdir(srcname):
				targetDirectory = os.path.join(targetBaseDirectory, name)
				targetPath += createTargetImagePath( srcname,targetDirectory )
			else:
				root, ext = os.path.splitext(srcname)
				if isTarget(ext) == True:
					targetPath.append((srcname,os.path.join(targetDirectory,DEST_PREFIX + name)))
		except (IOError, os.error), why:
			print("Can't copy",srcname,':',str(why))
	return (targetPath)
			
if __name__=='__main__':
	#引数がおかしい場合
	if len(sys.argv) < 2:
		print('Usage: # Python ',sys.argv[0],' [SouceImageDirectoryPath]...')
		raw_input()
		quit()
		
	targetPathList = []
	for x in range(1,len(sys.argv)):
		sourcePath = os.path.dirname(sys.argv[x] + '\\')

		if os.path.isdir(sourcePath) == False:	#存在しないPathを指定した場合
			print('[',sourcePath,']: Src directory does not exist.')
			raw_input()
			quit()
		elif os.path.isdir(TARGET_DIR) == False:	#存在しないPathを指定した場合
			print('[',TARGET_DIR,']: Dest directory does not exist.')
			raw_input()
			quit()
		elif sourcePath == TARGET_DIR:	#入力先と出力先が同じ場合
			print('The input destination is the same as the output destination.')
			raw_input()
			quit()
		else:
			targetPathList +=  createTargetImagePath(sourcePath,(TARGET_DIR + '\\' + os.path.basename(sourcePath)))
	
	if len(targetPathList) == 0:
		print('File does not exist.')
		quit()

	progress = ProgressBar(len(targetPathList))
	copyImageTree(targetPathList,progress)
関係する記事
  • [IronPython] 画像の縦横比を見て回転させ縮小するプログラム Ver1[記事]
posted by MINE at 01:31 | Comment(0) | TrackBack(0) | IronPython | このブログの読者になる | 更新情報をチェックする | edit

2011年05月15日

IronPythonでCSVを読み込む

IronPythonには、pythonのモジュールであるcsvモジュールが無い。
なので、VB.NetのCSVを扱うライブラリを使う。
以下は、UTF-8のtest.csvを読み込むときのコード。

Excelからcsvを保存するとShift-JISになるので、その時はGetEncodingを「Shift_JIS」に変えればよい。

1行ずつCSVを読むときのコード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from __future__ import print_function

import clr
clr.AddReferenceByPartialName('Microsoft.VisualBasic')
clr.AddReferenceByPartialName('mscorlib')
from Microsoft.VisualBasic.FileIO import *
from System.Text import *
	
if __name__ == "__main__":
	parser = TextFieldParser("test.csv",Encoding.GetEncoding("UTF-8"))
	parser.TextFieldType = FieldType.Delimited;
	parser.SetDelimiters(",");
	while parser.EndOfData == False:
		print(parser.ReadFields())

まとめてCSVを読むときのコード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
from __future__ import print_function

import clr
clr.AddReferenceByPartialName('Microsoft.VisualBasic')
clr.AddReferenceByPartialName('mscorlib')
from Microsoft.VisualBasic.FileIO import *
from System.Text import *
	
if __name__ == "__main__":
	parser = TextFieldParser("test.csv",Encoding.GetEncoding("UTF-8"))
	parser.TextFieldType = FieldType.Delimited;
	parser.SetDelimiters(",");
	print(parser.ReadToEnd())
参考
  • TextFieldParser クラス[MSDN]
タグ:Python IronPython
posted by MINE at 00:25 | Comment(0) | TrackBack(0) | IronPython | このブログの読者になる | 更新情報をチェックする | edit

2011年05月09日

IronPythonはPythonに比べてどれ位の速度なのか?

Python[記事]とIronPython[記事]で同じプログラム(っていっても微妙に違うけど)を作ってみたので、簡単に速度比較してみた。

519枚のBMP,JPG,PNGのファイルを圧縮するのを、6回ほど計測してみた。

回数\実装 Iron Python
単位:sec
CPython
単位:sec
1回目 45.94 23.17
2回目 45.84 23.21
3回目 45.81 23.21
4回目 45.61 23.02
5回目 45.64 23.05
6回目 46.00 23.46
平均 45.81 23.19

Google Chartで棒グラフにもしてみた。

IronPythonがダブルスコアで負けてる・・・。
遅すぎるぜ、IronPython。
関数単位でもうちょい解析してみるかなぁ。自分のコーディングがタコなのもあるのだろうし。

タグ:IronPython Python
posted by MINE at 00:11 | Comment(0) | TrackBack(0) | IronPython | このブログの読者になる | 更新情報をチェックする | edit

2011年05月08日

[IronPython] 画像の縦横比を見て回転させ縮小するプログラム Ver1

Python[記事]で書いていたが、Pythonのサイトに「IronPython has no GIL and multi-threaded code can use multi core processors 」と書いてあったので、ひとまず移植してみた。

勉強がてら、Python Imaging Libraryから.Netのライブラリに変更してみたんだけど、
移植して思うのはPILってよくできてるよな〜ってところ。
PILだと26行くらいで済んでたコードが、55行とほぼ倍になってしまった。
IronPythonの文字は全部Unicodeで統一されているので、日本語の処理はCPythonより楽でよいんだけど。

しかし、IronPythonはやっぱ日本語のページがあんま無いね。
基本は.Netだから同じなんだけど、C#もVB.Netも殆どやってないから、C#の画像圧縮について書いてあるサイトを見ながら、なんとか作ってみた。

コード

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# 引数で指定したフォルダの画像ファイルを
# 出力先フォルダに縮小・回転しながらコピーする

from __future__ import print_function
from __future__ import division
import os,sys,glob
import shutil

import clr
clr.AddReferenceByPartialName('System.Drawing')
from System.Drawing import *

# 出力先フォルダ指定。
TARGET_DIR = 'C:\\Photo'
#COWON A3向け
#max_size = (800, 480)
#PSP向け
#max_size = (480, 270)
#Ziio向け
max_size = (480, 800)
#対象拡張子
ext_dic = ['.jpg','.jpeg','.png','.bmp']
#ファイル名のprefix
DEST_PREFIX = 's_'
#JPEG品質
JPEG_QUALITY = 75

def makeOutputDirectory(outputDirPath):
	if os.path.isdir(outputDirPath) == False:
		os.makedirs(outputDirPath)

def isTarget(ext):
	return True if ext.lower() in ext_dic else False

class ProgressBar:
	def __init__(self,totalNum):
		self.totalNum = totalNum
		self.counter = 0
		self.chr = u"*"
		self.width = 40
	def addCounter(self,incrementNum):
		self.counter += incrementNum
	def show(self):
		pbar_chrs = self.chr * (self.width * self.counter // self.totalNum)
		percentage = 100 * self.counter // self.totalNum
		meter = '\r|{0}{1}| {2}/{3}個 ({4}%)'.format(pbar_chrs,u' ' * (self.width - len(pbar_chrs)),self.counter,self.totalNum, percentage)
		sys.stdout.write(meter)
		sys.stdout.flush()
		
def createJpegEncoder():
	jpgEncoder = [codec for codec in Imaging.ImageCodecInfo.GetImageEncoders() if codec.FormatID == Imaging.ImageFormat.Jpeg.Guid][0]
	encParam = Imaging.EncoderParameter(Imaging.Encoder.Quality,JPEG_QUALITY)
	encParams = Imaging.EncoderParameters(1)
	encParams.Param[0] = encParam
	return (jpgEncoder,encParams)
	
def shrinkImage(srcFileName, dstFileName,jpgEncoder):
	srcImg = Bitmap.FromFile(srcFileName)
	
	if srcImg.Width > max_size[0] or srcImg.Height > max_size[1] or srcImg.RawFormat.Equals(Imaging.ImageFormat.Bmp):
		# BMPの場合、JPEGにする
		if srcImg.RawFormat.Equals(Imaging.ImageFormat.Bmp):
			format = Imaging.ImageFormat.Jpeg
			root,ext = os.path.splitext(dstFileName)
			dstFileName = root + '.jpg'
		else:
			format = srcImg.RawFormat
		
		srcWidth = srcImg.Width
		srcHeight = srcImg.Height
		if max_size[0] > max_size[1]:
			#横が長いディスプレイの場合は縦長の画像を回転させた絵を作る
			if srcImg.Width < srcImg.Height:
				srcWidth = srcImg.Height
				srcHeight = srcImg.Width		
				srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
		else:
			#縦が長いディスプレイの場合は横長の画像を回転させた絵を作る
			if srcImg.Width > srcImg.Height:
				srcWidth = srcImg.Height
				srcHeight = srcImg.Width		
				srcImg.RotateFlip(RotateFlipType.Rotate90FlipNone);
		
		# 画面より画像が小さい場合はスケーリングしない
		if max_size[0] < srcWidth or max_size[1] < srcHeight:
			scalerate = min(max_size[0]/srcWidth,max_size[1]/srcHeight)
			destWidth = int(round(scalerate * srcWidth))
			destHeight = int(round(scalerate * srcHeight))
		else:
			destWidth = srcWidth
			destHeight = srcHeight
					
		destImg = Bitmap(destWidth,destHeight)
		grphics = Graphics.FromImage(destImg)
		grphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
		grphics.DrawImage(srcImg,0,0,destWidth,destHeight)
		if format  == Imaging.ImageFormat.Jpeg:
			destImg.Save(dstFileName,jpgEncoder[0], jpgEncoder[1])
		else:
			destImg.Save(dstFileName,format)
		destImg.Dispose()
	else:
		# 画面に収まらないor BMP形式以外の場合は、再圧縮する必要ないので普通のコピーにする
		shutil.copy(srcFileName,dstFileName)
	srcImg.Dispose()
	
def copyImageTree(targetList,progress):

	jpgEncoder = createJpegEncoder()
	for target in targetList:
		srcname = target[0]
		dstname = target[1]
		try:
			makeOutputDirectory(os.path.dirname(dstname))
			shrinkImage(srcname,dstname,jpgEncoder)
			progress.addCounter(1)
			progress.show()
		except (IOError, os.error), why:
			print("Cant' copy",srcname,'to',dstname,':',str(why))

def createTargetImagePath( path,targetBaseDirectory ):

	targetPath = []
	names = os.listdir(path)
	targetDirectory = targetBaseDirectory

	for name in names:
		srcname = os.path.join(path, name)
		try:
			if os.path.isdir(srcname):
				targetDirectory = os.path.join(targetBaseDirectory, name)
				targetPath += createTargetImagePath( srcname,targetDirectory )
			else:
				root, ext = os.path.splitext(srcname)
				if isTarget(ext) == True:
					targetPath.append((srcname,os.path.join(targetDirectory,DEST_PREFIX + name)))
		except (IOError, os.error), why:
			print("Can't copy",srcname,':',str(why))
	return (targetPath)
			
if __name__=='__main__':
	#引数がおかしい場合
	if len(sys.argv) < 2:
		print('Usage: # Python ',sys.argv[0],' [SouceImageDirectoryPath]...')
		raw_input()
		quit()
		
	targetPathList = []
	for x in range(1,len(sys.argv)):
		sourcePath = os.path.dirname(sys.argv[x] + '\\')

		if os.path.isdir(sourcePath) == False:	#存在しないPathを指定した場合
			print('[',sourcePath,']: Src directory does not exist.')
			raw_input()
			quit()
		elif os.path.isdir(TARGET_DIR) == False:	#存在しないPathを指定した場合
			print('[',TARGET_DIR,']: Dest directory does not exist.')
			raw_input()
			quit()
		elif sourcePath == TARGET_DIR:	#入力先と出力先が同じ場合
			print('The input destination is the same as the output destination.')
			raw_input()
			quit()
		else:
			targetPathList +=  createTargetImagePath(sourcePath,(TARGET_DIR + '\\' + os.path.basename(sourcePath)))
	
	if len(targetPathList) == 0:
		print('File does not exist.')
		quit()

	progress = ProgressBar(len(targetPathList))
	copyImageTree(targetPathList,progress)
参考にしたサイト
  • IronPython事始め[URL]
  • [C#][python] IronPythonで参照が必要なDLLの利用方法 (clr, AddReferenceByPartialName)[いろいろ備忘録日記]
  • [python][.net] IronPythonのメモ[いろいろ備忘録日記]
  • 品質を指定してJPEG画像を保存するには?[@IT]
  • Create Multiframe TIFF Image File[IronPython Coocbook]
  • EncoderParameter クラス[MSDN]
  • EncoderParameters クラス[MSDN]
  • ImageCodecInfo クラス[MSDN]
  • 方法 : JPEG 圧縮レベルの設定[MSDN]
  • Visual C# .NET を使用して、JPEG 品質要因を決定します。[Microsoft]
タグ:Python IronPython
posted by MINE at 16:43 | Comment(0) | TrackBack(0) | IronPython | このブログの読者になる | 更新情報をチェックする | edit