<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>motion detection &#8211; 编码无悔 /  Intent &amp; Focused</title>
	<atom:link href="https://www.codelast.com/tag/motion-detection/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.codelast.com</link>
	<description>最优化之路</description>
	<lastBuildDate>Sun, 03 May 2020 12:33:52 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>[原创]摄像头娘来了</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b%e6%91%84%e5%83%8f%e5%a4%b4%e5%a8%98%e6%9d%a5%e4%ba%86/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b%e6%91%84%e5%83%8f%e5%a4%b4%e5%a8%98%e6%9d%a5%e4%ba%86/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Fri, 27 Jan 2012 18:07:31 +0000</pubDate>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[motion detection]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[t.qq.com/cameragirl]]></category>
		<category><![CDATA[VC++发微博]]></category>
		<category><![CDATA[VC++运动检测]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[内存泄漏]]></category>
		<category><![CDATA[微博]]></category>
		<category><![CDATA[微博API]]></category>
		<category><![CDATA[摄像头娘]]></category>
		<category><![CDATA[物联网]]></category>
		<category><![CDATA[萌娘]]></category>
		<category><![CDATA[运动检测]]></category>
		<category><![CDATA[饮水机娘]]></category>
		<guid isPermaLink="false">http://www.codelast.com/?p=4341</guid>

					<description><![CDATA[<p>
被标题吸引进来的各位，抱歉，这还是一篇技术文章<img decoding="async" alt="crying" height="24" src="http://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/ckeditor/plugins/smiley/images/14.gif" title="crying" width="24" /><br />
本文的主角是一个摄像头及其配套程序，我毫无创意地模仿网上的流行说法，称之为&#8220;<span style="color:#ff0000;">摄像头娘</span>&#8221;。她会自己发微博，<span style="color:#0000ff;">记得follow她哦</span>：<strong><a href="http://t.qq.com/cameragirl" target="_blank" rel="noopener noreferrer"><span style="color:#ff0000;"><span style="background-color:#99ff99;">t.qq.com/cameragirl</span></span></a></strong></p>
<p>前段时间浙大有个博士做了个&#8220;<span style="color:#800080;">饮水机娘</span>&#8221;，也就是他实验室里的饮水机没水或者水加热开了的时候，都会自动发一条微博。这个与&#8220;物联网&#8221;扯上了关系的东西，让我原来以为那位博士是改造了饮水机，加上了温度及水位传感器，配合单片机，将饮水机的状态采集到PC中去，再写一个PC上的软件将触发的事件发送到微博上，后来看了相关的介绍，才知道没那么复杂，其实他没有改造饮水机，而是用一个摄像头对准饮水机的状态指示灯，根据指示灯的情况，来判断饮水机的状态。</p>
<p>于是我也就萌生了做一个&#8220;摄像头娘&#8221;的念头。<br />
我构想中的&#8220;摄像头娘&#8221;是这样的：当有物体在她面前运动的时候，她能感受得到，并且会为这个过客拍一张照片，然后发到微博上。<br />
下面是<span style="color:#ff0000;">实际效果截图</span>：<br />
<span id="more-4341"></span></p>
<div style="text-align: center; ">
	<a href="http://t.qq.com/cameragirl" target="_blank" rel="noopener noreferrer"><img decoding="async" alt="" src="http://www.codelast.com/wp-content/uploads/2012/01/weibo_snapshot.png" style="width: 542px; height: 330px; " /></a></div>
<p>好吧，说得傻一点就是：一个有运动检测（motion detection）功能的程序，当检测到摄像头前有物体在运动时，就将画面拍一张照片，发到微博上。<br />
确实，没啥创意，但是还是有一定实用性的。例如，你可以在家里放置一个&#8220;她&#8221;为你看家，假设你运气不好，有不速之客闯进了你家里，那么，只要他进入了&#8220;摄像头娘&#8221;的视角，就会马上被检测到，然后被拍上来，发到微博上，后面的事，哼哼，你就有第一手证据了。<br />
<span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
我是用<span style="color:#0000ff;">VC++ 2005</span>开发的这个软件，运行于Win7上，其实它很简单，功能主要分为两部分：运动检测（motion detection）&#38; 发微博，下面分别陈述。<br />
<span style="background-color:#afeeee;">【1】</span>运动检测 / motion detection<br />
从头自己写？那得多笨才能这样做啊！而且我也不是干视频处理这一行的，一时半会写不出来这玩意。<br />
久闻<a href="http://opencv.willowgarage.com/wiki/" target="_blank" rel="noopener noreferrer"><span style="background-color:#faebd7;">OpenCV</span></a>的大名，我知道它可以帮我实现想要的功能，所以毫不犹豫地选择了它。<br />
我以前也从未使用过OpenCV，从下载它的开发包开始，到参照网上的demo写出一个可用的motion detection程序，只花了半天多时间，由此可见OpenCV的强大。<br />
关于OpenCV的介绍，这里只摘取其官网的一句话：</p>
<blockquote>
<p>
		OpenCV (Open Source Computer Vision) is a library of programming functions for real time computer vision.</p></blockquote>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b%e6%91%84%e5%83%8f%e5%a4%b4%e5%a8%98%e6%9d%a5%e4%ba%86/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>
被标题吸引进来的各位，抱歉，这还是一篇技术文章<img decoding="async" alt="crying" height="24" src="http://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/ckeditor/plugins/smiley/images/14.gif" title="crying" width="24" /><br />
本文的主角是一个摄像头及其配套程序，我毫无创意地模仿网上的流行说法，称之为&ldquo;<span style="color:#ff0000;">摄像头娘</span>&rdquo;。她会自己发微博，<span style="color:#0000ff;">记得follow她哦</span>：<strong><a href="http://t.qq.com/cameragirl" target="_blank" rel="noopener noreferrer"><span style="color:#ff0000;"><span style="background-color:#99ff99;">t.qq.com/cameragirl</span></span></a></strong></p>
<p>前段时间浙大有个博士做了个&ldquo;<span style="color:#800080;">饮水机娘</span>&rdquo;，也就是他实验室里的饮水机没水或者水加热开了的时候，都会自动发一条微博。这个与&ldquo;物联网&rdquo;扯上了关系的东西，让我原来以为那位博士是改造了饮水机，加上了温度及水位传感器，配合单片机，将饮水机的状态采集到PC中去，再写一个PC上的软件将触发的事件发送到微博上，后来看了相关的介绍，才知道没那么复杂，其实他没有改造饮水机，而是用一个摄像头对准饮水机的状态指示灯，根据指示灯的情况，来判断饮水机的状态。</p>
<p>于是我也就萌生了做一个&ldquo;摄像头娘&rdquo;的念头。<br />
我构想中的&ldquo;摄像头娘&rdquo;是这样的：当有物体在她面前运动的时候，她能感受得到，并且会为这个过客拍一张照片，然后发到微博上。<br />
下面是<span style="color:#ff0000;">实际效果截图</span>：<br />
<span id="more-4341"></span></p>
<div style="text-align: center; ">
	<a href="http://t.qq.com/cameragirl" target="_blank" rel="noopener noreferrer"><img decoding="async" alt="" src="http://www.codelast.com/wp-content/uploads/2012/01/weibo_snapshot.png" style="width: 542px; height: 330px; " /></a></div>
<p>好吧，说得傻一点就是：一个有运动检测（motion detection）功能的程序，当检测到摄像头前有物体在运动时，就将画面拍一张照片，发到微博上。<br />
确实，没啥创意，但是还是有一定实用性的。例如，你可以在家里放置一个&ldquo;她&rdquo;为你看家，假设你运气不好，有不速之客闯进了你家里，那么，只要他进入了&ldquo;摄像头娘&rdquo;的视角，就会马上被检测到，然后被拍上来，发到微博上，后面的事，哼哼，你就有第一手证据了。<br />
<span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
我是用<span style="color:#0000ff;">VC++ 2005</span>开发的这个软件，运行于Win7上，其实它很简单，功能主要分为两部分：运动检测（motion detection）&amp; 发微博，下面分别陈述。<br />
<span style="background-color:#afeeee;">【1】</span>运动检测 / motion detection<br />
从头自己写？那得多笨才能这样做啊！而且我也不是干视频处理这一行的，一时半会写不出来这玩意。<br />
久闻<a href="http://opencv.willowgarage.com/wiki/" target="_blank" rel="noopener noreferrer"><span style="background-color:#faebd7;">OpenCV</span></a>的大名，我知道它可以帮我实现想要的功能，所以毫不犹豫地选择了它。<br />
我以前也从未使用过OpenCV，从下载它的开发包开始，到参照网上的demo写出一个可用的motion detection程序，只花了半天多时间，由此可见OpenCV的强大。<br />
关于OpenCV的介绍，这里只摘取其官网的一句话：</p>
<blockquote>
<p>
		OpenCV (Open Source Computer Vision) is a library of programming functions for real time computer vision.</p>
</blockquote>
<p>没错，大名鼎鼎的机器视觉开发库。<br />
我使用的版本是2.3.1，下载回来之后会看到，它里面已经没有VC++2005的lib了，只有2008及2010的（2005确实太老了），但是试验之后会发现，在VC++ 2005中用2008的lib完全没问题。<br />
<span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
运动检测的基本原理是：<span style="color:#0000cd;">获取摄像头的视频流&rarr;在很短的时间内连续抓取两帧图像&rarr;计算两幅图像的差值&rarr;计算直方图&rarr;判断某些指标是否超过了阈值&rarr;触发动作</span>。我没有图像处理的编码经验，所以也只能解释到这个业余的水平了。<br />
这种功能的代码在网上比比皆是，不过，很多都有陷阱：内存泄漏。基本上来说，都是错误使用cvCloneImage函数造成的。此函数如果放在一个循环中，会导致一次吃掉几M内存（对分辨率不高的图像来说），就算使用了cvReleaseImage函数来释放内存，似乎也没用&mdash;&mdash;应该是对OpenCV的熟悉度不足造成的，用法不对。网上一搜索，就会发现无数人都遇到了这样的问题，那些一篇又一篇的转载文章几乎都是说用同一种方法：以cvCopy来代替cvCloneImage实现同样的功能。<br />
我就是用这种方法解决了内存泄漏问题的，不过，在换成cvCopy之后还有许多其他的问题，一言难尽，看我下面的代码就知道正确的做法了。总之一句话：通过不断Google是可以搞定的这些问题的。<br />
下面，就来看看motion detection的核心代码吧（使用的OpenCV库文件为&nbsp;<span style="color:#008080;">opencv_core231.lib</span>，<span style="color:#008080;">opencv_highgui231.lib</span>，<span style="color:#008080;">opencv_imgproc231.lib</span>）：</p>
<pre class="brush:cpp;first-line:1;pad-line-numbers:true;highlight:null;collapse:false;">
/**
 * Author: Darran Zhang @ codelast.com
 * Date: 2012-01-27
 */

CvCapture* pCapture = cvCreateCameraCapture(0);  // 初始化摄像头 

if(NULL == pCapture) {
  MessageBox(_T(&quot;检测不到摄像头！&quot;), _T(&quot;错误&quot;), MB_ICONERROR);
  return;
}

string strCameraWindowName = &quot;摄像头&quot;;   // 窗口标题 
string strDiffWindowName = &quot;图像差值&quot;;   // 窗口标题 
cvNamedWindow(strCameraWindowName.c_str(), CV_WINDOW_AUTOSIZE); // 创建一个窗口，第二个参数使得用户不能手动改变窗口大小 
cvNamedWindow(strDiffWindowName.c_str(), CV_WINDOW_AUTOSIZE);

IplImage *pFrame = cvQueryFrame(pCapture);      // 随意获取一帧，这是为了通过这一帧取到其宽、高、像素位深、通道数，否则就无法正确创建其他帧图像 
IplImage *pFrameA = NULL;                       // 其中一帧 
IplImage *pFrameB = cvCreateImage(cvSize(pFrame-&gt;width, pFrame-&gt;height), pFrame-&gt;depth, pFrame-&gt;nChannels);     // 其中一帧 
IplImage *pFrameSub = cvCloneImage(pFrameB);    // A、B帧相减之后的帧 

int nDims = 256;     // 划分HIST的个数，越高越精确 
float hRangesArr[] = {0, 255};
float* hRanges = hRangesArr;

IplImage *pGrayscaleImage = NULL;  // 灰度图 
CvHistogram *pHist = cvCreateHist(1, &amp;nDims, CV_HIST_ARRAY, &amp;hRanges, 1);   // 创建直方图 
float fMaxValue = 0.0;

time_t ts = 0;   // 记录时间戳，用于防止在1秒内多次触发运动检测事件 

m_bActive = true;
while(m_bActive)
{
  pFrameA = cvQueryFrame(pCapture);  // 注意：cvQueryFrame返回的指针总是指向同一块内存 
  if(!pFrameA) {
    m_stcSD.strLatestErrMsg = _T(&quot;无法抓取视频帧&quot;);
    SendStatDataUpdateMsg();

    break;
  }

  cvAbsDiff(pFrameB, pFrameA, pFrameSub); // 计算两幅图像之差 
  cvCopy(pFrameA, pFrameB);               // 拷贝图像，第一个参数为源，第二个参数为目标 

  /* 显示摄像头图像 */
  cvMoveWindow(strCameraWindowName.c_str(), 150, 50);   // 设定窗口位置(x，y坐标) 
  cvShowImage(strCameraWindowName.c_str(), pFrameB);    // 显示图像，第2个参数指定了要显示的图像 

  /* 显示差值图像 */
  cvMoveWindow(strDiffWindowName.c_str(), 150, 400);
  cvShowImage(strDiffWindowName.c_str(), pFrameSub);

  /* 转换图像并计算直方图 */
  pGrayscaleImage = cvCreateImage(cvGetSize(pFrameSub), IPL_DEPTH_8U, 1);   // 创建灰度图 
  cvCvtColor(pFrameSub, pGrayscaleImage, CV_BGR2GRAY);                      // 将彩色图像转换为灰阶图像 
  cvCalcHist(&amp;pGrayscaleImage, pHist, 0, 0);                                // 计算直方图 

  /* 判断阈值是否超限，若超限则触发动作 */
  fMaxValue = 0.0;
  cvGetMinMaxHistValue(pHist, 0, &amp;fMaxValue, 0, 0);  // 找最大值，保存到fMaxValue中，第2个参数是最小值，不过我们不用 
  cvConvertScale(pHist-&gt;bins, pHist-&gt;bins, (fMaxValue ? (255.0 / fMaxValue) : 0.0), 0); // 缩放 bin 到区间 [0, 255] 

  double dRealtimeVal = cvGetReal1D(pHist-&gt;bins, 10);
  if (dRealtimeVal &gt; m_dDetectThreshold) {    // 判断是否大于预先设定的阈值 
    CTime ct = CTime::GetCurrentTime();
    time_t tsRef = ct.GetTime();
    if (tsRef - ts &gt;= 1) {
	  //TODO: 在此触发动作 
      ts = tsRef;
    }
  }

  cvReleaseImage(&amp;pGrayscaleImage);   // 释放内存 
  pGrayscaleImage = NULL;

  cvWaitKey(10);   // 等待若干毫秒 
}

cvReleaseCapture(&amp;pCapture);   // 停止捕获并释放摄像头资源 
cvReleaseHist(&amp;pHist);
cvReleaseImage(&amp;pFrameB);
cvReleaseImage(&amp;pFrameSub);

pCapture = NULL;
pHist = NULL;
pFrameB = NULL;
pFrameSub = NULL;
pFrame = NULL;
pFrameA = NULL;

cvDestroyWindow(strCameraWindowName.c_str());    // 销毁窗口 
cvDestroyWindow(strDiffWindowName.c_str());
</pre>
<p><span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
其中有几处要特别注意的代码：<br />
（1）<span style="color:#b22222;">IplImage *pFrameB = cvCreateImage(cvSize(pFrame-&gt;width, pFrame-&gt;height), pFrame-&gt;depth, pFrame-&gt;nChannels);</span><br />
创建B帧图像的时候，后面的参数都是通过pFrame来获取的，如果这几个参数你随意填写，那么就会导致程序编译可通过，运行时崩溃。所以我前面先抓取了一帧，再通过这一帧来获取B帧图像的参数，这样就完全符合了。<br />
（2）cvQueryFrame函数返回的指针总是指向同一块内存&mdash;&mdash;如果你不知道这一点，并且B帧图像是通过cvQueryFrame获取的，那么可能你调试了半天，却发现A帧、B帧的内容始终相同，二者相减得到的结果永远不变，motion detection就不起作用了。所以我把B帧图像用cvCreateImage来创建，A帧用cvQueryFrame来获取，这样就没有问题了。<br />
（3）由于两帧的检测时间较短，所以可能在多个瞬间触发多次动作，为此我根据时间戳做了一些简单的处理，来防止同一秒内触发多次动作。<br />
（4）其他的代码，各位看看就明白了，也无需过多的解释。</p>
<p><span style="background-color:#afeeee;">【2】</span>发微博<br />
我选择的是腾讯微博。<br />
不得不承认，腾讯微博对C++开发者的支持不足，下载回来的开发包里，仅仅同音的错别字就有一堆（可见开发API的同学用的是拼音输入法）。另外，还有各种各样的问题，例如，API Example是无法编译的&mdash;&mdash;原因是ApiType.cpp 和 ApiType.h没有被添加进工程中，导致找不到 CApiType 类定义。再看看它的代码中，编写风格非常随意，让人看了非常难受，总之就一句话，这API你就凑合着用吧！<br />
在动手写程序发微博之前，需要先在腾讯的网页上申请成为开发者，否则你的程序是无法用微博API来发微博的。申请的过程非常简单，当然你必须先有一个QQ号，登录后，在<a href="http://open.t.qq.com/develop.php" target="_blank" rel="noopener noreferrer"><span style="color:#ff0000;">这个页面</span></a>申请。申请之后，你需要在腾讯的网页上点击创建一个<strong><span style="color:#b22222;">客户端应用</span></strong>&mdash;&mdash;尽管这个时候，你还连程序都没有开始写，但是这是先决条件，不这样做的话，你就算写好了程序也用不了，所以我就把这个过程先全部做好了，再开始写程序的事。<br />
<span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
创建客户端应用的页面如下图所示：</p>
<div style="text-align: center; ">
	<a href="http://www.codelast.com" target="_blank" rel="noopener noreferrer"><img decoding="async" alt="create a client app" src="http://www.codelast.com/wp-content/uploads/2012/01/create_client_app.png" style="width: 581px; height: 277px; " /></a></div>
<p>点击之后只需要填写少许内容就可以创建一个客户端应用了。<br />
创建应用之后，你可以看到你所创建的应用的<span style="color:#ff0000;">App Key</span>（一串数字）和<span style="color:#ff0000;">App Secret</span>（数字和字母的混合），这两个字符串在你写程序发微博的时候会用到：</p>
<div style="text-align: center; ">
	<a href="http://www.codelast.com" target="_blank" rel="noopener noreferrer"><img decoding="async" alt="" src="http://www.codelast.com/wp-content/uploads/2012/01/app_info.png" style="width: 350px; height: 280px; " /></a></div>
<p><span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
在获取了以上所需的信息后，用API发微博的过程大致可以描述为：<span style="color:#0000cd;">通过App Key和App Secret跳转到腾讯的页面去获取oauth_verifier&rarr;用户人工输入oauth_verifier&rarr;通过oauth_verifier获取Access Key和Access Secret&rarr;授权通过，可以发微博了</span>。<br />
这个过程的demo，在腾讯微博的API Example中很详细地作了演示，不过，它的编码风格非常不规范，乱就一个字，会耽误开发者的时间。<br />
正因为腾讯微博API Example已经有了例子，所以我在这里就不把发微博相关的代码全部放上来了，只是提醒大家注意以下几点：<br />
（1）你的VC++工程中，只需要引入腾讯微博API中的一个库文件：QWBlogAPI.lib。<br />
（2）你的VC++工程需要以下头文件：</p>
<pre class="brush:plain;first-line:1;pad-line-numbers:true;highlight:null;collapse:false;">
JsonParser.h
UtilString.h
WeiboApi.h
WeiboParam.h
XmlParser.h
weibo.h
</pre>
<p>（3）你的程序运行时，需要以下dll：</p>
<pre class="brush:plain;first-line:1;pad-line-numbers:true;highlight:null;collapse:false;">
curllib.dll
libeay32.dll
openldap.dll
QWBlogAPI.dll
ssleay32.dll
</pre>
<p>这些文件在腾讯微博开发包中都能找到。<br />
（4）发普通微博，option是用<span style="color:#0000ff;">TXWB_T_ADD</span>；发带图片的微博，option是用<span style="color:#0000ff;">TXWB_T_ADD_PIC</span>。图片作为参数添加到CWeiboParam对象中时，是需要特殊处理的（详见API Example）。<br />
（5）微博发不出去时，一定要检查发送内容中的&ldquo;content&rdquo;的字符串是什么编码的！别以为字符串里有内容就是对的，我在这上面折腾了不少时间，就是没注意这个问题。可以用API Example中的<span style="color:#a52a2a;">Unicode2Mbcs</span>函数来转换一个CString到合适的字符串，很管用。<br />
（6）oauth_verifier的值，是在腾讯网页的地址中获取到的，而不是在网页正文中。你跳转到类似于如下的网址后（其实就是腾讯首页）：</p>
<pre class="brush:plain;first-line:1;pad-line-numbers:true;highlight:null;collapse:false;">
http://www.qq.com/?oauth_token=XXX&oauth_verifier=XXX&openid=&openkey=
</pre>
<p>就可以肉眼识别出其值了。<br />
<span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
<span style="background-color: rgb(175, 238, 238); ">【3】</span>软件UI<br />
UI很简单，但是调起来烦人。就截几幅图吧：</p>
<div style="text-align: center; ">
	<a href="http://www.codelast.com" target="_blank" rel="noopener noreferrer"><img decoding="async" alt="" src="http://www.codelast.com/wp-content/uploads/2012/01/cameragirl_ui_1.png" style="width: 438px; height: 324px; " /></a><br />
	&nbsp;</div>
<div style="text-align: center; ">
	<a href="http://www.codelast.com" target="_blank" rel="noopener noreferrer"><img decoding="async" alt="" src="http://www.codelast.com/wp-content/uploads/2012/01/cameragirl_ui_2.png" style="width: 405px; height: 313px; " /></a></div>
<p><span style="color: rgb(255, 255, 255); ">文章来源：</span><a href="http://www.codelast.com/" target="_blank" rel="noopener noreferrer"><span style="color: rgb(255, 255, 255); ">http://www.codelast.com/</span></a><br />
好了，先暂时到这吧，在折腾的道路上...</p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>

			<!--[syntaxhighlighter]-->
			<!--代码高亮，请勿编辑-->
			<script type="text/javascript" src="https://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/syntaxhighlighter/scripts/shCore.js"></script><script type="text/javascript" src="https://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/syntaxhighlighter/scripts/shBrushCpp.js"></script>
<script type="text/javascript" src="https://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/syntaxhighlighter/scripts/shBrushPlain.js"></script>

			<link type="text/css" rel="stylesheet" href="https://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/syntaxhighlighter/styles/shCoreCk.css" />
			<link type="text/css" rel="stylesheet" href="https://www.codelast.com/wp-content/plugins/ck-and-syntaxhighlighter/syntaxhighlighter/styles/shThemeCk.css" />
			<script type="text/javascript">
			SyntaxHighlighter.defaults['class-name']	= '';
			SyntaxHighlighter.defaults['smart-tabs']	= true;
			SyntaxHighlighter.defaults['tab-size']		= 2;
			SyntaxHighlighter.defaults['gutter']		= true;
			SyntaxHighlighter.defaults['quick-code']	= true;
			SyntaxHighlighter.defaults['collapse'] 		= false;
			SyntaxHighlighter.defaults['auto-links']	= true;
			SyntaxHighlighter.defaults['toolbar']		= true;
			SyntaxHighlighter.all();
			</script>
			<!--[/syntaxhighlighter]-->]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b%e6%91%84%e5%83%8f%e5%a4%b4%e5%a8%98%e6%9d%a5%e4%ba%86/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
	</channel>
</rss>
