Reiase's Blog

Happy coding

模拟Matlab工作空间的Python脚本

最近做Adaboost人脸检测训练,感觉为每一个功能都写一个命令行入口太麻烦,比如,三种训练算法,其Python实现的入口分别是train_1, train_2, train_3。通常需要为每一个训练算法写一个入口脚本,接受命令行参数,完成对训练算法的调用。但是这样太繁琐了,工作目录下一下子多出好多文件,而且要保持训练算法和对应入口脚本的一致性。我编写了一个从shell直接调用python函数的小工具,省去了编写入口脚本的麻烦。比如如下定义的Python函数(foo.py)

def foofunc(arg1, arg2, arg3):
    ...
    return retval

可通过如下命令调用:

$ ./script foofunc@foo arg1 arg2 arg3

为了能够向函数传递对象作为实参,引入了workspace的概念:workspace是一个路径,下边存放pickle格式的串行化对象。对于传递给函数的实参arg_n,script脚本首先检查workspace下是否存在同名文件,若存在就从该文件读取对象,若不存在,script脚本尝试把arg_n作为Python表达式来求值,并把该值作为函数实参,若求值失败,则arg_n作为字符串处理。可以通过等号操作向workspace内的变量赋值(实际上是把值保存到workspace下的文件)

./script foofunc@foo argv1 argv2 argv3 = retval

 

小工具由两个短文件实现:

script脚本,python函数的命令行入口

 

#!/usr/bin/env python
import sys
import cPickle as pickle

from utils import workspace as ws

sargv = sys.argv[1:]
argv = []
outfile = ''

try:
	eqind = sargv.index('=')
	argv = sargv[:eqind]
	outfile = sargv[eqind+1]
except:
	argv = sargv
	outfile = ''

re = ws.command(argv)

if not outfile:
    sys.stdout.write(pickle.dumps(re))
else:
    ws.save(re, outfile)

workspace支持workspace.py

 

import cPickle as pickle
import os

from utils import tlog

LOG = tlog.get(__name__)

def save(value, name):
    with open(os.path.join('workspace',name), 'w') as f:
        pickle.dump(value, f)
    LOG.info("Saving workspace variable: %s", name)

def load(name):
    with open(os.path.join('workspace',name)) as f:
        value = pickle.load(f)
    LOG.info("Loading workspace variable: %s",name)
    return value

def wseval(x):
    if os.path.isfile(os.path.join('workspace', x)):
        return load(x)
    try:
        re = eval(x)
        LOG.info("Eval code: %s",x)
        return re
    except:
        LOG.info("String argument: %s",x)
        return x

def command(argv):
    funname, modname = argv[0].split('@')
    mod = __import__(modname, fromlist=[argv[0]])
    fun = eval('mod.'+funname)
    try:
        nkw = filter(lambda x:not x.startswith('--'), argv[1:])
        nkw = map(wseval, nkw)
    except:
        nkw = []
    try:
        kws = filter(lambda x: x.startswith('--'), argv[1:])
        kws = map(lambda x: x.replace('--', '').split('='), kws)
        kws = dict( map(lambda x:tuple(x[0],wsevalx[1]), kws) )
    except:
        kws = {}
    if callable(fun):
        LOG.info("Excuting %s",argv)
        re = apply(fun, nkw, kws)
        LOG.info("Finish excute %s", argv)
        return re
    else:
        return fun

 

用Cython编写Wrapper(续)

上次提到的Demo程序没有入口,这次我尝试为那个Demo添加一个Web接口。 服务器端 首先导入上次编译出来的模块: 1from a import a 创建class a的一个实例,并开始主循环: 12x = a() thread.start_new_thread(x.mainloop,()) 开始处理Web事务处理,首先导入相应模块: 12345import os from BaseHTTPServer import HTTPServer from CGIHTTPServer import CGIHTTPRequestHandler from SocketServer import ThreadingMixIn from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler 创建一个XMLRPCServer,处理Web请求,允许用户发送Web请求来修改参数: 123456789101112131415161718class a:     global x     def setparam1(self,v):         x.param1 = v     def setparam2(self,v):         x.param2 = v class myHandler(SimpleXMLRPCRequestHandler,CGIHTTPRequestHandler):     pass class ThreadingServer(ThreadingMixIn, SimpleXMLRPCServer):     pass; serveraddr = ('',8080); srv = ThreadingServer(serveraddr,myHandler); srv.register_instance(a()) srv.register_introspection_functions() srv.serve_forever() Python Web编程部分内容可参考《Python网络编程基础》这本书。 客户端 在客户端使用AJAX技术向服务器发送XMLRPC申请,代码如下: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128<!DOCTYPE [...]

阅读全文

用Cython编写Wrapper

最近尝试了下用cython编写python扩展。由于cython中可以同时调用C和Python代码,因此也是编写Wrapper的不错工具。手头一个程序需要Web化的远程界面,正好用Python和C混合编程来实现。嘿嘿,先放一个自己写的Demo上来 建立C程序 这里用一段简单的代码来模拟视频处理算法的一般情况:接受几个参数,在死循环里逐帧处理视频。 12345678//a.h typedef struct { int param1; int param2; }a; a* aAlloc(void); void mainloop(a*); 123456789101112131415161718//a.c #include <stdio.h> #include <stdlib.h> #include "a.h" a* aAlloc(void) {     return malloc(sizeof(a)); } void mainloop(a* x) {     while (1) {         printf("param1:%d\n",x->param1);         printf("param2:%d\n",x->param2);         system("sleep 1");     } } 编写wrapper程序 123456789101112131415161718192021222324252627#a_ext.pyx cdef extern from "a.h":     ctypedef struct c_a "a":         int param1         int param2     cdef [...]

阅读全文

在Linux下链接win32 DLL

最近拿到一款IP摄像机,SDK只有win32版本。闲来无聊,就试了试在Linux下调用SDK里的DLL来控制摄像机。 在Linux下调用Windows DLL主要面临两个问题: DLL的加载。DLL可执行文件格式与Linux下的so文件格式类似,wine与mplayer等程序都是可以加载dll。为了实现方便,我们借助wine来加载DLL DLL中函数会进行windows系统调用,或者调用其他windows库。为了避免麻烦,我们也让wine处理这些调用 利用wine,仅需三步即可链接DLL库 导出dll文件的spec文件 winedump spec -I. yourlib.dll 该命令生成yourlib.spec文件。可能需要用”-I”添加dll文件对应的头文件目录,不然dll导出的符号,找不到原型,挥别忽略。 生成def文件 winebuild –def -E yourlib.spec -o libyourlib.def 这里需要指定def文件名为libyourlib.def,gcc查找库的时候需要lib这个前缀 编译程序 winegcc -L. -lyourlib main.c -o main

阅读全文