Normal view

There are new articles available, click to refresh the page.
Before yesterdayStories by invisprints on Medium

Shadowsocks 服务器搭建

13 September 2019 at 11:52

基本上算作官网文档的补充,官网很多东西散落在各个角落,不太好找,本文稍微归纳了一下。

技术发展日新月异,随着时间的流逝文中的一些东西可能会过时,请注意更新时间。

最后修改:2019–08–08。

目前 shadowsocks 中还在不断更新的只有 shadowsocks-libev,本文主要介绍这个。

首先你要有台用于搭建 ss 的服务器。另外本教程适合用户个人使用,如果想建站,请自行查阅其他资料。

shadowsocks-libev

ubuntu 的安装很简单,一条命令即可,不过貌似对 Ubuntu 版本有要求
sudo apt install shadowsocks-libev
安装的可能不是最新版,最新版请手动编译

Centos 7安装

按官网说明安装软件,建议采用手动方法,原因一是能保证用的是最新版,二是出了问题容易上网搜索解决。
Installation

不过官网上写得有些混乱,如果看不懂的话直接无脑进行如下操作即可:

yum install epel-release -y
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y

git clone https://github.com/shadowsocks/shadowsocks-libev.git
cd shadowsocks-libev
git submodule update --init --recursive

./autogen.sh && ./configure && make
sudo make install

接下来需要将配置文件拷贝到常用路径
添加配置文件:

cp ./rpm/SOURCES/etc/init.d/shadowsocks-libev /etc/init.d/shadowsocks-libev
cp ./debian/config.json /etc/shadowsocks-libev/config.json
chmod +x /etc/init.d/shadowsocks-libev

单用户配置

编辑配置文件

vim /etc/shadowsocks-libev/config.json

修改里面的配置,这里给个 demo,具体每个参数什么意思在官网了解吧:

{
"server":["[::0]","0.0.0.0"],
"server_port":8388,
"local_port":1080,
"password":"barfoo!",
"timeout":60,
"method":"chacha20-ietf-poly1305"
}

该配置同时支持 Ipv6 和 Ipv4,并采用 ss3.0 支持的 AEAD 加密方式。
接下来我们要修改 /etc/init.d/shadowsocks-libev,由于历史原因这里面有点问题。
把文件中的DAEMON=/usr/bin/ss-server改成DAEMON=/usr/local/bin/ss-server
修改完成后修改文件权限

chmod 755 /etc/init.d/shadowsocks-libev

启动 shadowsocks-libev

/etc/init.d/shadowsocks-libev start

多用户配置

多用户配置有多种方法,官方推荐通过给每个用户一个配置文件,启动多个ss-server实现。
还有种方法如下,通过启动ss-manager实现
多用户配置文件与单用户不同,我们配置文件目录创建一个ss_manager.json

{
"server": ["[::0]","0.0.0.0"],
"local_port": 1080, # 本地端口,自行设定
"timeout": 600, # 超时毫秒数
"method": "chacha20-ietf-poly1305",
"port_password": {
"8388": "barfoo1", # 端口号与密码
"8389": "barfoo2"
}
}

设置开机启动

单用户很简单

chkconfig --add shadowsocks 
service shadowsocks start

若是针对多用户情况,需要手写开机启动脚本,方法如下:
应在/usr/lib/systemd/system下新建一个.service文件,例如ssmanager.service

[Unit]
Description=shadowsocks manager # 服务的描述
After=network.target # 该服务跟在哪个服务后启动

[Service]
Type=forking # 启动时的进程行为,forking是以fork形式从父进程创建子进程,子进程创建后父进程退出
ExecStart=/usr/local/bin/ss-manager --manager-address /var/run/shadowsocks-manager.sock -c /etc/shadowsocks/ss_manager.json # 启动服务时执行的命令
PrivateTmp=true # 使用私有临时文件目录

[Install]
WantedBy=multi-user.target # 附挂在multi-user.target下

所有配置文件与脚本都设置完毕,使用systemctl开启服务。

# 更改.service文件后,都要重载守护进程更新systemctl
systemctl daemon-reload
# 启动服务
systemctl start ssmanager.service
# 查看服务状态,若为绿色active(running)则说明服务成功启动
systemctl status ssmanager.service
# 设置服务开机自启动
systemctl enable ssmanager.service
# 还可使用systemctl restart ssmanager.service重启服务,使用systemctl stop ssmanager.service停止服务

开启防火墙白名单

很多人按照教程的配置完后,发现并不能使用,原因是端口被防火墙关闭了。
输入如下代码开启防火墙端口白名单:

vim /etc/firewalld/zones/public.xml

在文件中适当位置添加下面代码:

<port protocol="tcp" port="[server port]"/>
<port protocol="udp" port="[server port]"/>

[server port] 填你的端口号。

重启防火墙

firewall-cmd --complete-reload

客户端

在这里面找适合自己版本的吧
GitHub

开启多进程

shadowsocks-libev 一个进程只能开启一个端口,因此我们要开启多个进程,对应每个进程使用一份相应的配置文件,从而达到多用户使用的目的
配置完多份配置文件后w在 /etc/init.d/shadowsocks 相应位置添加如下代码,一下代码仅供参考,读者可根据实际需求修改,这些代码的意思都很简单。

# 配置文件位置
CONF1=/etc/shadowsocks-libev/config1.json

# 检测配置文件是否存在
if [ ! -f $CONF1 ] ; then
echo "The configuration file1 cannot be found!"
exit 0
fi

# 定位到 pid 文件
PID1=/var/run/$NAME/pid1

# 开启进程
daemon $DAEMON -c $CONF1 -f $PID1

# 杀死进程
killproc -p ${PID1}

# 移除 pid 文件
rm -f ${PID1}

在原来的脚本里有跟上面代码极其相似的地方(数字1没有),把上面的6段代码插入到原来脚本中对应相似的代码后面即可。

Python 与 C++ 数据传输

13 September 2019 at 11:31

因毕设需要,需从 python 将图像数据传给 C++,接收 C++ 处理好后的图像。

新建 C++ 文件接收从 Python传来的数据

#include <opencv2/opencv.hpp>

cv::BackgroundSubtractorMOG2 mog(100, 16, false);

extern "C" void getfg(int rows, int cols, unsigned char* imgData,
unsigned char *fgD) {
cv::Mat img(rows, cols, CV_8UC3, (void *) imgData);
cv::Mat fg(rows, cols, CV_8UC1, fgD);
mog(img, fg);
}

extern "C" void getbg(int rows, int cols, unsigned char *bgD) {
cv::Mat bg = cv::Mat(rows, cols, CV_8UC3, bgD);
mog.getBackgroundImage(bg);
}

所有与 python 交互的 API 必须在 extern "C"中,如果交互 API 过多,上述代码也可以写成如下形式

#include <opencv2/opencv.hpp>

cv::BackgroundSubtractorMOG2 mog(100, 16, false);

extern "C"{
void getfg(int rows, int cols, unsigned char* imgData,
unsigned char *fgD) {
cv::Mat img(rows, cols, CV_8UC3, (void *) imgData);
cv::Mat fg(rows, cols, CV_8UC1, fgD);
mog(img, fg);
}

void getbg(int rows, int cols, unsigned char *bgD) {
cv::Mat bg = cv::Mat(rows, cols, CV_8UC3, bgD);
mog.getBackgroundImage(bg);
}
}

图像数据通过 unsigned char *data 传输进来,通过Mat image(h,w,CV_8UC3,data)转换成C++ OpenCV可识别数据,如果是灰度图,则是CV_8UC1,数据通过指针链接,在C++中是直接修改存在内存中的数据,无需传回。
之后将 C++ 编译成动态链接库,CmakeLists设置如下

add_library(prj SHARED
main.cpp
main.h libmain.cpp)

target_link_libraries(prj ${OpenCV_LIBS})

与C++交互的文件设置如下

import ctypes
# 链接动态库
libmog = ctypes.cdll.LoadLibrary('path/to/libmain.so')

def getfg(img):
(rows, cols) = (img.shape[0], img.shape[1])
res = np.zeros(dtype=np.uint8, shape=(rows, cols))
libmain.getfg(img.shape[0], img.shape[1],
img.ctypes.data_as(ctypes.c_char_p),
res.ctypes.data_as(ctypes.c_char_p)
return res


def getbg(img):
(rows, cols) = (img.shape[0], img.shape[1])
res = np.zeros(dtype=np.uint8, shape=(rows, cols, 3))
libmain.getbg(rows, cols, res.ctypes.data_as(ctypes.c_char_p))
return res

对于需要指针传输的数据,需要用ctypes.data_as(ctypes.c_char_p)将其转换成C++可读取的数据形式

参考文章
stackoverflow

在 Word 上给标题设置多级编号

在对规范要求较为严格的文档上,经常会对标题的编号有所要求。下面以某毕业文档为例,简要说明下如何让word自动给标题编号。

论文的章节标题称为一级标题,章内小节标题依次分为二级标题、三级标题等。一级标题的编号用数字1,2,…编制;二级标题的编号用1.1,1.2,…编制;三级标题的编号用1.1.1,1.2.1,…编制;四级及以后各级标题可依此类推。建议标题不超过3级(如1.1.1),超出部分可根据需要使用(1),①,A,a),…等形式描述。
标题编号与标题文字之间均用空格隔开,如:“1 引言”、“2.1 需求分析”。论文正文的一级标题(章)须另起一页居中排版。

最后的效果如图所示

1. 建立好各级标题样式表

既然是让word自动生成,就需要将各级标题的格式编写在样式表中,以macOS版Word2019为例,在“开始-样式窗格”中单击新建样式,按照规范要求将各级标题的格式填写在样式表中,如图所示。

以此类推,把各级标题的格式填写好并保存在样式表中。

2. 建立多级编号

在任意标题的样式表中,单击左下角的菜单栏,选择编号,在多级符号中选择自定义。或者在列表窗口中选择“定义新的多级列表”。

按要求设置每一级别的格式,设置好后将该级别链接要对应的标题样式中。如级别1链接到一级标题,级别2链接到二级标题。

常用软件推荐

更新时间2019–03–31

Dropbox

大名鼎鼎的文件同步软件,具有极佳的稳定性和易用性,可以说是高效工作的必备工具!缺点是需要梯子才能使用,免费版容量太少。

Dropbox 邀请链接:你我均可获得 500M 额外空间

OneDrive

微软旗下的云盘,与 Windows 和 Office 系列深度整合,相对于 dropbox,其大容量的免费空间吸引着很多用户。缺点是国内偶尔不太稳定,网页版无法访问。

如果付费的话推荐大家购买onedrive for business,相较于个人版稳定很多,且可以访问网页版。

OneDrive 邀请链接: 0.5G 额外空间

印象笔记

极具名气的笔记类应用,可以说是高效人士的必备应用,其各种扩展功能使其成为名副其实的第二大脑。 最近加入的 Markdown 让很多人重新回到大象阵营,但是移动端目前还不可编辑此类文件。

印象笔记邀请链接: 可获取印象分,用于兑换高级用户。

为知笔记

国内的笔记应用,相对于印象笔记提供了很多本土化功能。 新用户试用100天,之后只有付费才能使用。

为知笔记邀请链接

Notion

笔记类的新秀,号称是”将笔记、知识库和任务管理无缝整合的协作平台”,

目前中文搜索薄弱,只能搜索句子开头和前面有空格的词汇。

Notion 邀请链接

石墨文档

Google Docs 的最佳替代品,超低延迟+丰富功能,对于普通用户免费版已经足够使用了。

石墨文档邀请链接:15天高级版

ProcessOn

功能强大的在线作图工具,是 Visio 的绝佳替代品,对于普通用户而言免费版已足够使用。

ProcessOn 邀请链接

Vultr

性价比极高国外的云主机,个人建站之类的绝佳选择。 Vultr邀请链接: 10刀优惠

番茄土豆

全平台覆盖的番茄类时间管理应用,特色是全平台和结合番茄钟与 GTD,有学生优惠,价格低廉。缺点是已经有较长一段时间没有更新。

番茄土豆邀请链接:优惠码 D8VEZH3C 可获得10天高级版

扇贝网

国内知名的英语学习网站,特色是学习社群,可以一边学习一边给同伴加油! 扇贝网邀请链接:获取贝壳

MultCloud

网盘中转站,可以帮你把一个网盘中的数据转移到另一个网盘中,国内目前仅支持百度云。 个人在使用过程中发现对百度云的支持经常失效。

MultCloud 邀请链接 : 流量奖励

Seedr

种子离线下载器,免费版空间较少,可以当做迅雷的备胎。

Seedr: 获取额外空间

Offcloud

功能最强大的离线下载器,免费空间10G,每月仅支持3次下载。但是付费用户拥有超多功能,支持大量的国外付费网盘离线中转下载。

Offcloud 邀请链接

幕布

一款结合思维导图和大纲的应用,对标于国外的 workflowy。善用佳软极力推荐的工具,缺点是他们是初创公司,开发进度缓慢。

幕布邀请链接 : 可获15天高级版

macOS 下用 DOS 模拟器进行汇编实验

7 January 2018 at 16:30

学微机原理的同学都是要求学汇编语言的,但是这种古老的语言并没有良好的移植性,用 Mac 的同学深受其害,往往都需要在 Windows 虚拟机下运行 Dos 模拟器完成,但是 macOS 下也有很棒的 DOS 模拟器,让我们可以跳过 Window 虚拟机这一环。

不要给我说 nasm 命令!!那个东西基本跟学校学习的汇编不兼容,劝发现这个命令的人老老实实用 DOS 模拟器吧。

DOSBox

Windows 下著名的 DOS 模拟器,华中科技大学自动化学生御用 DOS 模拟器,其官网已经多年没有更新了,所以对于最新的系统可能有一些兼容问题。
最新的版本是 2010 年推出的 0.74 版,之后就再也没有更新。细心的读者可能会发现,DOSBox 居然有 MAC OS X 版!各位,先别急着欢呼,我这里之所以用 MAC OS X 而没用 macOS 就是想提醒大家这个版本已经很老了,最新版的兼容性堪忧。

DOSBox

所以广大的 macOS 该怎么办呢?大家放心,既然我博文都写出来了,肯定有比装虚拟机更好的方法。

Boxer

就是我们大名鼎鼎的 Boxer!虽然最新更新日期是 2016 年 2 月,快有一年没有更新了,但是相比于 DOSBox, 已经好太多。官网地址
软件本身自带几个 DOS 游戏,大家可以试着玩玩,但是我们今天的主题不是这个,而是用它进行汇编语言实验。

搭建环境

有了著名的 DOS 操作环境,下面我们需要搭建开发环境,毕竟 Boxer 本身是不包含编译汇编程序的。
这是我找的一份 DOS 环境下汇编语言开发包,提取码是 je38。至于从哪找的我已经忘了,反正好用无毒!
下载好后把里面的程序放到你的汇编语言开发环境中,即在同一个目录下。

挂载项目

打开 Boxer 后选择 Open a DOS prompt, 即进入的我们熟悉又和蔼的 DOS 操作环境。但是我们目前处于一个神奇的位置 — — Z 盘!Z 盘是在哪里呢?抱歉我也不知道,也不想知道。

Boxer

我们目前要做的就是定位到我们的项目文件夹。方法很简单,也有多种,这里我介绍最方便的一种,其他的读者可以自己探索。
把你的项目文件夹直接拖动到 Boxer 窗口中,Boxer会把你拖动的文件夹当成 C 盘挂载。
挂载成功后,就是这样的!

Cdrive

输入 dir 我们可以浏览当前文件夹下都有哪些文件。

编译并运行程序

编译文件用 masm 命令,如:

masm example.asm

编译成功后会生成 .obj 文件,用命令 link 链接对应的文件生成可执行文件,如:

link example.obj

运行生成的 .exe 文件即可!

program

大津算法(OTSU)

31 December 2017 at 13:55

在图像处理领域,我们会遇到如下需求:把图像中的目标物体和背景分开。比如背景用白色表示,目标物体用黑色表示。此时我们知道目标物体的灰度值相互接近,背景灰度值相互接近,那么用大津算法能很好把目标从背景当中区分开来。

算法思想

目标

比如对于下面这张灰度图片

origin

目标物体是中间黑色的几何物体,我们想让这些物体和背景区分更明显一些,比如让物体为纯黑,背景全白。那么我们就需要找到一个合适的阈值,使图片上灰度值大于这个阈值的像素点为255(白色),灰度值小于阈值的像素点为0(黑色)。也就是变成下面这幅图:

output

那么大津算法需要处理的就是找到最佳的阈值,让目标和物体尽可能分离开。

灰度直方图

为了找到合适的阈值,我们首先观察原图的灰度直方图📊:

histogram

这是用 Matlab 对原图形成的灰度直方图,灰度直方图的含义是统计图像中不同灰度值的分布情况。由图我们可以看出两个尖峰,在灰度值为0~20的地方存在一个尖峰,代表原图中有大量像素点灰度值为0~20,经观察我们可以认为这部分对应于目标物体。同理我们可以看出背景的灰度值大多集中于100~140之间,为了让目标和背景区分更加明显,我们想让目标物体的灰度值全为0,背景的灰度值全为255,这种处理手法也称为二值化法。

那么阈值取多少合适呢?从图上看似乎取50~100中的任意一点都可以,但是实际情况并不想参考图那样明显,有些图片背景和目标物体较为接近,我们需要一个算法来找到最优阈值才行。

聚类

首先我们思考什么样的东西才能成为一类,而我们又是怎么分类的。对于参考图来说,我们可以认为灰度值接近的为一类,灰度值不接近的不是同一类。那我们又是如何衡量灰度值接近的程度呢?这里面就需要用到方差的概念。
方差相比大家都了解,同一类的物体方差小,不同类的物体方差大。所以对于此图我们希望分类的结果是对于灰度值相近的同一类物体,它的方差最小,称为类内方差最小。灰度值不接近的不同类物体,它的方差大,称为类间方差最大。

步骤

所以步骤总结如下:
首先我们要形成参考图的灰度直方图,这样方便我们找到最佳阈值。
接下来我们通过穷举每一个灰度值,计算以此为阈值的类内和类间方差。
找到能形成类内方差最小的或类间方差最大的阈值,这个就是我们要找的最佳阈值。

算法

下面以两类分割讲解下具体的算法,实际上大津算法可以分割多类出来。

因为 Medium 不支持显示 MathJax 语法的公式,所以对这部分感兴趣的直接移步到《大津算法(OTSU)》查看吧。

代码实现

C语言实现

/* OTSU 算法
* *src 存储灰度图像,width 图像宽,height 图像长
* 返回最佳阈值
*/
int otsu(const int *src, int width, int height)
{
int histogram[256]; //存储灰度直方图,这里为256色灰度
int t,thred;
float wf,wb,ub,uf,curVal,maxVal;
int sumb=0,sumf=0,sumW=0,sumPixel=width*height;
wb=wf=maxVal=0.0f;

//求灰度直方图
memset(histogram,0,sizeof(histogram));
for(i=0;i<width*height;i++)
{
histogram[src[i]]++;
}

for (i=0;i<256;i++)
sumW+=i*histogram[i];

//枚举每个灰度
for(t=0;t<256;t++)
{
//求两类类概率密度
wb+=histogram[t];
wf=sumPixel-wb;
if (wb==0||wf==0)
continue;

//求类均值
sumb+=i*histogram[t];
sumf=sumW-sumb;
ub=sumb/wb;
uf=sumf/wf;

//求当前类间方差
curVal=wb*wf*(ub-uf)*(ub-uf);
if(curVal>maxVal)
{
thred=t;
maxVal=curVal;
}
}
return thred;
}

星轨拍摄:探索篇

24 December 2017 at 13:01

前段时间武汉天气异常晴朗,空气质量也出乎意料的差强人意,所以到了晚上,能看到不少✨。
作为一个资深的业余天文爱好者,怎么能放过这大好机会?!各种找关系之后终于从某土豪手中借来一台单反📷。
虽然不是专门用来拍星空🌃的单反,但是比上次《用手机拍星星》的穷酸样已经是天上地下了,争取下次扶摇直上九万里吧!

前期准备

因为这次要拍摄星轨,预计时间近 2 个小时,所以带上各种装备啦,吃的喝的玩的续命宝羽绒服手套等防寒的,总的来说就是要应付“漫长”和“寒冷”这两个关键词。
然后就是各种试参数,经过调查发现,我计划使用一个叫“星迹”的 APP 辅助完成,事后证明这是最大的败笔之一,没错后面还有败笔💔。

开拍

环顾华科四周,森林公园是个非常不错的拍摄场所,于是我在一个月黑风高之际,偷偷摸摸的潜入森林公园,架好设备,对准感兴趣的星空,开拍!
需要注意的是夜晚真的很暗,在操作相机时我都是打着手电筒照明🔦,所以拍摄的时候避免一个人单独拍摄,拉上基友来难忘今宵!
如果你的相机很智能,建议把什么自动降燥啊自动对焦之类的全部关闭,在夜空下这些东西会出很大的偏差,无法形成较好的效果。
快门时间要长,ISO 调低,广角很好。
冬季的星空最著名的就是猎户座了,四大亮星和三小星组成的猎户座,在冬季南方特别显眼。在作为一枚萌新,从他下手最好不过!如果你像我一样担心到时候认不出来,手机上下载个 Star Walk 2 — Night Sky Map是个非常好的选择。
然后我就犯了第二个错误,忘记对焦了。这个对焦有两种,如果画面中有近景的话对焦就对到近景上,否则找颗最亮的星星对焦。
按下开始拍摄的按钮后,就可以到一旁愉快的玩耍了。
这里要注意下按下快门时机身会有一定的抖动,如果你是马上拍摄的话就会造成一定的模糊。对于这个有两种解决方案:

  • 买个快门线,远程操作。
  • 定时拍摄,开下快门后过一段时间才开始拍摄。

身为一个吃了上顿愁下顿的穷苦学生,我肯定是采用第二种啦,不过经济条件可以的话最好用第一种。
拍星轨分两种,一种是超长快门时间拍一张出来,第二种是拍很多张快门时间较短的,然后合成一张图。我强烈推荐第二种,无论从可靠性还是可编辑性还是灵活性来说都是后者更好。

后期处理

就是用了垃圾的星迹 APP,居然生成 AVI 视频!还是后面效果图那样的视频!!不具有任何后期处理能力!!!

事后我研究了下,采用延迟模式拍摄多张图片就很好,不太建议大家用视频格式,因为可编辑能力跟多张照片比差远了。

效果图

星轨:

因方便浏览,我把 AVI 视频转成了 GIF 图片。

猎户座、金牛座和御夫座:

stars

这张是我拍了多张照片后生成的全景图。

总结

这是我第一次带着单反拍摄夜空,遇到了很多问题,后来也思考了很多。对于星轨拍摄,总结起来就是以下几条:

  • 场地要选好。
  • 防寒防寂寞。
  • 星星要认准。
  • 自动全关,ISO超低。
  • 对焦2种方法。
  • 拍摄2种模式。

macOS 下 OpenCV 环境搭建

16 December 2017 at 15:01

因为专业的原因,需要搭建个图像处理的开发环境。上网研究了下相关资料,再结合符合中国特色社会主义的时代背景,决定在 macOS 下用 Clion 搭建 OpenCV 等图像开发环境。

安装 Clion

Clion 是 JetBrains 公司近几年推出的 C/C++ 跨平台 IDE,由于学生免费使用并且包含 Vim 插件,所以相对于 Xcode 神一般的操作逻辑,我最终选择了 Clion。
有人问为什么不用我最喜欢的 Vim 骚遍全场呢,原因是 Vim 擅长处理小项目和临时打开一些文件,对于这种图像处理之类的大项目,还是用 IDE 来的方便,当然必须要有 Vim 插件!!!
Clion 官方主页
下载地址

安装 OpenCV

对于这种著名的开源的又不知道从何开始安装的鬼东西,我们一律用 HomeBrew 安装,省时省力又简单。

brew install opencv

安装的 OpenCV 版本应该是 3.3.1 或以后的。

创建第一个项目

安装好后怎么用呢?其实我也不太会,照着网上的教程一步一步来呗。

用 Clion 创建一个空白项目。

打开 CMakeLists.txt 配置文件,增加如下语句

find_package(OpenCV)
include_directories( ${OpenCV_INCLUDE_DIRS} )
target_link_libraries( Myexe ${OpenCV_LIBS} )

其中 Myexe 替换成你的可执行文件的名称。

将图片(如 demo.png)拷贝到项目的工作目录下(你也可以不拷贝,但是下面的图片路径就需要你自己指定)。

在 main.cpp 中输入如下代码:


#include <iostream>
#include <opencv2/opencv.hpp> //调用 OpenCV 的库

using namespace cv;

int main()
{
Mat image; // OpenCV 中图片格式为 Mat

image = imread( "../demo.png"); //读取图片
if( image.empty() ) //检查是否读取成功
{
std::cout << "Could not open or find the image" << std::endl ;
return -1;
}
imshow("demo",image); //显示图片

waitKey();
return 0;
}

运行程序,这下我们的第一个基于 OpenCV 的工程就搭建好了!

OpenCV 进阶

更多的内容请访问OpenCV 官网教程,教程给得很详细,而且有可以练手的地方,是很好的入门教程。

❌
❌