AoboSir 博客

与15年前的我比,我现在是大人;与15年后的我比,我现在还是个婴儿

Python 网络爬虫 011 (高级功能) 支持代理proxy — 让爬虫可以翻墙爬取网站

支持代理

  • 使用的系统:Windows 10 64位
  • Python 语言版本:Python 2.7.10 V
  • 使用的编程 Python 的集成开发环境:PyCharm 2016 04
  • 我使用的 urllib 的版本:urllib2

注意: 我没这里使用的是 Python2 ,而不是Python3


一 . 前言

在国内一些网站已经被屏蔽,比如googleFacebook等等。如果我们想要访问这些被屏蔽的网站,需要翻墙,术语叫:代理。简单的说就是,我们访问这些网站都是通过国内的服务器来访问这些网站,但是在你与服务器之间有一道长城防火墙,它会判断你访问的这个网站是不是在屏蔽列表里的网站。假如你现在访问google网站,长城防火墙就会屏蔽这个网站,不让你访问它。 那么代理又是什么呢? 简单的说就是你不是直接访问的google网站,而是访问的国外的一个服务器。你在电脑上输入google的网站后,信息的运输是这样的: 国外服务器接受到你访问的网站,它帮你访问,然后将访问得到的结果返回给你。

二 . 测试

我们可以使用 urllib2 支持代理。

1
2
3
4
5
proxy = ...
opener = urllib2.build_opener()
proxy_params = {urlparse.urlparse(url).scheme: proxy}
opener.add_handler(urllib2.ProxyHandler(proxy_params))
response = opener.open(request)

三 . 代码

代码在这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#-*- coding:utf-8 -*-

import urllib2
import chardet
import urlparse

def download(url, user_agent='wswp', proxy=None, num_retries=2):
    print 'Downloading: ', url
    headers = {'User-agent' : user_agent}
    request = urllib2.Request(url, headers=headers)

    opener = urllib2.build_opener()
    if proxy:
        proxy_params = {urlparse.urlparse(url).scheme: proxy}
        opener.add_handler(urllib2.ProxyHandler(proxy_params))
    try:
        html = opener.open(request).read()
        charset = chardet.detect(html)['encoding']
        if charset == 'GB2312' or charset == 'gb2312':
            html = html.decode('GBK').encode('GB18030')
        else:
            html = html.decode(charset).encode('GB18030')
    except urllib2.URLError as e:
        print 'Download error', e.reason
        html = None
        if num_retries > 0:
            if num_retries > 0:
                if hasattr(e, 'code') and 500 <= e.code < 600:
                    # recursively retry 5xx HTTP errors
                    return download(url, user_agent, proxy, num_retries-1)
    return html

四 . 运行

如何使用这个最新的 download() 函数。download() 函数里面的形参 proxy 究竟要传入什么?

如果直接运行:

1
>>> download('https://www.google.co.jp/')

输出:

1
2
Downloading:  https://www.google.co.jp/
Download error [Errno 11002] getaddrinfo failed

现在,我们启动proxy代理:

Alt text

proxy 的本地端口为:127.0.0.1:1080

所以,我们给download() 函数的 proxy 参数的值设置为:127.0.0.1:1080

1
>>> download('https://www.google.co.jp/', proxy='127.0.0.1:1080')

成功输出了google日本的网站源代码:

Alt text


五 . 讲解代码中重点部分

1
2
3
if proxy:
    proxy_params = {urlparse.urlparse(url).scheme: proxy}
    opener.add_handler(urllib2.ProxyHandler(proxy_params))

如果用户给proxy参数赋值了,那么就执行里面的代码。

其中urlparse.urlparse(url).scheme 得到的是网页的协议类型,比如:httphttpsftp等等。

所以proxy_params = {urlparse.urlparse(url).scheme: proxy}这句代码现在这个情况就等于:proxy_params = {'https', '127.0.0.1:1080'}。所以,proxy_params是一个字典,里面存放在代理的端口号。

urllib2包中有ProxyHandler类,通过此类可以设置代理访问网页。

所以,上面完整的代码所执行的功能,和下面这一小段代码执行所得到的效果是一样的:

1
2
3
4
5
6
7
8
9
10
11
#coding=utf8

import urllib2
import chardet

proxy = urllib2.ProxyHandler({'https': '127.0.0.1:1080'})
opener = urllib2.build_opener(proxy)
html = opener.open('https://www.google.co.jp/').read()
charset = chardet.detect(html)['encoding']

print html.decode(charset).encode('GB18030')

参考网站:

http://outofmemory.cn/code-snippet/2625/python-urllib2-usage-ProxyHandler-through-Proxy-call-wangye

Git(GitHub) 007 如何删除一个库


来到将要删除的库:

Alt text

点击右上角的 Settings

Alt text

调到 Settings网页,拉倒最后,你会看到下面这个样子:

Alt text

点击 Delelte this repository 按钮。

弹出下面的提示窗口:

Alt text

意思是说:

你是否真的真的真的要这样做?

如果你不阅读下面这些东西的话,不好的事情可能会意外地发生!

这个动作不能撤消。这将永久删除AoboJaing/ AoboJaing.github.io库,维基,问题和评论,并删除所有合作者协会。

为了再次确认,请输入资源库的名称。

所以我如果真的想要删除这个资源库的话,输入这个资源库的名称,再点击 I understand the consequences, delete this repoitory 按钮。


Git(GitHub) 006 如何新建一个库


GitHub网页,登录你的 GitHub 账号 之后。

点击右上角的图标 -> 然后选择 Your profile

Alt text

接着点击: Repositories

Alt text

现在,点击 New

Alt text

现在,你就可以输入你要创建的资源库的名称了:

Alt text

输入完成之后,点击 Create repository 按钮

Alt text

OK,搞定

现在你所看到的,说明这个库里面什么都没有。

Alt text

Git(GitHub) 005 添加SSH密钥 — 解决:Permission Denied (Publickey) Fatal the Remote End Hung Up Unexpectedly 问题


当你下载一个源代码的时候。出现下面错误:

1
2
3
4
5
ubuntu@ubuntu:~/catkin_ws/src$ git clone git@github.com:turtlebot/turtlebot.git
Cloning into 'turtlebot'...
Permission denied (publickey).
fatal: The remote end hung up unexpectedly
ubuntu@ubuntu:~/catkin_ws/src$ 

此时需要添加SSH密钥。步骤如下:

参考网址:Generating an SSH key

步骤

先检查现有的SSH密钥

1
ls -al ~/.ssh

输出:

1
2
3
4
total 12
drwx------  2 ubuntu ubuntu 4096 Dec 24 07:40 .
drwxrwxr-x 32 ubuntu ubuntu 4096 Dec 24 07:29 ..
-rw-r--r--  1 ubuntu ubuntu  884 Dec 24 07:40 known_hosts

默认的,公钥的文件名可能是下面的几个:

1
2
3
4
id_dsa.pub
id_ecdsa.pub
id_ed25519.pub
id_rsa.pub

如果你现在没有公有的或者私有的钥匙,或者你不希望使用现有的任何一个去连接GitHub,这个时候,你可以去生成一个新的SSH密钥(SSH key)

如果你在上面的输出中看到了现有的公有和私有的密钥(比如: id_rsa.pubid_rsa),这个时候,你可以直接连接GitHub,你可以将你的SSH密钥添加到ssh-agent。

生成一个新的SSH密钥(SSH key)

当你查看了你现有的密钥后没有SSH密钥,现在你可以来生成一个新的SSH密钥,用来身份验证。然后在将它添加到ssh-agent。

添加你的GitHub使用的e-mail地址:

1
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

这是会创建一个新的SSH密钥,使用提供的电子邮件作为标签。

1
Generating public/private rsa key pair.

此时提示你:“输入一个用来保存钥匙的文件”,默认保存在/Users/you/.ssh/id_rsa,我们直接按回车键。(它保存的位置跟你当前路径没有关系,默认都是保存在~/.ssh/id_rsa路径(即/home/ubuntu/.ssh/id_rsa)里面。)

1
Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa): 

接下来,它提示你输入密码短语(passphrase),如果你直接按回车,就是没有密码。我们可以输入123456:(详细的信息:这里

1
2
Enter passphrase (empty for no passphrase): [Type a passphrase]
Enter same passphrase again: [Type passphrase again]

现在,密钥就生成了。

Alt text


如果你不想在每次都使用你的SSH密钥重新输入你的密码短语,现在,你需要将你的密钥添加到SSH 代理(SSH Agent)中,它会管理你的SSH密钥,并记住你的密码短语。


添加你的密钥(SSH key)到ssh-agent

在你添加一个新的SSH密钥到ssh-agent去管理你的密钥之前,我们查看一下当前新生成的密钥:

1
ls -al ~/.ssh

Alt text


现在启动 ssh-agent(SSH代理),如果它还没有运行的话。

1
2
3
# start the ssh-agent in the background
$ eval "$(ssh-agent -s)"
Agent pid 2117

Alt text

这个时候,将你的SSH密钥添加到 ssh-agent。

1
ssh-add ~/.ssh/id_rsa

如果你你给你的SSH密钥设置了密码短语,你需要在输出提示Enter passphrase for /home/ubuntu/.ssh/id_rsa:时,输入密码短语(passphrase )。

Alt text

将SSH密钥添加到你的GItHub账户上

参考网址:Adding a new SSH key to your GitHub account

为了配置你的GitHub账户去使用你的新的SSH密钥,你需要将SSH密钥添加到你的GitHub账户上。

第一步:复制共有密钥到剪切板上:

1
2
3
4
5
$ sudo apt-get install xclip
# 下载并安装 xclip. 如果你没有 `apt-get` 工具, 你可以使用其他的下载工具 (比如 `yum`)

$ xclip -sel clip < ~/.ssh/id_rsa.pub
# 复制 id_rsa.pub 文件里面的内容到你的剪切板里

注意,如果xclip工具不工作, 你可以直接手动复制。

Alt text

cat ~/.ssh/id_rsa.pub

Alt text

再任何一个GitHUb页面右上角 你的用户图标 -> Settings :

Alt text

在用户设置侧边栏中,点击SSH and GPG keys

Alt text

点击 New SSH key

Alt text

输入这个SSH密钥的标题 和 公有密钥,然后点击 Add SSH key

Alt text

输入GitHub账户的密码:

Alt text

添加成功:

Alt text

测试你的SSH连接

参考网站:Testing your SSH connection

1
2
3
4
ubuntu@ubuntu:~$ ssh -T git@github.com
Warning: Permanently added the RSA host key for IP address '192.30.253.113' to the list of known hosts.
Hi AoboJaing! You've successfully authenticated, but GitHub does not provide shell access.
ubuntu@ubuntu:~$

成功了。

我们现在再来重新测试最上面的命令:

1
git clone git@github.com:turtlebot/turtlebot.git

Alt text

如果你在之前创建密钥的时候,给密钥添加的密码短语的话,在你执行git clone XXX的时候可能会让你输入密码短语:

Enter passphrase for key '/home/ubuntu/.ssh/id_rsa':

你现在可能会发现,下载速度好像有点慢啊。如何给Git提速呢。请参考这篇博客


当你使用了git,在你的GitHub账号的SSH keys管理的页面里面,可以看到:(它变绿了。)

Alt text


你现在可以执行下面的命令,查看当前你的git的配置。

1
2
ubuntu@ubuntu:~/catkin_ws/src$ git config --list
ubuntu@ubuntu:~/catkin_ws/src$ 

如果里面什么都没有,想我现在这个样子。你可以去完善你的git配置。请参考这个网页


Git(GitHub) 004 配置代理 目的:clone提速


你如果没有翻墙,就算通过本篇博客对你的Git进行了配置,也是没有一点效果的。

在终端中执行:

1
2
$ git config --global http.proxy http://127.0.0.1:1080
$ git config --global https.proxy https://127.0.0.1:1080

查看一下:

1
$ git config --list

对于我现在使用的Windows 系统而言,输出是下面这个样子的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
core.symlinks=false
core.autocrlf=true
core.fscache=true
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
help.format=html
http.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
diff.astextplain.textconv=astextplain
rebase.autosquash=true
credential.helper=manager
filter.lfs.clean=git-lfs clean %f
filter.lfs.smudge=git-lfs smudge %f
filter.lfs.required=true
user.name=AoboJaing
user.email=744910955@qq.com
https.proxy=https://127.0.0.1:1080
http.proxy=http://127.0.0.1:1080

现在测试下载一个源代码试试看:(速度马上提上来)

Alt text

搞定


注意: 错误的做法:

1
2
$ git config --global http.proxy 'socks5://127.0.0.1:1080'
$ git config --global https.proxy 'socks5://127.0.0.1:1080'

参考网站:

Git(GitHub) 003 如何 Clone 非 Master 分支的代码 — 切换到指定 Branch分支 或者 Tag版本



切换到指定 branch (分支)


举例

我们的目的是:得到 https://github.com/turtlebot/turtlebot_viz 网址里面的groovy分支的源代码:

Alt text

第一步:git源代码到本地。(注意: 不是Download ZIP,它只是下载master分支的源代码,不会下载所有分支的源代码)

Alt text

1
git clone git@github.com:turtlebot/turtlebot_viz.git

Alt text

第二步:查看所有分支

1 . 绿色的表示本地当前分支

2 . 红色的表示远程的分支。

3 . origin/HEAD -> origin/hydro 指:远程库的当前分支是hydro

Alt text

1
git branch -a

Alt text

第三步:切换到指定分支,比如groovy

1
git checkout groovy

切换到指定 tag (版本)

举例

我们的目的是:得到 https://github.com/ros-drivers/freenect_stack 网址里面 freenect-stack-0.2.2 版本。

Alt text

克隆

1
git clone git@github.com:ros-drivers/freenect_stack.git

Alt text

1
2
cd freenect_stack
git tag

Alt text

1
git checkout freenect-stack-0.2.2

Alt text


总结:其实tag和 branch是一样的操作。

如果你感觉使用git clone XXX 下载源代码的速度太慢了,你可以参考这篇博客来配置你的git,让它提速。


参考网站:

C++ String 、char 、char *、wstring、wchar_t * 、wchar_t 之间的转换


charwchar_t 之间的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <iomanip>

int main(void)
{
  char c = 'a';
  std::cout << c << std::endl;
  //char -> wchar_t
  wchar_t wc = (wchar_t)c;
  std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << wc << std::endl;
  //wchar_t -> char
  char c_ = (char)wc;
  std::cout << c_ << std::endl;
  
  system("pause");
  return 0;
}

输出:

1
2
3
4
a
U+0061
a
请按任意键继续. . .

Unicode编码表:A-Z,a-z,0-9的unicode编码表

stringwstring 之间的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>
#include <iomanip>

int main(void)
{
  std::string str = "HelloWorld";
  std::cout << str << std::endl;
  //string -> wstring
  std::wstring wstr;
  wstr.assign(str.begin(), str.end());
  // std::cout << wstr.c_str() << std::endl; //error 这样是打印不出来的
  //std::cout << wstr.c_str() << std::endl; //error 编译不报错,但是它打印的是wstr第一个字符的地址
  //打印 success
  std::cout << "Unicode is ";
  for(int i=0; i<wstr.length(); i++){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << wstr[i] << " ";
  }
  std::cout << std::endl;
  //打印 end

  //wstring -> string
  std::string str_;
  str_.assign(wstr.begin(), wstr.end());
  std::cout << str_ << std::endl;

  system("pause");
  return 0;
}

输出:

1
2
3
4
HelloWorld
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
HelloWorld
请按任意键继续. . .

char *string 之间的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <string>

int main(void)
{
  std::string str = "HelloWorld";
  //string -> char *
  char * cstr = (char *)str.c_str();
  std::cout << cstr << std::endl;
  //char * -> string
  std::string str_ = cstr;
  std::cout << str_ << std::endl;

  system("pause");
  return 0;
}

输出:

1
2
3
HelloWorld
HelloWorld
请按任意键继续. . .

char *wchar_t * 之间的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <iomanip>

int main(void)
{
  char * cstr = "HelloWorld";
  std::cout << cstr << std::endl;

  // char * -> wchar_t *
  //wchar_t * wcstr = (wchar_t *)cstr; //error
  //success
  size_t len = strlen(cstr) + 1;
  size_t converted = 0;
  wchar_t *wcstr;
  wcstr=(wchar_t*)malloc(len*sizeof(wchar_t));
  mbstowcs_s(&converted, wcstr, len, cstr, _TRUNCATE);

  //打印
  wchar_t * temp = wcstr;
  int i = 0;
  std::cout << "Unicode is ";
  while(temp[i]!='\0'){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << temp[i] << " ";
      i++;
  }
  std::cout << std::endl;
  //打印 end

  std::cout << "------------------" << std::endl;
  //-------------------------------------------------

  wchar_t * wcstr_ = L"HelloWorld";
  //打印
  wchar_t * temp_ = wcstr_;
  int i_ = 0;
  std::cout << "Unicode is ";
  while(temp_[i_]!='\0'){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << temp_[i_] << " ";
      i_++;
  }
  std::cout << std::endl;
  //打印 end

  //wchar_t * -> char *
  size_t len_ = wcslen(wcstr_) + 1;
  size_t converted_ = 0;
  char * cstr_;
  cstr_ = (char*)malloc(len*sizeof(char));
  wcstombs_s(&converted_, cstr_, len_, wcstr_, _TRUNCATE);
  std::cout << cstr_ << std::endl;

  system("pause");
  return 0;
}

输出:

1
2
3
4
5
6
HelloWorld
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
------------------
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
HelloWorld
请按任意键继续. . .

注意:

  • cstrwcstrcstr_ 是地址变量,使用 std::cout << cstr_ << std::endl;代码打印的值是地址,并不是字符串的值。
  • wchar_t *char * 之间的转换,使用wchar_t * wcstr = (wchar_t *)cstr;是错误的。(异想天开)

wchar_t *wstring 之间的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>
#include <iomanip>

int main(void)
{
  std::wstring wstr = L"HelloWorld";
  //打印
  std::cout << "Unicode is ";
  for(int i=0; i<wstr.length(); i++){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << wstr[i] << " ";
  }
  std::cout << std::endl;
  //打印 end
  //wstring -> wchar_t *
  wchar_t * wcstr = (wchar_t *)wstr.c_str();
  //打印
  wchar_t * temp = wcstr;
  int i = 0;
  std::cout << "Unicode is ";
  while(temp[i]!='\0'){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << temp[i] << " ";
      i++;
  }
  std::cout << std::endl;
  //打印 end
  //wchar_t * -> wstring
  std::wstring wstr_ = wcstr;
  //打印
  std::cout << "Unicode is ";
  for(int i=0; i<wstr_.length(); i++){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << wstr_[i] << " ";
  }
  std::cout << std::endl;
  //打印 end

  system("pause");
  return 0;
}

输出:

1
2
3
4
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
请按任意键继续. . .

wchar_t *string 之间的转换

知道了上面的几种转换,我们就可以通过组合它们,来实现,比如:wchar_t *string 之间的转换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <string>
#include <iomanip>

int main(void)
{
  std::wstring wstr = L"HelloWorld";
  wchar_t * wcstr = (wchar_t *)wstr.c_str();
  //打印
  wchar_t * temp = wcstr;
  int i = 0;
  std::cout << "Unicode is ";
  while(temp[i]!='\0'){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << temp[i] << " ";
      i++;
  }
  std::cout << std::endl;
  //打印 end

  //wchar_t * -> string (wchar_t * -> wstring -> string)
  std::wstring wstr_ = wcstr;
  std::string str;
  str.assign(wstr_.begin(), wstr_.end());
  std::cout << str << std::endl;
  //string -> wchar_t * (string -> wstring -> wchar_t *)
  wstr_.assign(str.begin(), str.end());
  wchar_t * wcstr_ = (wchar_t *)wstr_.c_str();
  //打印
  wchar_t * temp_ = wcstr;
  int i_ = 0;
  std::cout << "Unicode is ";
  while(temp_[i_]!='\0'){
      std::cout << "U+" << std::setw(4) << std::setfill('0') << std::hex << temp_[i_] << " ";
      i_++;
  }
  std::cout << std::endl;
  //打印 end

  system("pause");
  return 0;
}

输出:

1
2
3
4
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
HelloWorld
Unicode is U+0048 U+0065 U+006c U+006c U+006f U+0057 U+006f U+0072 U+006c U+0064
请按任意键继续. . .

Intel RealSense 004(Learning RealSense SDK 003) DF_CameraViewer示例讲解


  • 我使用的Intel RealSense 硬件:F200、SR300 和 R200 摄像头 都可以
  • Intel RealSense SDK:intel_rs_sdk_offline_package_10.0.26.0396(安装教程这里
  • 电脑系统:Windows 10 64位
  • 编程语言:C++
  • 开发工具软件:Visual Studio 2010 (安装教程这里
  • 参考程序所在路径:C:\Program Files (x86)\Intel\RSSDK\sample\DF_CameraViewer\src\camera_viewer.cpp
  • 示例程序官方文档使用说明:C:\Program Files (x86)\Intel\RSSDK\doc\CHM\sdkmanual-essential.chm -> Sample: DF_CameraViewer [C++]

Alt text


DF_ 指的是什么

(在我写的:介绍F200、SR300 和 R200 摄像头 的博文里面已经有讲过了。)这里直接截个图。

Alt text


注意:Intel RealSense 模块使用时间长了发热会很严重。不要开启太长的时间,并且注意使用散热片散热

在命令行中的使用方法

1
2
DF_CameraViewer [-load <module name>] [-sdname <device name>] 
[-csize <resolution>] [-dsize <resolution>] [-file <Output Filename>] [-listio] [-record] [-help]
Col1 Col2 Col3
-load 明确加载指定模块(如果你的电脑上连接了两个Intel RealSense模块,使用这个参数就可以明确指定你要使用哪一个模块) field3
-csize 指定彩色流分辨率和帧速率。 例如,使用640x480指定分辨率,或使用640x480x30指定分辨率和帧速率。 DF_CameraViewer -csize 640x480x30 或者 DF_CameraViewer -csize 640x480
-dsize 指定深度流分辨率和帧速率。 例如,使用640x480指定分辨率,或使用640x480x30指定分辨率和帧速率。 DF_CameraViewer -dsize 640x480x30 或者 DF_CameraViewer -dsize 640x480
-sdname 指定一个输入设备名称
-nframes 指定要显示的最大帧数。就是刷新多少次显示的图片。比如设置为200,那么帧数刷新200次,程序自动结束。 DF_CameraViewer –nframes 200
-listio 列出I/O 设备列表
-record 启用文件记录。 如果使用这个参数,就必须要还要使用-file参数指定记录文件名
-file 录像或者播放指定文件名。 如果未指定-record,则程序将播放指定的文件。 否则,示例将摄像机数据记录到指定的文件。 (注意:指定的路径一定要有可写的权限。)
-help 输出帮助信息

1
2
3
4
5
6
7
8
9
10
11
12
13
>DF_CameraViewer -help
Usage: [options]
-csize 640x480x30             Set the source device color resolution and frame rate
-dsize 320x240x60             Set the source device depth resolution and frame rate
-isize 640x480x30             Set the source device IR resolution and frame rate
-file FILENAME                Specify playback (or recording) file
-record                       Use together with -file to enable recording
-nframes 350                  Record specific number of frames then exit
-sdname Integrated            Specify the source device by its partial name
-listio                       List all I/O devices
-noRender                     Disable rendering of all streams
-mirror                       Enable MIRROR_MODE_HORIZONTAL
-help                         This help

在命令行中运行程序

下面简单的使用几个命令,来通过实战了解各个参数的作用。

1
>DF_CameraViewer.exe

默认输出两个图片,一个是彩色图片(1080p),一个是深度图片(640x480)。(彩色图片太大了,这里只截了一半的图)

Alt text


1
2
>DF_CameraViewer.exe -csize 640x480 -dsize 640x480 -isize 640x480
(注意:640x480, 使用的是字母 x )

输出三个图片:彩色图片、深度图片、红外线图片

Alt text


1
>DF_CameraViewer.exe -csize 640x480 -dsize 640x480 -isize 640x480 -mirror

输出的是镜面图像。

Alt text


讲解程序

DF_CameraViewer示例是一个简单的C ++控制台应用程序。从这个示例程序,我们可以学到:如何从 Intel RealSense模块 以数据流的形式获取彩色图像和深度图像(或者其他图像)

1 . 创建了一个PXCSenseManager(RealSense管理器)类的实例化对象:

1
PXCSenseManager *pp = PXCSenseManager::CreateInstance();

注:

  • Intel的RealSense SDK 的C++的:接口全部携带“PXC”前缀、 顶层枚举器全部携带“pxc”前缀、实用程序类全部携带“Util”前缀。
  • Intel RealSense SDK C#使用类似的前缀方案,但在末尾加一个“M”(代表“管理”的意思):接口携带“PXCM”前缀、 顶层枚举器携带“pxcm”前缀、实用程序类携带“UtilM”前缀。
  • 如果你在网上搜索资料时看到:"PXC[M]“, "pxc[m]” 和 “Util[M]",这表示这个资料是C++ 和 C#都可以使用的资料。里面使用"PXC[M]”, “pxc[m]” 和 “Util[M]” 标注的接口和函数,如果替换成 “PXC”、“pxc” 和 “Util”,那么就是C++程序;反之,如果替换成“PXCM”、“pxcm” 和 “UtilM”,那么就是C#程序。
  • PXC” 是全称是:?2016-12-13 07:01:17 https://software.intel.com/en-us/forums/realsense/topic/601434 这个我还不太清楚,应该是:Perceptual eXperience Coding

2 . 程序接下来,检查是否pp这个对象是否创建成功:(这个就是一个检测类的实例化对象是否创建成功的代码。电脑不插Intel RealSense模块, 这段代码也可以正常执行。)

1
2
3
4
if (!pp) {
    wprintf_s(L"Unable to create the SenseManager\n");
    return 3;
}

获取命令行参数:

1
2
3
4
5
UtilCmdLine cmdl(pp->QuerySession());
if (!cmdl.Parse(L"-listio-nframes-sdname-csize-dsize-isize-lsize-rsize-file-record-noRender-mirror",argc,argv)){
  system("pause");
  return 3;
}

其中QuerySession()方法返回的是一个Session类的实例化对象。

UtilCmdLine 这个类里面的Parse()方法会自动将-listio-nframes-sdname-csize-dsize-isize-lsize-rsize-file-record-noRender-mirror这一长串的字符串还有命令行参入的参数转换为一些数值,然后分配给UtilCmdLine类里面的一些变量:(util_cmdline.h文件所在路径: C:\Program Files (x86)\Intel\RSSDK\sample\common\include

Alt text

注意:这个QuerySession()方法返回的Session实例化对象(pp->QuerySession())是存储在PXCSenseManager类(就是pp这个实例化对象)里面的,所以,你不可以手动释放它(pp->QuerySession())。


3 .

1
2
3
4
/* Sets file recording or playback */
PXCCaptureManager *cm=pp->QueryCaptureManager();
cm->SetFileName(cmdl.m_recordedFile, cmdl.m_bRecord);
if (cmdl.m_sdname) cm->FilterByDeviceInfo(cmdl.m_sdname,0,0);
  • 定义了一个PXCCaptureManager(捕获管理器)对象。
  • 来到cmdl.m_recordedFile这个路径(如果你没有在命令行中指定-file参数,那么这段代码执行没有什么效果。第二个参数cmdl.m_bRecord,判断是播放还是录制。)
  • 如果在命令行中指定了-sdname参数,那么就在这里设定使用指定的Intel RealSense设备。

4 .

创建了几个UtilRender类的实例对象。它们分别是:彩色图像显示流、深度图像显示流、红外激光显示流、右摄像头显示流、左摄像头显示流。

1
2
3
// Create stream renders
UtilRender renderc(L"Color"), renderd(L"Depth"), renderi(L"IR"), renderr(L"Right"), renderl(L"Left");
pxcStatus sts;

注:C++的字符串前面的L的作用: L"我的字符串" 表示将ANSI字符串转换成unicode的字符串


5 .

接下来,根据命令行传入的参数进行相应的设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
do {
    /* Apply command line arguments */
    pxcBool revert = false;
    if (cmdl.m_csize.size()>0) {
            pp->EnableStream(PXCCapture::STREAM_TYPE_COLOR, cmdl.m_csize.front().first.width, cmdl.m_csize.front().first.height, (pxcF32)cmdl.m_csize.front().second);
    }
    if (cmdl.m_dsize.size()>0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_DEPTH, cmdl.m_dsize.front().first.width, cmdl.m_dsize.front().first.height, (pxcF32)cmdl.m_dsize.front().second);
    }
    if (cmdl.m_isize.size() > 0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_IR, cmdl.m_isize.front().first.width, cmdl.m_isize.front().first.height, (pxcF32)cmdl.m_isize.front().second);
    }
    if (cmdl.m_rsize.size() > 0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_RIGHT, cmdl.m_rsize.front().first.width, cmdl.m_rsize.front().first.height, (pxcF32)cmdl.m_rsize.front().second);
    }
    if (cmdl.m_lsize.size() > 0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_LEFT, cmdl.m_lsize.front().first.width, cmdl.m_lsize.front().first.height, (pxcF32)cmdl.m_lsize.front().second);
    }
    if (cmdl.m_csize.size() == 0 && cmdl.m_dsize.size() == 0 && cmdl.m_isize.size() == 0 && cmdl.m_rsize.size() == 0 && cmdl.m_lsize.size() == 0) {
        PXCVideoModule::DataDesc desc={};
        if (cm->QueryCapture()) {
            cm->QueryCapture()->QueryDeviceInfo(0, &desc.deviceInfo);
        } else {
            desc.deviceInfo.streams = PXCCapture::STREAM_TYPE_COLOR | PXCCapture::STREAM_TYPE_DEPTH;
            revert = true;
        }
        pp->EnableStreams(&desc);
    }

使能某个显示流显示窗口的方法是:pp->EnableStream()

如果你给上面的程序的每一个if判断语句内部添加上注释(像下面这样),然后再在命令行中使用命令运行程序。你就知道了,这些程序是怎么执行的了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
do {
    /* Apply command line arguments */
    pxcBool revert = false;
  printf("cmdl.m_csize.size() = %d\n", cmdl.m_csize.size());
    if (cmdl.m_csize.size()>0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_COLOR, cmdl.m_csize.front().first.width, cmdl.m_csize.front().first.height, (pxcF32)cmdl.m_csize.front().second);
      printf("cmdl.m_csize.front().first.width=%d, cmdl.m_csize.front().first.height=%d, cmdl.m_csize.front().second=%d\n", cmdl.m_csize.front().first.width, cmdl.m_csize.front().first.height, cmdl.m_csize.front().second);
    }
  printf("cmdl.m_dsize.size() = %d\n", cmdl.m_dsize.size());
    if (cmdl.m_dsize.size()>0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_DEPTH, cmdl.m_dsize.front().first.width, cmdl.m_dsize.front().first.height, (pxcF32)cmdl.m_dsize.front().second);
          printf("cmdl.m_dsize.front().first.width=%d, cmdl.m_dsize.front().first.height=%d, cmdl.m_dsize.front().second=%d\n", cmdl.m_dsize.front().first.width, cmdl.m_dsize.front().first.height, cmdl.m_dsize.front().second);
   }
  printf("cmdl.m_isize.size() = %d\n", cmdl.m_isize.size());
    if (cmdl.m_isize.size() > 0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_IR, cmdl.m_isize.front().first.width, cmdl.m_isize.front().first.height, (pxcF32)cmdl.m_isize.front().second);
      printf("cmdl.m_isize.front().first.width=%d, cmdl.m_isize.front().first.height=%d, cmdl.m_isize.front().second=%d\n", cmdl.m_isize.front().first.width, cmdl.m_isize.front().first.height, cmdl.m_isize.front().second);
    }
  printf("cmdl.m_rsize.size() = %d\n", cmdl.m_rsize.size());
    if (cmdl.m_rsize.size() > 0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_RIGHT, cmdl.m_rsize.front().first.width, cmdl.m_rsize.front().first.height, (pxcF32)cmdl.m_rsize.front().second);
          printf("cmdl.m_rsize.front().first.width=%d, cmdl.m_rsize.front().first.height=%d, cmdl.m_rsize.front().second=%d\n", cmdl.m_rsize.front().first.width, cmdl.m_rsize.front().first.height, cmdl.m_rsize.front().second);
   }
  printf("cmdl.m_lsize.size() = %d\n", cmdl.m_lsize.size());
    if (cmdl.m_lsize.size() > 0) {
        pp->EnableStream(PXCCapture::STREAM_TYPE_LEFT, cmdl.m_lsize.front().first.width, cmdl.m_lsize.front().first.height, (pxcF32)cmdl.m_lsize.front().second);
      printf("cmdl.m_lsize.front().first.width=%d, cmdl.m_lsize.front().first.height=%d, cmdl.m_lsize.front().second=%d\n", cmdl.m_lsize.front().first.width, cmdl.m_lsize.front().first.height, cmdl.m_lsize.front().second);
    }

如果有时程序秒退的话,你可以在return之前加上:system("pause");这样一段代码,让程序先暂停到这。


6 .

下面的代码是对命令行传入的 -mirror 参数进行处理:是否对图像进行镜像配置。

1
2
3
4
5
6
    /* Set mirror mode */
    if (cmdl.m_bMirror) {
        device->SetMirrorMode(PXCCapture::Device::MirrorMode::MIRROR_MODE_HORIZONTAL);
    } else {
        device->SetMirrorMode(PXCCapture::Device::MirrorMode::MIRROR_MODE_DISABLED);
    }

7 . 下面显示图片:

1
2
3
4
5
6
7
8
9
10
        if (cmdl.m_bNoRender == false) {
            const PXCCapture::Sample *sample = pp->QuerySample();
            if (sample) {
                if (sample->depth && !renderd.RenderFrame(sample->depth)) break;
                if (sample->color && !renderc.RenderFrame(sample->color)) break;
                if (sample->ir    && !renderi.RenderFrame(sample->ir))    break;
                if (sample->right && !renderr.RenderFrame(sample->right)) break;
                if (sample->left  && !renderl.RenderFrame(sample->left))  break;
            }
        }

参考文献:C:\Program Files (x86)\Intel\RSSDK\doc\CHM\sdkmanual-essential.chm -> QuerySample

  • QuerySample()函数可以返回所有可能存在的图片样本。
  • 如果不给QuerySample()函数不传入任何形参,那么它将返回一个Sample结构体,这个结构体里面包含了所有的可能存在的图片样本。[可能存在的图片样本:depth(深度图像)、color(彩色图像)、ir(红外线图像)、right(右图像)、left(左图像)。] (下图就是Sample结构体其中一部分)
    • Alt text
  • 如果给QuerySample()函数传入一个指定的参数,那么它将只返回对应参数的图片样本。
  • 如果你给QuerySample()函数传入一个参数,是你当前使用的Intel RealSense模块没有的设备,那么QuerySample()函数会返回NULL/null比如说:我们当前使用的Intel RealSense模块是SR300,它没有right Camera 和 left Camera设备,所以如果你给QuerySample()函数传入sample->right 或者 sample->left参数,那么QuerySample()函数将返回NULL/null。R200版的Intel RealSense模块是具备right Camera 和 left Camera设备的,所以如果你当前使用的是R200,那么给QuerySample()函数传入sample->right 或者 sample->left参数,QuerySample()函数会返回sample->right 或者 sample->left对应的图片样本。

上面的代码中,类似if (sample->depth && !renderd.RenderFrame(sample->depth)) break;这样的代码一共有5句。它们分别处理:depth(深度图像)、color(彩色图像)、ir(红外线图像)、right(右图像)、left(左图像)。


下面以深度图像为例,讲解:

  • 第一个判断条件:有没有得到深度图片sample->depth。如果没有直接break,第二个判断条件不会执行。
  • 第二个判断条件:RenderFrame()函数是UtilRender类中的一个方法,它用来显示传入的形参图片,并返回一个bool类型数据,如果成功显示,返回true,否则返回false

那么对于深度图像sample->depth,伪码就应该是下面这样的。所以不执行break;

1
if(true && !true)  break;

对于右图像sample->right,它的伪码是下面这样的(当前使用的是SR300)。所以也不执行break;

1
if(false && !false)    break;

程序会正常的执行,图片会正常的显示。那么什么时候图片会不正常显示呢:当执行到break;,图片就不显示了。执行到break说明判断语句是if(true && !false)这样的状态。说明图片我们会得到了,但是在显示的时候失败了。


讲解完毕

Intel RealSense 003(Learning RealSense SDK 002) 给Visual Studio 2010搭建 Intel RealSense SDK开发环境


  • 我使用的Intel RealSense 硬件:F200、SR300 和 R200 摄像头 都可以
  • Intel RealSense SDK:intel_rs_sdk_offline_package_10.0.26.0396(安装教程这里
  • 电脑系统:Windows 10 64位
  • 编程语言:C++
  • 开发工具软件:Visual Studio 2010 (安装教程这里

准备工作

先新建一个项目:(一些简单的操作步骤,我忽略不记录)

Alt text

Alt text

在项目里面新建一个.cpp文件:camera_viewer.cpp。并将下面的代码拷贝到里面。

这段代码是Intel RealSense SDK 中的一个示例程序。在这个路径里面可以找到它:C:\Program Files (x86)\Intel\RSSDK\sample\DF_CameraViewer\src\camera_viewer.cpp


现在我们先不管代码里面写的是什么,这一节我们重点介绍搭建开发环境。下一节,我们讲解这段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*******************************************************************************

INTEL CORPORATION PROPRIETARY INFORMATION
This software is supplied under the terms of a license agreement or nondisclosure
agreement with Intel Corporation and may not be copied or disclosed except in
accordance with the terms of that agreement
Copyright(c) 2011-2014 Intel Corporation. All Rights Reserved.

*******************************************************************************/
#include <windows.h>
#include "pxcsensemanager.h"
#include "pxcmetadata.h"
#include "util_cmdline.h"
#include "util_render.h"
#include <conio.h>

int wmain(int argc, WCHAR* argv[]) {
    /* Creates an instance of the PXCSenseManager */
    PXCSenseManager *pp = PXCSenseManager::CreateInstance();
    if (!pp) {
        wprintf_s(L"Unable to create the SenseManager\n");
        return 3;
    }

    /* Collects command line arguments */
    UtilCmdLine cmdl(pp->QuerySession());
    if (!cmdl.Parse(L"-listio-nframes-sdname-csize-dsize-isize-lsize-rsize-file-record-noRender-mirror",argc,argv)) return 3;

    /* Sets file recording or playback */
    PXCCaptureManager *cm=pp->QueryCaptureManager();
    cm->SetFileName(cmdl.m_recordedFile, cmdl.m_bRecord);
    if (cmdl.m_sdname) cm->FilterByDeviceInfo(cmdl.m_sdname,0,0);

    // Create stream renders
    UtilRender renderc(L"Color"), renderd(L"Depth"), renderi(L"IR"), renderr(L"Right"), renderl(L"Left");
    pxcStatus sts;
    do {
        /* Apply command line arguments */
        pxcBool revert = false;
        if (cmdl.m_csize.size()>0) {
            pp->EnableStream(PXCCapture::STREAM_TYPE_COLOR, cmdl.m_csize.front().first.width, cmdl.m_csize.front().first.height, (pxcF32)cmdl.m_csize.front().second);
        }
        if (cmdl.m_dsize.size()>0) {
            pp->EnableStream(PXCCapture::STREAM_TYPE_DEPTH, cmdl.m_dsize.front().first.width, cmdl.m_dsize.front().first.height, (pxcF32)cmdl.m_dsize.front().second);
        }
        if (cmdl.m_isize.size() > 0) {
            pp->EnableStream(PXCCapture::STREAM_TYPE_IR, cmdl.m_isize.front().first.width, cmdl.m_isize.front().first.height, (pxcF32)cmdl.m_isize.front().second);
        }
        if (cmdl.m_rsize.size() > 0) {
            pp->EnableStream(PXCCapture::STREAM_TYPE_RIGHT, cmdl.m_rsize.front().first.width, cmdl.m_rsize.front().first.height, (pxcF32)cmdl.m_rsize.front().second);
        }
        if (cmdl.m_lsize.size() > 0) {
            pp->EnableStream(PXCCapture::STREAM_TYPE_LEFT, cmdl.m_lsize.front().first.width, cmdl.m_lsize.front().first.height, (pxcF32)cmdl.m_lsize.front().second);
        }
        if (cmdl.m_csize.size() == 0 && cmdl.m_dsize.size() == 0 && cmdl.m_isize.size() == 0 && cmdl.m_rsize.size() == 0 && cmdl.m_lsize.size() == 0) {
            PXCVideoModule::DataDesc desc={};
            if (cm->QueryCapture()) {
                cm->QueryCapture()->QueryDeviceInfo(0, &desc.deviceInfo);
            } else {
                desc.deviceInfo.streams = PXCCapture::STREAM_TYPE_COLOR | PXCCapture::STREAM_TYPE_DEPTH;
                revert = true;
            }
            pp->EnableStreams(&desc);
        }

        /* Initializes the pipeline */
        sts = pp->Init();
        if (sts<PXC_STATUS_NO_ERROR) {
            if (revert) {
                /* Enable a single stream */
                pp->Close();
                pp->EnableStream(PXCCapture::STREAM_TYPE_DEPTH);
                sts = pp->Init();
                if (sts<PXC_STATUS_NO_ERROR) {
                    pp->Close();
                    pp->EnableStream(PXCCapture::STREAM_TYPE_COLOR);
                    sts = pp->Init();
                }
            }
            if (sts<PXC_STATUS_NO_ERROR) {
                wprintf_s(L"Failed to locate any video stream(s)\n");
                pp->Release();
                return sts;
            }
        }

        /* Reset all properties */
        PXCCapture::Device *device = pp->QueryCaptureManager()->QueryDevice();
        device->ResetProperties(PXCCapture::STREAM_TYPE_ANY);

        /* Set mirror mode */
        if (cmdl.m_bMirror) {
            device->SetMirrorMode(PXCCapture::Device::MirrorMode::MIRROR_MODE_HORIZONTAL);
        } else {
            device->SetMirrorMode(PXCCapture::Device::MirrorMode::MIRROR_MODE_DISABLED);
        }

        /* Stream Data */
        for (int nframes=0;nframes<cmdl.m_nframes;nframes++) {
            /* Waits until new frame is available and locks it for application processing */
            sts=pp->AcquireFrame(false);

            if (sts<PXC_STATUS_NO_ERROR) {
                if (sts==PXC_STATUS_STREAM_CONFIG_CHANGED) {
                    wprintf_s(L"Stream configuration was changed, re-initilizing\n");
                    pp->Close();
                }
                break;
            }

            /* Render streams, unless -noRender is selected */
            if (cmdl.m_bNoRender == false) {
                const PXCCapture::Sample *sample = pp->QuerySample();
                if (sample) {
                    if (sample->depth && !renderd.RenderFrame(sample->depth)) break;
                    if (sample->color && !renderc.RenderFrame(sample->color)) break;
                    if (sample->ir    && !renderi.RenderFrame(sample->ir))    break;
                    if (sample->right && !renderr.RenderFrame(sample->right)) break;
                    if (sample->left  && !renderl.RenderFrame(sample->left))  break;
                }
            }

            /* Releases lock so pipeline can process next frame */
            pp->ReleaseFrame();

            if( _kbhit() ) { // Break loop
                int c = _getch() & 255;
                if( c == 27 || c == 'q' || c == 'Q') break; // ESC|q|Q for Exit
            }
        }
    } while (sts == PXC_STATUS_STREAM_CONFIG_CHANGED);

    wprintf_s(L"Exiting\n");

    // Clean Up
    pp->Release();
    return 0;
}

现在编译程序是不会通过的,有很多错误。下面开始搭建开发环境。

搭建VS2010使用C++编写Intel RealSense的程序的开发环境

现在开始搭建Intel RealSense在VS2010中的开发环境,这里有两种方法,我都介绍一遍,你可以选择任何一种方法。

方法一

这个方法是最简单,最直接的。我们直接使用集成属性表

参考文献:C:\Program Files (x86)\Intel\RSSDK\doc\CHM\sdkdevguide.chm -> Importing the SDK Property Sheets

Intel RealSense SDK已经为我们配置好了属性表,并且这些属性表在VS2010~VS2015软件里都能使用。它的所在路径是:C:\Program Files (x86)\Intel\RSSDK\props

Alt text

视图(V) -> 属性管理器(M)

Alt text

项目名 -> 添加现有属性表(E)…

Alt text

随便选择哪一个都可以。

  • VS2010-15.Integration.MD.props:动态编译
  • VS2010-15.Integration.MT.props:静态编译

Alt text

一次添加,自动添加到DebugRelease里面。

Alt text

所有步骤操作完成了,环境搭建好了,是不是很简单。OK,现在编译程序就成功了。(生成成功:(但是有一个警告,这个警告不用管。))

运行程序之前注意:要将Intel RealSense模块连接到电脑的USB3.0接口


注意: 下次重新建新的工程,还需要重新搭建环境。

如果你觉得这个方法一太简单了,学不到什么东西。那么下面的方法二就是所有的环境都自己手动搭建,不使用Intel RealSense SDK提供的现成的属性表了。


方法二

如果你操作了方法一,现在先把刚刚添加的属性表删除,让属性管理器变成原来的样子:

Alt text

参考文献:C:\Program Files (x86)\Intel\RSSDK\doc\CHM\sdkdevguide.chm -> Configuring Project Settings

一共分三步:

Step 1 . 添加 包含目录

解决方案资源管理器 里,对着项目名右键 -> 属性

Alt text

添加:

1
2
C:\Program Files %28x86%29\Intel\RSSDK\sample\common\include
C:\Program Files %28x86%29\Intel\RSSDK\include

Alt text

Step 2 . 添加 库目录

1
2
C:\Program Files %28x86%29\Intel\RSSDK\sample\common\lib\win32\v100
C:\Program Files %28x86%29\Intel\RSSDK\lib\Win32

Alt text

Step 3 . 添加 附加依赖项

先查看:查看当前项目使用的运行库是动态多线程调试(/MDd)还是静态多线程调试(/MTd)的。

如果是/MDd(新建的项目默认都是/MDd

Alt text

1
2
3
4
libpxcutilsmd_d.lib
libpxcmd_d.lib
libpxcmd.lib
libpxcutilsmd.lib

注意: 这里 文件名后有_d的是Debug使用的链接文件。Debug的链接文件一定要添加在Release链接文件前面。否则会出现error LNK2038错误

Alt text

OK,环境搭建完成,可以运行程序了。(生成成功:(但是有一个警告,这个警告不用管。))


如果是/MTd:

Alt text

1
2
3
4
libpxc_d.lib
libpxcutils_d.lib
libpxc.lib
libpxcutils.lib

Alt text

OK,环境搭建完成,可以运行程序了。(生成成功:(但是有一个警告,这个警告不用管。))


运行 (测试环境是否搭建成功)

运行程序之前注意:要将Intel RealSense模块连接到电脑的USB3.0接口

(编译成功:(但是有一个警告,这个警告不用管。))

1
2
3
4
1>  camera_viewer.cpp
1>d:\workspace\test_ws\intel_realsense_sdk_ws\hello_intel_realsense_sdk\hello_intel_realsense_sdk\camera_viewer.cpp(93): warning C4482: 使用了非标准扩展: 限定名中使用了枚举“PXCCapture::Device::MirrorMode
1>d:\workspace\test_ws\intel_realsense_sdk_ws\hello_intel_realsense_sdk\hello_intel_realsense_sdk\camera_viewer.cpp(95): warning C4482: 使用了非标准扩展: 限定名中使用了枚举“PXCCapture::Device::MirrorMode
1>生成成功。

默认输出两个图片,一个是彩色图片(1080p),一个是深度图片(640x480)。(彩色图片太大了,这里只截了一半的图)

Alt text


总结: 这一讲,我们以 VS2010开发平台C++语言 为例,讲解了如何搭建Intel RealSense SDK 的开发环境。这个方法在VS2012、VS2013、VS2015上一样适用。

下一节,我们详细讲解本篇博客里面使用的camera_viewer.cpp的代码。

Intel RealSense 001 开发环境的选择


不管你使用Intel RealSense的哪款摄像头,本文都适合你。

对于开发环境(就是你编写程序),你有两个选择:

我个人推荐使用librealsense这个跨平台库,它让Intel RealSense摄像头在Linux系统上使用。并且同时可以在Linux系统里面的ROS机器人操作系统里面使用Intel RealSense。(这里