picamera 1.10 教程及api中文简译(三)picamera的基本使用

来源:互联网 发布:linux查所有进程命令 编辑:程序博客网 时间:2024/06/05 04:53

转自:点击打开链接

4、picamera基本使用方法

如果你是一个Python程序员,那么你将轻松的掌握以下实例,请随时提出改进或新的实例。

4.1、捕捉一个图像输出至文件

使用capture方法可以轻松将捕捉到的图像输出至指定文件。 
下面这个实例是捕捉一个分辨率为1024*768的图像,并将之输出到foo.jpg中:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">768</span>)    camera.start_preview()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#摄像头预热2秒</span>    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    camera.capture(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'foo.jpg'</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

需要注意的是,若目录中有同名文件,picamera将会重置该图片。

4.2、捕捉一个流

这个实例是通过capture()方法将捕捉的一个图像转成一个以jpeg解码的流(bytes流):

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个流</span>my_stream = io.BytesIO()<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 摄像头预热</span>    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    camera.capture(my_stream, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'jpeg'</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

需要注意的是,这不像输出到一个文件,该流捕捉以后会自动关闭脚本,因为在这个实例中没有对流进行其他操作。若对象有flush方法的话,在捕捉完毕后,会调用对象的flush方法,如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 打开一个扩展名为jpg的文件</span>my_file = open(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'my_image.jpg'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'wb'</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    camera.capture(my_file)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 在此时capture会调用my_file的flush方法,完成流封装。</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 但并未关闭文件,需要调用close进行关闭</span>my_file.close()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

上边这个实例需要注意的是,我们并没有指定捕捉文件的解码格式,所以capture会获取输出的文件名的扩展名来寻找解码属性。

4.3、捕捉一个图像转化为PIL imag对象

首先我们要捕捉一个图像流,然后通过流读取将图像的数据转换成PIL image对象。

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> PIL <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> Image<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个流</span>stream = io.BytesIO()<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    camera.capture(stream, format=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'jpeg'</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将指针指向流的开始</span>stream.seek(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)image = Image.open(stream)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

4.4、捕捉一个图像转化为open cv对象

首先我们捕捉一个图像流,然后将图像数据转换为open cv对象:

<code class="hljs haskell has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-import" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io</span><span class="hljs-import" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time</span><span class="hljs-import" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera</span><span class="hljs-import" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> cv2</span><span class="hljs-import" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># 创建一个流</span><span class="hljs-title" style="box-sizing: border-box;">stream</span> = io.<span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">BytesIO</span>()<span class="hljs-title" style="box-sizing: border-box;">with</span> picamera.<span class="hljs-type" style="box-sizing: border-box; color: rgb(102, 0, 102);">PiCamera</span>() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    camera.capture(stream, format='jpeg')<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># 从流构建numpy</span><span class="hljs-typedef" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">data</span> = np.fromstring<span class="hljs-container" style="box-sizing: border-box;">(<span class="hljs-title" style="box-sizing: border-box;">stream</span>.<span class="hljs-title" style="box-sizing: border-box;">getvalue</span>()</span>, dtype=np.uint8)</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># 通过opencv解码numpy</span><span class="hljs-title" style="box-sizing: border-box;">image</span> = cv2.imdecode(<span class="hljs-typedef" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">data</span>, 1)</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;"># opencv解码后返回以RGB解码的图像数据</span><span class="hljs-title" style="box-sizing: border-box;">image</span> = image[:, :, ::-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

如果你不想使用有损JPEG编码,并希望加快这一解码过程的话,可以使用picamera自带的picamera.array模块。可以使用PiRGBArray类简单的捕获’brg’格式的数据。(假定RGB与BGR是分辨率相同的数据,只是具有相反的颜色)

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera.array<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> cv2<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.array.PiRGBArray(camera) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> stream:        camera.capture(stream, format=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'bgr'</span>)        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 此时就可以获取到bgr的数据流了</span>        image = stream.array</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

4.5、调整捕捉图像的分辨率

有时,我们需要将图片进行某种分析或处理,你希望尽可能的捕获比较小分辨率的图像,虽然这种分辨率的调整可以交给PIL或者OpenCV来完成,但是通过picamera可以更搞笑的完成这个操作:

<code class="hljs python has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">768</span>)    camera.start_preview()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 摄像头预热</span>    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    camera.capture(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'foo.jpg'</span>, resize=(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">320</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">240</span>))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

同时调整分辨率的参数也可以适用于捕获视频的start_recording()方法。

4.6、捕获连续图像

您可能希望连续捕捉到的图像的亮度、色彩与对比度上保持一致(例如,这个可能在延迟摄影中非常有用)。可以设置一些属性,确保在多个镜头中保持画面的一致。具体来说,您需要保证摄像头的曝光时间,白平衡和画面增益都是固定的。

  • 设置曝光时间:shutter_speed
  • 设置画面增益:首先将 exposure_mode设置为’off’然后将analog_gain和digital_gain设置在合理的范围值。
  • 设置白平衡:将awb_mode设置为’off’,然后将awb_gains设置为red或者blue或者直接设置iso的值。

设置这些属性是非常专业的,并且非常难调整到合适的范围值。在白天,对于iso,100~200是一个简单的合理范围,而在低光环境下,需要调整到400~800。对于shutter_speed如果需要确定一个合理的范围值可以直接查询exposure_speed属性。对于曝光增益,通常只需要将analog_gain设置为大于1的值(analog_gain的默认值为1,但这将产生一个全黑的图像帧)。

下面的这个例子提供了一些简单配置的实例:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1280</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 等待摄像头预热,适应光线环境</span>    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 现在设置图像修正值</span>    camera.shutter_speed = camera.exposure_speed    camera.exposure_mode = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'off'</span>    g = camera.awb_gains    camera.awb_mode = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'off'</span>    camera.awb_gains = g    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 最后将采取修正值的图像输出到文件</span>    camera.capture_sequence([<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'image%02d.jpg'</span> % i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>)])</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>

4.7、捕获延时拍摄序列

有一种需求就是,每若干分钟捕获一张图像,并存储起来,若像实现这种需求最简单的方法就是capture_continuous()函数。调用这个函数时,会不断捕捉摄像头图像,知道调用停止函数。这样你可以很轻易的控制定时捕获两张图片之间的时间。 
接下来这个例子就是演示每5分钟定时抓拍一张图片:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> filename <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> camera.capture_continuous(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'img{counter:03d}.jpg'</span>):        print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Captured %s'</span> % filename)        time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">300</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 休眠5分钟</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

除了延时捕获图像以外,还可以通过datetime来计算时间,在特定的时间开启摄像头捕获图像。

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> datetime <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> datetime, timedelta<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">wait</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>:</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 计算时间,将从下一个小时开始捕获图像</span>    next_hour = (datetime.now() + timedelta(hour=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)).replace(        minute=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, second=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, microsecond=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)    delay = (next_hour - datetime.now()).seconds    time.sleep(delay)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.start_preview()    wait()    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> filename <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> camera.capture_continuous(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'img{timestamp:%Y-%m-%d-%H-%M}.jpg'</span>):        print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Captured %s'</span> % filename)        wait()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>

4.8、在光线比较弱的环境下捕获图像

树莓派的摄像头可以在光纤比较弱的环境下捕获图像,其主要的实现方式是通过设置捕获属性,给摄像头设置一个比较高的光线增益,以及增加曝光的时间以让摄像头接收尽可能多的光。我们可以通过设置shutter_speed[设置曝光时间]与framerate[帧率]两个参数。首先我们要设置一个比较慢的帧率,然后将曝光时间设置为6秒来捕获图像:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> time <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> sleep<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> fractions <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> Fraction<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1280</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 设置帧率为1/6fps,然后将曝光时间设置为6秒</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 最后将iso参数设置为800</span>    camera.framerate = Fraction(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>)    camera.shutter_speed = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6000000</span>    camera.exposure_mode = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'off'</span>    camera.iso = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">800</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 给摄像头一个比较长的预热时间,让摄像头尽可能的适应周围的光线</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 你也可以试试开启AWB【自动白平衡】来代替长时间的预热</span>    sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 最后捕捉图像,因为我们将曝光时间设置为6秒,所以拍摄的时间比较长</span>    camera.capture(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'dark.jpg'</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>

如果在一个光线不是特别暗的地方使用以上实例,则你会得到一个严重曝光以至于可能是全白的图像文件。

因为我们设置了一个比较长的曝光时间,如果这时移动摄像头,那么我们将会得到一个严重图像扭曲的照片。

4.9、将捕获的流转换为网络流

这是一个将捕获的图片通过网络传给服务器的例子。在这个例子中我们有两个脚本:服务器端,树莓派端。然后通过socket进行连接。我们使用一种简单的数据包协议。首先我们数据包的前4个字节是类型为int值的数据,代表图像数据的长度,然后是图像的数据。若收到的数据长度为0,则代表picamera已经停止捕获图像。 
数据包格式如下: 
这里写图片描述 
首先在服务器运行一下脚本(这个脚本是基于PIL包来解析jpeg文件,你也可以使用其他的图形库,比如opencv或graphicsMagick等来替代PIL):

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> socket<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> struct<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> PIL <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> Image<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 启动socket,设置监听端口为8000,接受所有ip的连接</span>server_socket = socket.socket()server_socket.bind((<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'0.0.0.0'</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span>))server_socket.listen(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 接受一个客户端连接</span>connection = server_socket.accept()[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].makefile(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'rb'</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>:        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 读取我们的包头,也就是图片的长度</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 如果长度为0则退出循环</span>        image_len = struct.unpack(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'<L'</span>, connection.read(struct.calcsize(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'<L'</span>)))[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">not</span> image_len:            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 构造一个流来接受客户端传输的数据</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 开始接收数据并写入流</span>        image_stream = io.BytesIO()        image_stream.write(connection.read(image_len))        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将流的指针指向开始处,并通过PIL来读入流</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 并将之存储到文件</span>        image_stream.seek(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)        image = Image.open(image_stream)        print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Image is %dx%d'</span> % image.size)        image.verify()        print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Image is verified'</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:    connection.close()    server_socket.close()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>

树莓派脚本如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> socket<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> struct<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 连接之前创建的服务器端</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将my_server替换成服务器的ip</span>client_socket = socket.socket()client_socket.connect((<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'my_server'</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个连接</span>connection = client_socket.makefile(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'wb'</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:        camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 摄像头预热 </span>        camera.start_preview()        time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 记录一个开始时间,并构建一个流来存储捕获的图片数据</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 我们可以直接讲捕获的数据流传给服务器,但为了捕获我们的图像长度,</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 我们暂且阻碍传输,并等待捕获完成,并获取图长度组建数据包</span>        start = time.time()        stream = io.BytesIO()        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> foo <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> camera.capture_continuous(stream, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'jpeg'</span>):            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将数据写入流中</span>            connection.write(struct.pack(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'<L'</span>, stream.tell()))            connection.flush()            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将数据流的指针指向起始位置</span>            connection.write(stream.read())            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 如果我们的等待的连接时间大于30秒则退出循环</span>            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> time.time() - start > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>:                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 重置捕获流,等待下一次捕获图像。</span>            stream.seek(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)            stream.truncate()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 循环结束,写一个长度为0的数据包,告知服务器我们已经完成了整个操作。</span>    connection.write(struct.pack(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'<L'</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>))<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:    connection.close()    client_socket.close()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul>

4.10、录制视频文件

录制一个视频文件很简单:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    camera.start_recording(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'my_video.h264'</span>)    camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span>)    camera.stop_recording()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

请注意,我们在这里使用的方法是wait_recording,而不是time.sleep(),以下的例子也是使用这个方法来演示,虽然功能上与time.sleep相同,但是wait_recording会不断的监听错误的抛出(比如磁盘空间不足),一旦出现错误会立即暂停捕获图像,来处理当前的错误,而不是在sleep以后才进行处理。所以如果我们用time.sleep来替代wait_recording方法的话,这种错误只能在stop_recording()后才能被处理,这可能导致了我们未能及时处理错误,导致图像数据捕获失败。

4.11、将录制的视频转换为数据流

这个例子与将录制的视频存储到文件很像:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamerastream = io.BytesIO()<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    camera.start_recording(stream, format=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'h264'</span>, quality=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">23</span>)    camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>)    camera.stop_recording()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

在这里,我们设置了一个视频质量参数quality,指示解码器将图像质量维持在23左右。H.264视频编码主要取决于两个参数:

  • 视频输出是以秒为单位,单位时间内输出的视频最大则质量越高,视频输出的默认缺省为17000000(17Mbps)最大值为25000000(25Mbps)。我们设置的参数越大,则解码器会在相应的品质上进行解码。你可能会发现,除非你使用更高的分辨率,否则在默认情况下是不需要限制视频质量的。
  • 质量参数通知解码器保持什么水平的图像进行录制。quality参数值的的范围是1(最高质量)~40(最低质量),在普通的4M宽带下,将视频质量设置为20~25之间是合理范围。

4.12、录制多个视频文件

如果你希望将视频文件分割多个进行录制,可以使用split_recording()方法来实现这个功能:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    camera.start_recording(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'1.h264'</span>)    camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">11</span>):        camera.split_recording(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'%d.h264'</span> % i)        camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>)    camera.stop_recording()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

在实例中,我们通过split_recording函数来分割录制10个视频文件,每个视频文件的时间为5秒。

也可以利用record_sequence()函数来实现这个功能,而且代码更加简洁:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> filename <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> camera.record_sequence(            <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'%d.h264'</span> % i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">11</span>)):        camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

record_sequence这个方法适用于1.3以后的版本。

4.13、循环录制

这个功能类似于将录制的视频转换成文件流,区别是,picamera将产生一个loop缓冲区,如果在缓冲区已满,则picamera会将最开头的视频替换掉,以保证在缓冲区的视频是最新的。

一个典型的例子,就是安全监控实例,在这个实例中,我们希望检测到视频内有移动的物体,然后将这段视频记录起来。本例中我们先进行录制20秒的视频,并将其存储到文件流中,直到write_now返回true才会将这个缓存区域存储起来(这段实现比较多样,我们可以使用任意一个检测图像运动的算法来实现这个例子)。如果我们检测到有移动的物体,那么我们将刷新缓存中录制10秒的视频,并将该视频保存至磁盘:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> io<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> random<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">write_now</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>:</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 在这我们做一个假的例子,产生一个随机的true来代替检测到运动的物体</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> random.randint(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>) == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">write_video</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(stream)</span>:</span>    print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Writing video!'</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> stream.lock:        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 找到视频的起始端</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> frame <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> stream.frames:            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> frame.frame_type == picamera.PiVideoFrameType.sps_header:                stream.seek(frame.position)                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将流输出到磁盘</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> io.open(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'motion.h264'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'wb'</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> output:            output.write(stream.read())<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    stream = picamera.PiCameraCircularIO(camera, seconds=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>)    camera.start_recording(stream, format=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'h264'</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>:            camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> write_now():                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 检测到移动的物体</span>                <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 进行10秒的录制,并将录制的视频存放至缓存区</span>                camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>)                write_video(stream)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:        camera.stop_recording()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li></ul>

在上面的示例中,我们使用了线程锁,以防止我们在保存视频时缓存区的录像被修改(因为我们创建的缓存流是一个loop缓冲区,是可以读写覆盖的)。如果没有使用with语句块,那么我们在写入完成时,应该取消对缓存的stream.lock锁。

需要注意的是,缓存区最少要有20秒的视频,因为使用H.264解码的话,最小码率为17Mbps,所以超过或等于20秒的视频流才是可用的视频。

这功能支持1.0及以后版本。

4.14、将录制的视频用于网络传输

这个功能类似于录制视频流,但区别在于,我们将创建一个socket对象,这不像我们传输图像的数据协议那么复杂,我们并不需要对视频流进行数据包的封装。这一次,我们将持续发送视频的帧组成的数据流,以便简化我们的socket视频通讯。

首先我们开始编写服务器端脚本:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> socket<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> subprocess<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 首先我们创建一个socket监听,端口为8000,接受所有的ip连接</span>server_socket = socket.socket()server_socket.bind((<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'0.0.0.0'</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span>))server_socket.listen(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 然后我们创建一个socket文件流</span>connection = server_socket.accept()[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].makefile(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'rb'</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 如果接受到一个客户端连接,那么我们将通过终端来打开一个播放器。</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 如果你使用的是mplayer,则需要注释掉vlc这段。</span>    cmdline = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'vlc'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'--demux'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'h264'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'-'</span>]    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#cmdline = ['mplayer', '-fps', '25', '-cache', '1024', '-']</span>    player = subprocess.Popen(cmdline, stdin=subprocess.PIPE)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>:        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个死循环,每次读取1k的数据</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 然后将数据传送到播放器</span>        data = connection.read(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1024</span>)        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">not</span> data:            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>        player.stdin.write(data)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:    connection.close()    server_socket.close()    player.terminate()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>

注意,如果你是在Windows上运行此代码,则需要提供完成播放器exe文件路径。

你可能会注意到,播放的视频有几秒钟的延迟,不用担心,这是正常现象,因为媒体播放器为了能够流畅的播放视频,会事先换成几秒的视频流,以防止网络卡顿。但是一些播放器(比如mplayer)允许用户跳过缓存或减少缓冲区直接播放视频,虽然这将提高了播放的卡顿和中断播放的现象,但是视频的延迟将大大减少。

现在我们来编写树莓派端代码:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> socket<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个socket连接,来连接我们的服务器,这里需要将my_server替换成服务器的ip</span>client_socket = socket.socket()client_socket.connect((<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'my_server'</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个socket文件流</span>connection = client_socket.makefile(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'wb'</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:        camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)        camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 开启摄像头,并预热两秒</span>        camera.start_preview()        time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 开始录制并传输,录制视频总长度为60秒</span>        camera.start_recording(connection, format=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'h264'</span>)        camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span>)        camera.stop_recording()<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:    connection.close()    client_socket.close()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>

还可以指出的是,我们能够利用netcat和raspivid命令来快速实现这段脚本,在终端上运行以下代码:

<code class="language-linux hljs lasso has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">server<span class="hljs-attribute" style="box-sizing: border-box;">-side</span>: nc <span class="hljs-attribute" style="box-sizing: border-box;">-l</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">|</span> vlc <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">--</span>demux h264 <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-</span>client<span class="hljs-attribute" style="box-sizing: border-box;">-side</span>: raspivid <span class="hljs-attribute" style="box-sizing: border-box;">-w</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span> <span class="hljs-attribute" style="box-sizing: border-box;">-h</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span> <span class="hljs-attribute" style="box-sizing: border-box;">-t</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60000</span> <span class="hljs-attribute" style="box-sizing: border-box;">-o</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">|</span> nc my_server <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

然而,我们可以将连接反过来,通过树莓派简历一个视频服务器,等待播放器的连接。当连接简历时,我们会录制60秒的视频,并实时传输过去。这样我们可以先初始化摄像头的连接,等待播放器的接入:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> socket<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>    server_socket = socket.socket()    server_socket.bind((<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'0.0.0.0'</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8000</span>))    server_socket.listen(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个socket文件流</span>    connection = server_socket.accept()[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].makefile(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'wb'</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:        camera.start_recording(connection, format=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'h264'</span>)        camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span>)        camera.stop_recording()    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:        connection.close()        server_socket.close()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>

然后我们可以通过播放器来打开这个网络地址,这里演示的是利用vlc来打开摄像头:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">vlc tcp<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/h264:/</span><span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">/my_pi_address:8000/</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

注意的是,目前,VLC或mplayer都不会对视频流进行GPU解码,他们会先尝试利用CPU进行解码,但这种软解码的效率不够强大。所以为了能够顺利播放,你需要将播放器运行在一个性能比较好的设备上(废话。。。)

4.15、在捕捉的图像上叠加图片

在摄像头进行捕捉的同时我们可以运行多层渲染器,然而picamera只允许加载单个渲染器到相机端,所以如果想在捕获的图像上叠加图片,我可以需要创建一个附加的渲染器来显示我们捕捉到的静态图像。

注意,picamera不支持在捕捉图像或拍摄视频的同时来叠加图像信息,如果需要嵌入一些文字信息请参阅下面的“在捕捉的图像上叠加文字信息”

叠加图片工作是一个比较复杂的操作,因为摄像头模块的大小是32X16,所以渲染的图片的宽度必须是32的倍数,其高度必须是RGB格式所规定的字节。不过虽然听上去很复杂,但是实现起来却很简单。

下面这个实例演示的是,加载任意一个图像或PIL,让他扩展到RGB允许的尺寸,这将调用add_overlay()函数:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> PIL <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> Image<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> time <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> sleep<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1280</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>    camera.start_preview()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 读取任意一张图片</span>    img = Image.open(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'overlay.png'</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个新的RGB渲染器,并指定渲染器的格式</span>    pad = Image.new(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'RGB'</span>, (        ((img.size[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">31</span>) // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span>) * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">32</span>,        ((img.size[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] + <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>) // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>) * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>,        ))    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将原始图片加载到渲染器中</span>    pad.paste(img, (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>))    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 在这里我们使用原始图片的尺寸来进行叠加</span>    o = camera.add_overlay(pad.tostring(), size=img.size)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 在默认情况下,图片将叠加在第0层上,下方是我们的摄像头图片层(第2层)</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 这里我们将图片设置为盘透明并覆盖在捕捉的图像上</span>    o.alpha = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">128</span>    o.layer = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个死循环,等待用户终止脚本</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>:        sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

我们可以不使用一个图片文件作为叠加源,我们可以直接从numpy中产生叠加图片数据。在下面的例子中,我们构建了一个numpy 以捕捉图片相同的分辨率覆盖在图片上,并在重心画一个白色的十字以标示出我们的覆盖物。

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 创建一个numpy空间,指定分辨率为1280*720,并在画面中间画一个十字</span>a = np.zeros((<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1280</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>), dtype=np.uint8)a[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">360</span>, :, :] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span>a[:, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, :] = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0xff</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1280</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>    camera.start_preview()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 我们通过add_overlay直接将覆盖物叠加在第3层上,这里我们可以省略覆盖物的尺寸</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 默认为捕获图片的尺寸</span>    o = camera.add_overlay(np.getbuffer(a), layer=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>, alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">64</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span>:        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 等待用户终止脚本</span>        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>:            time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">finally</span>:        camera.remove_overlay(o)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>

我们可以调成layer参数以隐藏渲染器(layer默认为2),或者可以通过alpha参数设置渲染器的透明度和调整渲染器的大小,使渲染器不用拉伸显示在界面上。我们也可以通过叠加图片来构建简单的用户界面。

这功能支持1.8及以后版本。

4.16、在捕捉的图像上叠加文字

相机模块包含一个基本的注释工具,它最多可允许在图片上叠加255个ASCII字符(包括在图片或视频的捕捉中或捕捉后进行叠加)。想要实现这一功能,只需要将需要叠加的文字填在annotate_text参数上:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>    camera.start_preview()    camera.annotate_text = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Hello world!'</span>    time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将图片输出到文件</span>    camera.capture(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'foo.jpg'</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

我们也可以通过一点技巧来显示比较长的字符串:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> itertoolss = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"This message would be far too long to display normally..."</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">640</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>    camera.start_preview()    camera.annotate_text = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">31</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> c <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> itertools.cycle(s):        camera.annotate_text = camera.annotate_text[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">31</span>] + c        time.sleep(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.1</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

当然,这个功能也可以用在显示或嵌入录像的时间戳(该实例还演示了在绘制的时间戳下利用annotate_background属性填充背景色):

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> datetime <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> dt<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    camera.resolution = (<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1280</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>)    camera.framerate = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>    camera.start_preview()    camera.annotate_background = picamera.Color(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'black'</span>)    camera.annotate_text = dt.datetime.now().strftime(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'%Y-%m-%d %H:%M:%S'</span>)    camera.start_recording(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'timestamped.h264'</span>)    start = dt.datetime.now()    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (dt.datetime.now() - start).seconds < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>:        camera.annotate_text = dt.datetime.now().strftime(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'%Y-%m-%d %H:%M:%S'</span>)        camera.wait_recording(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.2</span>)    camera.stop_recording()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

该功能支持1.7及以后版本。

4.17、控制摄像头的led指示灯

摄像头的led指示灯指示了该摄像头模块在开启中,但是在某种情况下,这可能会是一个障碍,比如你在拍摄野外动物的情况下,这个led灯可能会吓跑动物,而且在近距离拍摄的时候,可能会将led的灯光反射到摄像头上。

你可以利用一些简单的方式来解决,比如用胶带或者一些遮挡物来挡住led灯,也可以通过picamera来设置disable_camera_led属性关闭led指示灯。

但是这种操作需要有RPi.GPIO库的支持,以及提供运行该python脚本足够的权限(这意味着你将需要通过root身份来运行这段脚本)才可以控制Led灯的属性。

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> picamera<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">with</span> picamera.PiCamera() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> camera:    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将led指示灯设置为关闭</span>    camera.led = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">False</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 这时拍照时指示灯不会亮起</span>    camera.capture(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'foo.jpg'</span>)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

这里需要注意的是,当你第一次使用led属性来控制指示灯时,GPIO库将设置为BCM模式[GPIO.setmode(GPIO.BCM)]和禁止使用警示灯[GPIO.setwarnings(False)],所以这将使你无法控制板载led灯,如果想控制则需要手动开启。


0 0
原创粉丝点击