-
CentOS安装git
CentOS默认源是没有git的,所以希望通过yum install来安装的童鞋们,不要在错误的道路上越走越远……
所以,要从源安装,对应的命令:
yum -y install zlib-devel openssl-devel perl cpio expat-devel gettext-devel
wget http://git-core.googlecode.com/files/git-1.7.7.5.tar.gz
./configure –prefix=/usr/local/git
make
make install
然后对执行文件进行链接,当然,如果安装在/usr/local目录的话,就不用这步了。
ln -s /usr/local/git/bin/git /usr/local/bin/git
ln -s /usr/local/git/bin/gitk /usr/local/bin/gitk
ln -s /usr/local/git/bin/git-shell /usr/local/bin/git-shell
ln -s /usr/local/git/bin/git-upload-pack /usr/local/bin/git-upload-pack
ln -s /usr/local/git/bin/git-cvsserver /usr/local/bin/git-cvsserver
ln -s /usr/local/git/bin/git-receive-pack /usr/local/bin/git-receive-pack
ln -s /usr/local/git/bin/git-upload-archive /usr/local/bin/git-upload-archive
常见问题
1、如果出现“git: error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory”
在确认已经安装iconv库的情况下,执行以下命令:
echo "/usr/local/lib" > /etc/ld.so.conf.d/git.conf
/sbin/ldconfig
2、如果在“git clone https://***”时出现“error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed while accessing”
在使用git前加上“GIT_SSL_NO_VERIFY=true”的环境变量,即:
env GIT_SSL_NO_VERIFY=true git clone https://***
-
firefox蛋疼升级到9.0.1后提示“附加组件不兼容”解决办法
firefox蛋疼升级到9.0.1后提示“附加组件不兼容”解决办法
访问about:config->我保证我会小心->右击“新建”->“布尔值”->名称中填写“extensions.checkCompatibility.9.0”->值的内容为“false”。重启firefox即可屏蔽兼容性检查,直接启用插件。 将来升级到10的话,将上面的“extensions.checkCompatibility.9.0”改为“extensions.checkCompatibility.10.0”即可。
参考: http://kb.mozillazine.org/Extensions.checkCompatibility
需要注意的是,在“附加组件管理器”中搜索某个插件,可能会提示“找不到任何匹配的附加组件”,这是因为,即使设置了安装插件是不检查兼容性,但搜索时自动过滤了Firefox认为不兼容的插件。这时,需要移步去https://addons.mozilla.org/搜索对应插件。
在about:config怎么删除一个首选项名称:如果是自己添加的,在键上点右键→ 重置,重新启动firefox之后就没有了。
-
PHP的curl/libcurl连接https/SSL网站
在PHP中使用libcurl连接https/SSL网站,可以用以下代码测试是否连接畅通:
<? $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, 'https://passport.baidu.com/?login'); curl_setopt($curl, CURLOPT_POST, false); $curl_res = curl_exec($curl); echo $curl_res; if (curl_errno($curl)) { echo 'Error: ' . curl_error($curl); } curl_close($curl); ?>
如果显示正常,则证明连接畅通。
如果显示“Error: couldn’t connect to host”,则证明出错啦!
首先,进入phpinfo页面查看libcurl,看看curl字段是否有OpenSSL支持。如果没有,那就自己折腾PHP的安装吧!
然后,将libeay32.dll和ssleay32.dll拷贝到windows目录、system32目录;或者如果是命令行运行PHP,则拷贝到当前运行目录;或运行Apache运行PHP,则拷贝到当前运行Apache的目录。
重启Apache或者PHP,再次执行代码查看是否正常。
-
Windows下编译安装Privoxy
首先,要安装MingW。在此不赘述。当然,用cygwin也可以,但是这样编译出来的Privoxy没有GUI图形界面。PS:Privoxy在jcc.c那里已经自动识别了MingW,并且嵌入了Windows GUI的API,因此编译出来就可以自己采用图形界面了。
然后,在这里下载Privoxy的源代码,本文以privoxy-3.0.18-stable为例。
进入privoxy-3.0.18-stable源码目录,执行以下命令,进入bash:
bash
执行以下命令,进行配置:
autoheader
autoconf
./configure –prefix=/r/privoxy –enable-mingw32 –disable-pthread稍微解释以下configure的各个参数。–prefix参数指明privoxy的安装目录,/r/privoxy是mingw表示windows文件系统的方式,即R盘的privoxy文件夹。–enable-mingw32指明了为mingw环境配置,其实不指明配置程序也会自动检测得到。–disable-pthread是禁用POSIX的pthread,privoxy会自动使用windows API的thread来实现线程,具体参照errlog.c的部分代码:
/********************************************************************* * * Function : get_thread_id * * Description : Returns a number that is different for each thread. * * XXX: Should be moved elsewhere (miscutil.c?) * * Parameters : None * * Returns : thread_id * *********************************************************************/ static long get_thread_id(void) { long this_thread = 1; /* was: pthread_t this_thread;*/ #ifdef __OS2__ PTIB ptib; APIRET ulrc; /* XXX: I have no clue what this does */ #endif /* __OS2__ */ /* FIXME get current thread id */ #ifdef FEATURE_PTHREAD this_thread = (long)pthread_self(); #ifdef __MACH__ /* * Mac OSX (and perhaps other Mach instances) doesn't have a debuggable * value at the first 4 bytes of pthread_self()'s return value, a pthread_t. * pthread_t is supposed to be opaque... but it's fairly random, though, so * we make it mostly presentable. */ this_thread = abs(this_thread % 1000); #endif /* def __MACH__ */ #elif defined(_WIN32) this_thread = GetCurrentThreadId(); #elif defined(__OS2__) ulrc = DosGetInfoBlocks(&ptib, NULL); if (ulrc == 0) this_thread = ptib -> tib_ptib2 -> tib2_ultid; #endif /* def FEATURE_PTHREAD */ return this_thread; }
配置成功后,编译安装:
make
make install
其实,make后已经有privoxy.exe,可以下载官方的Win32版本的ZIP包,替换里面的privoxy.exe即可使用,无需再make install。
一些注意的问题:
1、编译时提示未定义“NI_MAXSERV”
编译时出现如下错误:
jbsockets.c: In function ‘get_host_information’:
jbsockets.c:979:22: error: ‘NI_MAXSERV’ undeclared (first use in this function)jbsockets.c:979:22: note: each undeclared identifier is reported only once for e
ach function it appears in
make: *** [jbsockets.o] Error 1
修改jbsockets.c,在
const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION;
前面加上:
/* MOD BY Creke START */
#ifndef NI_MAXSERV#define NI_MAXSERV 32
#endif
/* MOD BY Creke END */
说实话,这是configure没有识别getnameinfo和getaddrinfo,因此config.h中没有定义HAVE_RFC2553所致。这些依赖于官方修复,再次仅拷贝ws2tcpip.h中的相关值进来,作临时修补。
2、MingW默认安装的话,需要额外的库吗?
需要zlib库,在mingw中又称为libz,可以在这里下载。当然,如果需要将privoxy拷贝到其它电脑运行,需要将libz-1.dll拷贝到privoxy程序目录中。
3、额外的DLL?
libgcc_s_dw2-1.dll
4、编译好如何发行和安装?
推荐下载官方发行的win32的zip包,将编译好的privoxy.exe覆盖。同时别忘记拷贝依赖的dll。
-
使用plowshare命令行下自动下载国内外网盘资源
下载plowshare:
git clone https://code.google.com/p/plowshare/
安装:
PREFIX=/usr/local/plowshare make install
执行链接:
ln -s /usr/local/plowshare/bin/plowdown /usr/bin/plowdown
ln -s /usr/local/plowshare/bin/plowup /usr/bin/plowup
ln -s /usr/local/plowshare/bin/plowlist /usr/bin/plowlist
ln -s /usr/local/plowshare/bin/plowdel /usr/bin/plowdel下载国内外网盘的东西,如网盘下载链接为“http://xxx/xxx”只需执行一条命令
plowdown http://xxx/xxx
如果plowshare出现“Can’t locate HTML/Entities.pm in @INC”,执行以下命令:
cpan
(如果是第一次使用cpan,根据自己情况配置好)
当看到:
cpan>
输入:
install HTML::Entities
这样就会修复上述问题啦!
-
CentOS5安装后常见问题解决方案
教育网用户怎么设置更新源?
用163的更新源吧:
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.old
wget http://mirrors.163.com/.help/CentOS5-Base-163.repo
mv CentOS5-Base-163.repo /etc/yum.repos.d/CentOS5-Base-163.repo用了163更新源,yum install时出现“GPG key retrieval failed: [Errno 4] IOError: <urlopen error (111, ‘Connection refused’)>”咋办?
那是你的教育网不能连国外网站,获取不了官网镜像上的GPG公钥。解决方法:
编辑/etc/yum.repos.d/CentOS5-Base-163.repo
把其中的“gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-5”
改为“gpgkey=http://mirrors.163.com/centos/RPM-GPG-KEY-CentOS-5”
SSH在机子里可以连接,在机子外不能?
确认是不是防火墙iptables挡住了吧!解决办法:
iptables -I INPUT 1 -p tcp –dport 22 -j ACCEPT
iptables-save
service iptables save好啦,差不多就这么多,最后附一个dev环境的给力批量安装脚本。保存为xxoo.sh使用。
#! /bin/bash
for packages in patch make gcc gcc-c++ gcc-g77 flex bison file libtool libtool-libs autoconf kernel-devel libjpeg libjpeg-devel libpng libpng-devel libpng10 libpng10-devel gd gd-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glib2 glib2-devel bzip2 bzip2-devel libevent libevent-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel fonts-chinese gettext gettext-devel ncurses-devel gmp-devel pspell-devel unzip screen;
do yum -y install $packages; done -
Eclipse支持PHP使用Zend Debugger调试
一、安装Eclipse
下载地址为http://www.eclipse.org/downloads/
上面有好多个版本,通过Compare Packages科研看到其中的区别。开发PHP的话,Eclipse IDE for JavaScript Web Developers就行。但我考虑到以后可能要用它来折腾JAVA EE,所以下了Eclipse IDE for Java EE Developers。
下载下来的是ZIP包,解压即可用。
二、安装Eclipse for PHP集成开发环境
参考http://wiki.eclipse.org/PDT/Installation#Installation_Flow
选择“Help”——“Install New Software…”——Work With下拉菜单处选择对应版本的release,如我的3.7选“Indigo – http://download.eclipse.org/releases/indigo”——展开“Programming Languages”——选择“PHP Development Tools”。
然后确认条款,等待安装,重启Eclipse即可支持PHP开发。
三、PHP配置Zend Debugger
在这里,点击“Studio Web Debugger”那个链接,下载ZendDebugger,解压缩,如我解压缩到W:\ZendDebugger文件夹中。
我是使用PHP5.2,则讲ZendDebugger文件夹中的5.2.x_comp改名为php-5.2.x。
然后在php.ini的[Zend]段末加上以下内容:
; zend_debugger
zend_extension_manager.debug_server_ts="W:\ZendDebugger"
;zend_debugger.allow_hosts=127.0.0.1,192.168.0.0/24
zend_debugger.expose_remotely=always注意,如果是有安装Zend Optimizer的话,要在Zend Optimizer的配置后加入Zend Debugger的配置语句。
四、联合Eclipse和Zend Debugger
首先,开启WWW服务器,确认Zend Debugger成功配置。
然后,开启Eclipse。
在Eclipse中,选择“Window”——“Preferences”——“PHP”——“PHP executables”。在里面设置php的各项参数。我把SAPI设为“CGI”。
在Eclipse中,选择“Window”——“Preferences”——“PHP”——“Debug”——“Installed Debuggers”。在里面设置php的各项参数。把Zend Debugger的“Debug Port”设为“10137”,默认的端口为10137,需要与php.ini设置的一致。
将W:\ZendDebugger中的dummy.php拷贝至Web服务器的根目录中。
在Eclipse中,选择“Run”——“Debug Configuration…”。在PHP Web Page中右击,选“new”,新建一个server配置,并设置好其中各项内容。点击“Test Debugger”,如果成功了就恭喜恭喜。如果没通过,则按照出错提示修正配置错误。
OK,大功告成。
-
让SSH/SOCKS成为全局代理的软件们(Windows+Linux)
Windows下的有:
前者比较好用,可控规则较多。我正在使用。
Linux下的有:
proxychain功能较多,支持多个代理轮询等;redsocks据说支持android;tsocks配置简单。
proxychains教程
假设代理为127.0.0.1,端口为7070。我在Ubuntu下安装。
安装很简单:
sudo apt-get install proxychains
配置:
sudo vi /etc/proxychains.conf
把最后的“[ProxyList]”部分配置为自己的代理即可:
socks4 127.0.0.1 7070
使用方法:
proxychains <程序名>
即可让程序使用代理。
redsocks教程
严格意义上来说,proxychains不算自动的全局代理,有没有像Proxifier这样,开了之后自动让所有启动的程序都走系统代理呢?答案就是redsocks。
首先安装Ubuntu编译环境和必要的库:
sudo apt-get install autoconf automake libtool libevent-dev g++
下载源代码,然后编译安装:
./mkauto.sh
cp redsocks /usr/local/bin/
配置文件为:
base {
// debug: connection progress & client list on SIGUSR1
log_debug = off;// info: start and end of client session
log_info = off;/* possible `log’ values are:
* stderr
* file:/path/to/file
* syslog:FACILITY facility is any of "daemon", "local0"…"local7"
*/
log = "file:/dev/null";
// log = stderr;
// log = "file:/path/to/file";
// log = "syslog:local7";// detach from console
daemon = on;/* Change uid, gid and root directory, these options require root
* privilegies on startup.
* Note, your chroot may requre /etc/localtime if you write log to syslog.
* Log is opened before chroot & uid changing.
*/
// user = nobody;
// group = nobody;
// chroot = "/var/chroot";/* possible `redirector’ values are:
* iptables – for Linux
* ipf – for FreeBSD
* pf – for OpenBSD
* generic – some generic redirector that MAY work
*/
redirector = iptables;
}redsocks {
/* `local_ip’ defaults to 127.0.0.1 for security reasons,
* use 0.0.0.0 if you want to listen on every interface.
* `local_*’ are used as port to redirect to.
*/
local_ip = 127.0.0.1;
local_port = 12345;// `ip’ and `port’ are IP and tcp-port of proxy-server
ip = 127.0.0.1;
port = 7070;// known types: socks4, socks5, http-connect, http-relay
type = socks5;// login = "foobar";
// password = "baz";
}redudp {
// `local_ip’ should not be 0.0.0.0 as it’s also used for outgoing
// packets that are sent as replies – and it should be fixed
// if we want NAT to work properly.
local_ip = 127.0.0.1;
local_port = 10053;// `ip’ and `port’ of socks5 proxy server.
ip = 10.0.0.1;
port = 1080;
login = username;
password = pazzw0rd;// kernel does not give us this information, so we have to duplicate it
// in both iptables rules and configuration file. By the way, you can
// set `local_ip’ to 127.45.67.89 if you need more than 65535 ports to
// forward
// This limitation may be relaxed in future versions using contrack-tools.
dest_ip = 8.8.8.8;
dest_port = 53;udp_timeout = 30;
udp_timeout_stream = 180;
}dnstc {
// fake and really dumb DNS server that returns "truncated answer" to
// every query via UDP, RFC-compliant resolver should repeat same query
// via TCP in this case.
local_ip = 127.0.0.1;
local_port = 5300;
}// you can add more `redsocks’ and `redudp’ sections if you need.
这里的配置没有配置udp的代理部分,只是配置了tcp即redsocks部分。监听端口是12345。日志关闭了,因为好像我下载的当前版本无论怎么样都产生一堆调试日志,不知道以后会不会修复这点。
启动关闭脚本redsocks.sh为(via):
#! /bin/bash
SSHHOST=creke
SSHPORT=22
SSHUSR=creke
SSHPWD=crekeSSHDAEMON=/usr/local/bin/plink
SSHPIDFILE=/var/run/sshtunnel.pidstart_ssh()
{
echo "Start SSH Tunnel Daemon: "
start-stop-daemon -b -q -m -p $SSHPIDFILE –exec $SSHDAEMON -S \
— -N -D 127.0.0.1:7070 -P $SSHPORT -pw $SSHPWD $SSHUSR@$SSHHOST
echo "SSH Tunnel Daemon Started."
}stop_ssh()
{
#ps aux|grep "ssh -NfD 1234"|awk ‘{print $2}’|xargs kill
if [ -f $SSHPIDFILE ]; then
PID=$(cat $SSHPIDFILE)
kill $PID
while [ -d /proc/$PID ];
do
sleep 1
done
fi
rm -rf $SSHPIDFILE
echo "SSH Tunnel Daemon Stoped."
}case "$1" in
start)
start_ssh
cd /usr/local/redsocks
if [ -e redsocks.log ] ; then
rm redsocks.log
fi
./redsocks -p /usr/local/redsocks/redsocks.pid #set daemon = on in config file
# start redirection
# iptables -t nat -A OUTPUT -p tcp –dport 80 -j REDIRECT –to 12345
# iptables -t nat -A OUTPUT -p tcp –dport 443 -j REDIRECT –to 12345
# Create new chain
iptables -t nat -N REDSOCKS# Ignore LANs and some other reserved addresses.
iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN# Anything else should be redirected to port 12345
iptables -t nat -A REDSOCKS -p tcp -j REDIRECT –to-ports 12345
# Any tcp connection should be redirected.
iptables -t nat -A OUTPUT -p tcp -j REDSOCKS
;;stop)
stop_ssh
cd /usr/local/redsocks
if [ -e redsocks.pid ]; then
kill `cat redsocks.pid`
rm redsocks.pid
else
echo already killed, anyway, I will try killall
killall -9 redsocks
fi
# stop redirection
iptables -t nat -F OUTPUT
iptables -t nat -F REDSOCKS
iptables -t nat -X REDSOCKS
;;start_ssh)
start_ssh
;;stop_ssh)
stop_ssh
;;clean_dns)
# iptables -A INPUT -p udp –sport 53 -m state –state ESTABLISHED -m you-know-who -j DROP -m comment –comment "drop you-know-who dns hijacks"
echo this function not finished
;;*)
echo "Usage: redsocks start|stop|start_ssh|stop_ssh|clean_dns" >&2
exit 3
;;
esaciptables的规则是让所有的TCP包都发送到redsocks监听的端口12345。本脚本还整合了ssh的daemon启动,使用start-stop-daemon来实现。
启动和关闭:
将启动关闭脚本中的开头的几个变量配置好
启动命令:sudo ./redsocks.sh start
关闭命令:sudo ./redsocks.sh stop
-
Kinect驱动Microsoft官方与OpenNI对比
RGB:
RGB对比就不用了,因为在普通应用中,没有什么好对比的。
结论:都能捕捉RBG彩色图像
骨骼捕捉:
微软:当人完整出现在Kinect感应范围内时,不需要做特定动作,即可以准确地捕捉全身骨骼。但不能捕捉半身骨骼。
OpenNI:当深度图像中识别到用户时,需要手臂和肘呈90度,作投降姿势,才能识别骨骼。可以捕捉半身骨骼。
深度数据:
微软:默认情况下会出现两个重影(因为有两个红外摄像头的缘故)。而且深度信息精确度较低。
OpenNI:深度信息处理较好,精确度较高。 这些对自己实现的手指捕捉,手势识别等很重要。
-
Kinect SDK中SkeletalViewer sample的学习笔记
运行时初始化
VideoStream必须在Runtime初始化时指定UseColor;分辨率有两种格式:Resolution1280×1024和Resolution640×480;图像类型有三种:Color,ColorYUV和ColorYUVRaw。
DepthStream必须在Runtime初始化时指定UseDepthAndPlayerIndex;的分辨率有两种格式:Resolution320×240和Resolution80×60;图像类型只有一种:DepthAndPlayerIndex。
运行的时候
当一个视频帧准备好时,runtime发出VideoFrameReady信号,并调用nui_ColorFrameReady。其余的DepthFrameReady和SkeletonFrameReady,与其相关的EventHandler函数类似。
nui_ColorFrameReady函数的内容是,更新对应控件(即video)的图像内容。
处理Depth数据
void nui_DepthFrameReady(object sender, ImageFrameReadyEventArgs e) { PlanarImage Image = e.ImageFrame.Image; byte[] convertedDepthFrame = convertDepthFrame(Image.Bits); depth.Source = BitmapSource.Create( Image.Width, Image.Height, 96, 96, PixelFormats.Bgr32, null, convertedDepthFrame, Image.Width * 4); ++totalFrames; DateTime cur = DateTime.Now; if (cur.Subtract(lastTime) > TimeSpan.FromSeconds(1)) { int frameDiff = totalFrames - lastFrames; lastFrames = totalFrames; lastTime = cur; frameRate.Text = frameDiff.ToString() + " fps"; } }
函数大概意思:首先,从事件中获得图片信息Image;然后,将原始的16位景深图转为32位图像;接着,设置depth控件的图像为convertedDepthFrame,即转换后的32位景深图;最后,将总帧数加1,并判断,如果统计事件超过一秒,则刷新fps的记录。
原始的16位景深图描述如下(这里第8个问题为更详细的解释):
- 最低3位为skeleton ID
- 剩下的13位中的低12位是深度值,单位为毫米
如果景深数据以raw或gray-scale显示,用户很难分清场景中的人像。所以,程序将不同的用户渲染一种不同的颜色。先看代码:
// Converts a 16-bit grayscale depth frame which includes player indexes into a 32-bit frame // that displays different players in different colors byte[] convertDepthFrame(byte[] depthFrame16) { for (int i16 = 0, i32 = 0; i16 < depthFrame16.Length && i32 < depthFrame32.Length; i16 += 2, i32 += 4) { int player = depthFrame16[i16] & 0x07; int realDepth = (depthFrame16[i16+1] << 5) | (depthFrame16[i16] >> 3); // transform 13-bit depth information into an 8-bit intensity appropriate // for display (we disregard information in most significant bit) byte intensity = (byte)(255 - (255 * realDepth / 0x0fff)); depthFrame32[i32 + RED_IDX] = 0; depthFrame32[i32 + GREEN_IDX] = 0; depthFrame32[i32 + BLUE_IDX] = 0; // choose different display colors based on player switch (player) { case 0: depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 2); break; case 1: depthFrame32[i32 + RED_IDX] = intensity; break; case 2: depthFrame32[i32 + GREEN_IDX] = intensity; break; case 3: depthFrame32[i32 + RED_IDX] = (byte)(intensity / 4); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); break; case 4: depthFrame32[i32 + RED_IDX] = (byte)(intensity); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 4); break; case 5: depthFrame32[i32 + RED_IDX] = (byte)(intensity); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 4); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); break; case 6: depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2); depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2); depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); break; case 7: depthFrame32[i32 + RED_IDX] = (byte)(255 - intensity); depthFrame32[i32 + GREEN_IDX] = (byte)(255 - intensity); depthFrame32[i32 + BLUE_IDX] = (byte)(255 - intensity); break; } } return depthFrame32; }
解释一下具体步骤:
- “player = depthFrame16[i16] & 0×07”说的是,将用户信息从最低3位中提取。值从0到6(Kinect理论上最多支持7个用户,但官方文档称SDK最多只支持6个),如果值为0,则表示无用户。
- “realDepth = (depthFrame16[i16+1] << 5) | (depthFrame16[i16] >> 3)”的意思是,因为depthFrame16只有8位,所以从第一个byte得到高5位(depthFrame16[i16] >> 3),以及与第二个byte中拼接(depthFrame16[i16+1] << 5)。注:上面那里官方文档有误!
- “intensity = (byte)(255 – (255 * realDepth / 0×0fff))”这句话,是将12位的景深数据转化为8位。注:官方文档也不准确!其实就是:255*(1 – realDepth/0×0fff)
- “depthFrame32[i32 + *_IDX] = 0;”几条语句将32位的图像置0。其实,从初始化语句“byte[] depthFrame32 = new byte[320 * 240 * 4]”可以看到,这是一个具有4个通道,320*240的视频帧。前三个通道分别为蓝、绿、红的颜色值,第4个通道为保留字段。
- “case”语句基于用户序号信息,将玩家所在的像素设置为不同的颜色。当然,当前Kinect最多支持6个玩家,所以“case 7”我认为只是理论上有用。
处理骨架数据
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) { SkeletonFrame skeletonFrame = e.SkeletonFrame; int iSkeleton = 0; Brush[] brushes = new Brush[6]; brushes[0] = new SolidColorBrush(Color.FromRgb(255, 0, 0)); brushes[1] = new SolidColorBrush(Color.FromRgb(0, 255, 0)); brushes[2] = new SolidColorBrush(Color.FromRgb(64, 255, 255)); brushes[3] = new SolidColorBrush(Color.FromRgb(255, 255, 64)); brushes[4] = new SolidColorBrush(Color.FromRgb(255, 64, 255)); brushes[5] = new SolidColorBrush(Color.FromRgb(128, 128, 255)); skeleton.Children.Clear(); foreach (SkeletonData data in skeletonFrame.Skeletons) { if (SkeletonTrackingState.Tracked == data.TrackingState) { // Draw bones Brush brush = brushes[iSkeleton % brushes.Length]; skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.HipCenter, JointID.Spine, JointID.ShoulderCenter, JointID.Head)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.ShoulderCenter, JointID.ShoulderLeft, JointID.ElbowLeft, JointID.WristLeft, JointID.HandLeft)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.ShoulderCenter, JointID.ShoulderRight, JointID.ElbowRight, JointID.WristRight, JointID.HandRight)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.HipCenter, JointID.HipLeft, JointID.KneeLeft, JointID.AnkleLeft, JointID.FootLeft)); skeleton.Children.Add(getBodySegment(data.Joints, brush, JointID.HipCenter, JointID.HipRight, JointID.KneeRight, JointID.AnkleRight, JointID.FootRight)); // Draw joints foreach (Joint joint in data.Joints) { Point jointPos = getDisplayPosition(joint); Line jointLine = new Line(); jointLine.X1 = jointPos.X - 3; jointLine.X2 = jointLine.X1 + 6; jointLine.Y1 = jointLine.Y2 = jointPos.Y; jointLine.Stroke = jointColors[joint.ID]; jointLine.StrokeThickness = 6; skeleton.Children.Add(jointLine); } } iSkeleton++; } // for each skeleton }
iSkeleton标明当前是第几个骨架,从0到5。brush数组标明了每个骨架的骨头绘制颜色。然后,就开始for循环,获得每个骨架的信息,然后判断,如果已经捕捉到(tracked),则开始绘制骨头、绘制关节点。
getBodySegment()函数在文档中解释道,此函数有3个参数:
- 骨架的关节点的集合,Microsoft.Research.Kinect.Nui.JointsCollection对象
- 绘制线条的brush
- JointID值,多个,每一个都标识一个特定的骨架关节
getBodySegment()返回Polyline,连接各个JointID。函数原型为:
Polyline getBodySegment(Microsoft.Research.Kinect.Nui.JointsCollection joints, Brush brush, params JointID[] ids) { PointCollection points = new PointCollection(ids.Length); for (int i = 0; i < ids.Length; ++i ) { points.Add(getDisplayPosition(joints[ids[i]])); } Polyline polyline = new Polyline(); polyline.Points = points; polyline.Stroke = brush; polyline.StrokeThickness = 5; return polyline; }
里面有个叫的getDisplayPosition()函数,将关节点从原始数据转化为程序界面显示区域的坐标。解释如下:
骨架的数据、颜色图像数据和深度数据都是基于不同坐标的。为了从三个流中显示一致的数据,程序就要将各个坐标转换啦!转换步骤如下:
- 将骨架坐标从[-1.0, 1.0]转化为深度数据,调用的函数是SkeletonEngine.SkeletonToDepthImage。该函数返回x和y坐标,浮点
(不是螺纹>_<),从0.0到1.0。 - 将浮点坐标转化为320*240的深度坐标空间,这是NuiCamera.GetColorPixelCoordinatesFromDepthPixel要求的格式。
- 将深度坐标转化为彩色图像坐标,调用NuiCamera.GetColorPixelCoordinatesFromDepthPixel,函数的要求参考第三点,返回一个彩色图像,坐标是640*480的彩色图像空间。(各种蛋疼)
- 把图像转化为程序界面可以显示的图像,方法是,将x坐标和y坐标分别除以640和480,然后再乘以程序界面显示区域的高和宽。
函数原型为:
private Point getDisplayPosition(Joint joint) { float depthX, depthY; nui.SkeletonEngine.SkeletonToDepthImage(joint.Position, out depthX, out depthY); depthX = depthX * 320; //convert to 320, 240 space depthY = depthY * 240; //convert to 320, 240 space int colorX, colorY; ImageViewArea iv = new ImageViewArea(); // only ImageResolution.Resolution640x480 is supported at this point nui.NuiCamera.GetColorPixelCoordinatesFromDepthPixel(ImageResolution.Resolution640x480, iv, (int)depthX, (int)depthY, (short)0, out colorX, out colorY); // map back to skeleton.Width & skeleton.Height return new Point((int)(skeleton.Width * colorX / 640.0), (int)(skeleton.Height * colorY / 480)); }
好了,说完了。小朋友们,下次节目,再见吧~
注:文章所述之“文档”皆指:http://research.microsoft.com/en-us/um/redmond/projects/kinectsdk/docs/SkeletalViewer_Walkthrough.pdf
时间脚印
| 一 | 二 | 三 | 四 | 五 | 六 | 日 |
|---|---|---|---|---|---|---|
| « 一 | ||||||
| 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 | 29 | ||||
最新文章
- 从火车票提取完整实名信息
- CentOS安装git
- firefox蛋疼升级到9.0.1后提示“附加组件不兼容”解决办法
- 关于SSL证书通用名(CN)通配符的实验
- CentOS下安装使用start-stop-daemon
最近评论
- creke 在 从火车票提取完整实名信息 上的评论
- Xiaoxia 在 从火车票提取完整实名信息 上的评论
- 有DNS的地方就能上网 « 细节的力量 在 用DNS隧道实现免费上网 上的评论
- creke 在 Windows下编译安装Privoxy 上的评论
- 小铱 在 Windows下编译安装Privoxy 上的评论

