概述
由于项目需要,我在使用oepncv3.4.1调用摄像头的时候,需要设置摄像头的曝光值。本以为opencv会有很简单的方式或者接口供我调用直接实现,不曾想这么一个小需求却折腾了我一整周。
这篇文章,其实定稿也已经很长一段时间了。由于所处公司领域的原因,身为嵌入式工程师的我对于opencv这么一个图像处理库接触颇深(最近更是由于疫情期间人手不足的原因,搞了好几个月的图像算法,差点以为要转行了)。相关的资料笔记也整理了一大堆,所以就独立开设一个专栏来记录所有与opencv相关的东西。本来想以opencv3.4.1在各平台的源码编译作为该专栏的开篇,但哪些笔记还要截图排版补充一些细节完善整体流程才好发布。而这篇文章在笔记的时候刚好写的比较详细,不用怎么整理,而且很有意思,就先发这篇了。
设置曝光值很好解决,由于我是通过opencv的VideoCapture类来打开摄像头,该类提供了一个接口函数
bool VideoCapture::set(int propId, double value)
可以很方便的设置摄像头的曝光值。我只需要通过传入宏CV_CAP_PROP_EXPOSURE
调用set函数即可解决
capture->set(CV_CAP_PROP_EXPOSURE, exposure);
虽然期间考虑到一个问题,我还不知道曝光值可设置的范围,不过好在设置失败也就没有效果而已,并不会导致程序的崩溃。所以范围问题的重要程度不高。所以我就直接传递随机值进行测试了。
测试下来也发现,该接口函数确实能够改变相机的曝光值,但存在一个很致命的问题。
使用该接口函数设置完曝光之后即便相机掉电重启,之前设置的曝光参数还是会存在,并且一直处于手动曝光模式,没法恢复到自动曝光。
这就很麻烦了,当相机使用的过程中设置了曝光值之后想要设置回自动曝光没法实现。虽然过程中发现使用Windows10自带的相机软件打开该摄像头,可以恢复自动曝光模式(这也间接说明该摄像头的自动曝光可调)。但这显然不是解决问题的根本方案。
然后我就到opencv的库函数中去寻找设置相机自动曝光的方法。查找的过程中发现VideoCapture::set接口中支持的宏有一个CV_CAP_PROP_AUTO_EXPOSURE
宏,从名字看来应该就是我需要找的。但需要传入什么参数设置自动曝光不得而知。
百度了一圈发现网上普遍提及一个方法需要设置为0.25
,测试了一下不行。也有说法是范围在0-4
之间,0-2.6
为手动曝光,2.6-4
为自动曝光。试了一下也不行,无法让相机回到自动曝光模式。
在查找资料期间还发现一些资料有提及低版本的opencv(我所用是3.4.1)中并不支持
CV_CAP_PROP_AUTO_EXPOSURE
宏,opencv内部并没有对这个宏提供具体的实现代码。
但当时手上没有高版本的opencv即不太在意。后期在Ubuntu下的opencv4.1.0中测试发现设置0-2.6
可以手动曝光,设置2.6-4
可以自动曝光。
而且网上也说了这个是设置手动曝光没效果的时候设置的,但我设置手动曝光是没有问题的,我现在的问题是设置成手动曝光之后无法设置回自动曝光了。
测试还发现在Ubuntu下面设置这个宏VideoCapture::set的返回值为true
,而如果在Windows下则会为false
。
《opencv设置曝光无效的解决办法》
https://blog.csdn.net/greenlight_74110/article/details/82798136
《opencv 曝光设置》
https://blog.csdn.net/jrainbow/article/details/84033369
《RoboMaster视觉教程(1)摄像头.md》
https://www.jianshu.com/p/23b8cf9318e3
翻阅了我在百度上面能找到的所有资料,以及搜索了我能想到的所有关键字,还到opencv这个类的开发手册看了一遍,但均没能找到我想要的设置方法。
《cv::VideoCapture Class Reference》
https://docs.opencv.org/3.4.1/d8/dfe/classcv_1_1VideoCapture.html
期间在看一些blog的时候发现AMCap软件可以调节自动曝光
而AMCap就是用opencv写的,这也更加坚定了我对于oepncv可以设置自动曝光的信心。
查找资料测试得知AMCap实现opencv的曝光调节的方法很简单。通过VideoCapture::set接口传入CV_CAP_PROP_SETTINGS
宏即可实现弹出同样的设置窗口。
capture->set(CV_CAP_PROP_SETTINGS, 1);
《opencv中调整摄像机参数, CV_CAP_PROP_SETTINGS》
https://bbs.csdn.net/topics/392054079
这相当于调用opencv启动了一个带界面的程序来设置相机的参数,这个方法一定程度上确实可以满足我的需求。但是这终究不是我想要的设置方法,我想要的是在代码里面直接设置的方法,而且界面设置的方法如果程序的运行环境并不支持界面也将无法设置自动曝光。所以这确实不是我想要的最优解。测试时发现这个宏的调用在Ubuntu下不起作用,而且测试也发现,设置“CV_CAP_PROP_SETTINGS
”宏的时候,第二个参数的具体作用不明,似乎没有效果。
在多次尝试无果后,我被迫的只能去阅读opencv的源码以寻找自动曝光的实现方法。对于一个opencv小白来说,让我去看opencv的源码我内心是拒绝的。看源码本来就是一件比较痛苦的事情了,这要看的还是用C++写的源码。
因为我电脑的opencv是我到官网下载源码进行编译安装的,所以打开opencv的源码目录
不清楚源码到底是那个目录下面。查阅资料,了解到opencv的具体实现源码在modules目录下面
《2015-04-05-《OpenCV 2 计算机视觉编程手册》读书笔记》
https://www.jianshu.com/p/193a6d15ffe0
打开modules
头皮发麻,这么多文件该从何找起啊!突然想到可以在全部文件中搜索关键字查找所涉及的文件。但Windows下搜索我不会,便把源码目录modules拷贝到Ubuntu下面进行全局搜索。
后来发现我可以通过把opencv的源码工程导入到VS或Qt中查看,不过这也是后来的事情了。
《从源码学习OpenCV(一)查看源码》
https://blog.csdn.net/jelatine/article/details/100105976
输入命令
find . -type f -name “*” | xargs grep "XXX"
即可递归在当前目录下的所有目录里面的所有文件里面查找涉及XXX字符串的文字了。
我首当其冲的在opencv的源码全局搜索CV_CAP_PROP_AUTO_EXPOSURE
宏。
根据搜索到的结果进行排查,发现只有五个文件涉及到这个宏
其中cap_aravis.cpp
和cap_v4l.cpp
以及cap_dc1349_v2.cpp
均是linux下对于相机支持的库以及底层支持。而gen_dict.json
是个配置信息存储文件可以不管。剩下的就只有videoio_c.h
了。
打开之后发现仅仅有定义而已。其注释也是一些无关痛痒的设置曝光说法。
从这个结果来看,似乎在windows端opencv的源码里面确实没有对于CV_CAP_PROP_AUTO_EXPOSURE
宏做具体的实现。但为了保守起见,我还是去看了另外3个Linux下的源码文件。
我首先去看的是cap_aravis.cpp
源码文件
发现涉及这个宏的有两处
他们分别在getProperty
和setProperty
接口函数里面,而且所属类为CvCaptureCAM_Aravis
。
这不禁让我产生疑惑,因为并不是我想象中的在bool VideoCapture::set(int propId, double value)接口函数里面。
嗯,作为一个阅码无数老司机(这句话咋有点奇怪),稍加思索我便意识到VideoCapture是个封装了多层的上层类,基于多态它底层提供了各个平台的多个子实现。回过头去看CvCaptureCAM_Aravis
的定义处,
继承自CvCapture
,没见过的类,当前文件搜索一下,没有。
但期间我意外发现了文件开头注释部分有这么一段介绍
嗯?对于CV_CAP_PROP_AUTO_EXPOSURE
宏的设置难道第二个参数是设置为true和false?
有那么一瞬间,我以为找到了真理,赶紧去测试了一下
capture->set(CV_CAP_PROP_AUTO_EXPOSURE, true);
不行
capture->set(CV_CAP_PROP_AUTO_EXPOSURE, false);
也不行
有点受挫。
回过头来全局搜索“class CvCapture
”,在所涉及的文件里面没有找到CvCapture的定义处。苦苦思考半天没有想明白。既然上面都说了CvCaptureCAM_Aravis
这个类继承自CvCapture
,那么怎么可能在源码里面找不到“class CvCapture
”呢?
百度了一下CvCapture
《OpenCV参考手册之CvCapture结构体》
https://blog.csdn.net/sysstc/article/details/25126551
居然是个结构体,原来C++中结构体和类的属性很相近,既可以被类继承也可以继承类,长见识了。而且CvCapture
还是一个opencv做视频处理的上层接口常用类,只是我也没怎么用过而已。
《C++中Struct与Class的区别与比较》
https://blog.csdn.net/weixin_39640298/article/details/84349171
于是乎全局搜索了"struct CvCapture
",果然能够找到CvCapture
的定义处。
在precomp.hpp
文件里面
CvCapture
结构体里面全部都是虚函数,看来这是个全虚函数的父类。那么CvCapture应该就是为了多平台实现多态用来继承的,这也验证了我之前的猜想。
但有一点让我刚到意外的是,虽然该类的所有函数皆是虚函数,但却没有一个是纯虚函数,所以这个类还不是抽象类,这意味着这个类我是可以创建对象的,只是其中的接口都是直接返回,所以意义不大而已。
但因为CvCapture
是个全虚函数最顶层父类,没有实现源码,我就没有再去了解它的意义了。
随即我回过头来再打开另外两个涉及到CV_CAP_PROP_AUTO_EXPOSURE
宏的源码文件cap_v4l.cpp
和cap_dc1349_v2.cpp
,里面的情况和acp_aravis.cpp
别无二致,里面的主类均继承于CvCapture
,也都有实现其父类CvCapture
的虚函数接口。
值得一提的是,我在cap_v4l.cpp文件中发现了这么两行代码,这也算是给前面设置为0-4的说法的一个论证了。
分析到这里,我大概算是了解了这几个文件的作用了,他们应该都是在Linux下面为了适应不同平台环境所做的不同分支实现,但似乎线索到这里就断了。因为它们与VideoCapture
并没有搭上关系。而且我当前程序是在Windows下面做开发。所以就并不打算往这个方向继续深挖下去了。
然后我就想,查找CV_CAP_PROP_AUTO_EXPOSURE
宏的相关信息找不到什么有价值的东西了,那我就找VideoCapture::set接口看下吧。于是就在所以文件中搜索“class VideoCapture
”。
所涉及的文件不多,都看了个遍,居然没有找到定义处,可是我程序里面明明都可以使用啊。难道又是结构体?于是全局搜索一下“struct VideoCapture
”。啥都没有。全局搜索“VideoCapture
”涉及的文件又太多了,不想一个一个看。
接着我突然想到,VideoCapture
的定义处找不到我就直接找VideoCapture
的具体实现代码吧,于是又全局搜索了“VideoCapture::set
”(当时也不知道为啥不搜索构造函数或者析构函数,可能我最关注的还是这个set函数吧)
哎,这次就很顺利了,直接在cap.cpp
文件中找到了“VideoCapture::set
”接口的具体实现代码。查看具体实现代码,里面主要其实用到的是一个名为“icap
”的类指针和一个名为“cap
”的变量。
而“cap
”是在只有当“icap
”为空的时候才使用,从这点来看“icap
”比“cap
”优先级更高。但是当我在cap.cpp
文件里面搜索“icap
”和“cap
”时候却找不到它们的定义处,看来这个类指针的定义处应该还是在类的定义里面啊。弄到最后,我想要弄清楚“VideoCapture::set
”的具体实现流程还是得找到VideoCapture
的定义处啊。
正当我想再查找别的关键字时,看到搜索"VideoCapture::set
“时还涉及的另外一个文件videoio.hpp
,怀着好奇的心情打开来看一下,首先是找到了涉及”VideoCapture::set
"的地方
中间两段机翻过来是
读写属性涉及到许多层。沿着这条链可能会发生一些意想不到的结果。
有效的行为取决于设备硬件、驱动程序和API后端。
整体的意思是:底下的那个VideoCaptureProperties
枚举涉及到的变量都是用于VideoCapture
这类的,而由于涉及到硬件设备、驱动、以及API后端,所以有些枚举变量未必都有效。具体的调用接口是VideoCapture::get()
, VideoCapture::set()
。
嗯,算是一个友好的提醒和忠告。
然后我在顺便翻一下这个videoio.hpp
文件大概浏览一下内容的时候,居然在中间的位置发现了这么一处定义,Oh, my god!这是什么!踏破铁鞋无觅处,得来全不费工夫啊。这不就是我幸幸苦苦寻找的VideoCapture
类的定义处吗?
怎么在类和类名之间还给我整了这么一个宏,害我找的那么苦。
后来通过VS和Qt打开了整个工程之后一个Ctrl+鼠标点击类名就可以跳转到定义处了,科技的力量啊!
ε(┬┬﹏┬┬)3
而且也终于发现了它是没有继承于任何父类了,这也就表明了它就是提供给用户使用的最顶层类了。
这下总算是找到定义处了,中间的CV_EXPORTS_W
宏并不是在当前的文件中定义的,估计应该是为了满足opencv多平台下面编译适应的一个宏。我这个心力憔悴的菜鸡也就不打算去深究其中的机制了。简单知道这个就是定义处就差不多了。同时也在该头文件中发现了opencv的另外一个视频处理的常用类VideoWriter
的定义处。
如出一辙,也算是留个心眼,以后遇到相关问题可以找回来。
最后在底下私有变量那里找到了我前面找“VideoCapture::set
”接口实现代码时出现的两个变量“icap
”和“cap
”。
先看“icap
”,它是一个模板类Ptr,传入的参数“IVideoCapture
”,比“VideoCapture
”多了个“I
"?这又是个什么东西啊?然而我看到了上面的"cap
"变量也是同样的模板类Ptr,但传入的参数是我刚刚才接触的“CvCapture
”那么我有理由相信“IVideoCapture
”和“CvCapture
”是一个东西,都是类。
我第一反应先是全局搜索了"struct IVideoCapture
",没有找到任何东西,奇怪,居然不是结构体,紧接着便全局搜索"class IVideoCapture
"
嗯,果然是一个类。
并且就在之前找的“CvCapture
”类定义处相同的文件precomp.hpp
中,而且这个文件中还有一个“IVideoWriter
”类,从名字就可以看出它和“VideoWriter
”的相关性。最重要的是“IVideoCapture
”和“CvCapture
”极为相似,都是由全虚函数组成。区别在于“IVideoCapture
”类内部有纯虚函数,也就是说它是一个抽象类不能创建对象。
这几个类“CvCapture
”、“IVideoCapture
”和“IVideoWriter
”都在同一个文件里面,共同管理。至此,opencv的视频摄像头处理常用类“VideoCapture
”的整个实现架构我算是整体清楚了。
“VideoCapture
”内部有两个由模板控制的类指针,cap
和icap
,它们都是由虚函数组成的类“IVideoCapture
”和“CvCapture
”,然后底下有一堆接口继承这两个类。
真正的具体实现就在这些底下的类里面,通过这两个模板类的指针使得程序在调用VideoCapture
运行的时候能够访问到特定的子类。
而VideoCapture::get()和VideoCapture::set()这两个用户接口函数的实现应该就是特定子类中的getProperty()
和setProperty()
,也就是前面找到的“VideoCapture::set
”接口和“VideoCapture::get
”实现代码中“icap
”指针调用的函数。
但是,我虽然知道了“VideoCapture
”的整体实现架构,但是我还是不知道我的程序到底调用了底层的那个具体文件。线索到这里又断了。
当时分析到这里的时候其实我是已经打算向生活妥协的了,涉及这么多个文件总不能让我一个一个找吧?说实话看这些开源库的源码很多时候是一种折磨,期间你会接触到很多你平时开发中不常用到的语法机制,像这次遇到的结构体代替类,像中间涉及的模板类概念等等等等,而且期间你还要不断去分析与推敲源码开发者的意图和整个模块的代码框架,期间你还可能走不少弯路,甚至卡在一个地方很久很久。虽然最后你会收获很多,但是期间的成就感与获得感很低。所以看源码是一个很枯燥乏味的事情。而且这源码还是C++写的。
当时我走到这一步的时候,是打算直接用前面提到的设置CV_CAP_PROP_SETTINGS
宏来实现自动曝光的功能了,虽然这不是我程序设计之初想要的最优解,但作为一个过度与妥协,这个方法也算的上不错,总比用CV_CAP_PROP_AUTO_EXPOSURE
宏设置不了自动曝光强。
capture->set(CV_CAP_PROP_SETTINGS, 1);
但是在用CV_CAP_PROP_SETTINGS
宏设置的过程中,我突然有一个想法,既然这个宏调出来的界面能够设置自动曝光,那么我是否可以找这个宏的具体实现代码,一步步解剖到自动曝光的具体设置代码呢?而且我之前测试这个宏的时候有提到一点,这个宏只能在Windows下有作用,在Ubuntu下面不起作用。那么运气好的话,我是不是还可以通过找这个宏的具体实现代码,找到Windows下面调用VideoCapture::set
具体的实现代码在那个文件里面了。
运气不好的话虽然这个宏可能在多个文件里面有具体实现,当时没有多想,只要有一点希望我愿意去尝试。但是至少能够缩小范围。
于是,我又在全局范围内搜索CV_CAP_PROP_SETTINGS
宏
这次,幸运女神是站在我这边的,所涉及的文件极少!
videoio_c.h
文件里面是宏的定义,没有特别重要的信息。剩下的就是cap_dshow.cpp
文件了,看到这个文件的名字我更加确定我需要找的东西在里面了。DShow,我以前接触过的一个库,在Windows下面处理摄像头用的。
找到源码目录中的cap_dshow.cpp
文件,顺便也打开和它紧挨着的同名cap_dshow.hpp
文件。
先看头文件cap_dshow.hpp
。
继承自IVideoCapture
类,预料之中。和我之前猜想的一样,看来在Windows下我当前电脑的环境下,调用VideoCapture::set
最终会走到这个文件里面具体实现。
打开cap_dshow.cpp
,查看涉及CV_CAP_PROP_SETTINGS
宏的位置,一共有两处,一处在getProperty
接口函数里面
getProperty接口函数里面的实现不是我所关注的,我的关注点还是另外一处在setProperty
接口函数里面的CV_CAP_PROP_SETTINGS
宏实现
这个是在调用了另外一个函数,从函数的命名来看,这是在显示设置窗口。看到这个命名,我已经能够确定这个文件就是我要找的文件了。
找到这个文件之后,我验证了之前的两处猜想:
第一处:设置CV_CAP_PROP_SETTINGS宏的时候,第二个参数似乎没有效果。
因为在设置这个的时候,第二个参数根本没有参与具体实现。第二处:低版本opencv中CV_CAP_PROP_AUTO_EXPOSURE宏并没有提供具体的实现代码。
因为在这个文件中根本找不到涉及这个宏的代码。
然后继续看这个CV_CAP_PROP_SETTINGS
宏的具体实现。
调用了一个showSettingsWindow()
函数
return g_VI.showSettingsWindow(m_index);
首先我先要确定g_VI
是个什么东西?m_index
又是个什么东西?找到之前的头文件cap_dshow.hpp
,里面有它俩的定义。
g_VI
是一个static videoInput
静态类指针,而m_index
是一个int变量
先看简单的变量,全文件搜索一下,发现有几个地方涉及m_index
,构造函数初始化处,open()
函数close()
函数。
在VdieoCapture_DShow
类的构造函数里面。m_index
最开始被赋值为-1,
其中CoInitialize(0)
是Windows系统的API库函数,用于初始化COM组件的,COM组件是什么东西?我倒是没怎么接触过。先不管,继续往下面看。
《CoInitialize》
https://baike.baidu.com/item/CoInitialize/4114580
而open函数的源码中,我看到这么一段
有对m_index
进行赋值修改操作,而赋值变量index
来自于构造函数的参。由此,我可以大胆推断出m_index
存储的就是具体相机的索引。
然后就是g_VI
了,它是videoInput
这个类的静态指针,那么showSettingsWindow()
函数应该就在这个类中了,而具体的自动曝光实现应该也在里面了。
找videoInput
这个类的源码倒是简单,它就在当前文件下定义的,和VideoCapture_DShow
类放在一起。
其showSettingsWindow()
函数的实现也在当前文件。
分析代码,可以看到代码中涉及到InterlockedIncrement()
和InterlockedDecrement()
,这两个函数是多线程的时候为了保护变量的原子性操作而带有互斥锁机制的加减函数,结合videoDevice* dev = VDList[id];
设备从数组中选择,以及注释。可以知道opencv是可以打开多个摄像头设备共同管理的。这里的互斥是为了不让不同相机之间的设置交叉混乱。
《InterlockedIncrement函数详解》
https://blog.csdn.net/zhongguoren666/article/details/7541778
使用getDevice()
获取设备成功之后,即调用_beginthread()
启动线程运行basicThread()
任务函数。
_beginthread(basicThread, 0, dev);
剩下的就是一些不成功结束的收尾操作,所以重点就在任务函数basicThread()
里面了。
而basicThread()
任务函数也没有让我难找,就在showSettingsWindow()
函数上面。
除了两行定义赋值之外,剩下两行代码中InterlockedDecrement()
是和showSettingsWindow()
中的InterlockedIncrement()
上面有使用过,就是哪个带有互斥机制的自加函数。所以剩下的就只有ShowFilterPropertyPages()
是起实际性作用的了。
ShowFilterPropertyPages()
函数的定义也在当前文件中。搜索一下即可找到。
兜兜转转垮了这么多层,终于找到了实际性的代码了。但是这里的代码我一行也没看懂。为了看懂这三十多行代码,却花了我两天时间。
期间我看了不下十篇文章,其实主要是认识了Windows下的COM组件。就前面在VdieoCapture_DShow
类的构造函数里面提到的。
看过的主要文章有(按我查找到的时间顺序):
《ISpecifyPropertyPages接口》
https://docs.microsoft.com/zh-cn/windows/win32/api/ocidl/nn-ocidl-ispecifypropertypages
《COM组件》
https://baike.baidu.com/item/COM%E7%BB%84%E4%BB%B6/3351509
《C++ 编程之QueryInterface函数(一)》
https://blog.csdn.net/sinat_32596537/article/details/53649051
《C++设计模式之简单工厂模式实例》
https://www.jb51.net/article/55858.htm
《C++ COM编程之接口背后的虚函数表》
https://www.jb51.net/article/55881.htm
《C++ COM编程之什么是接口?》
https://www.jb51.net/article/55880.htm
《怎么通俗的解释COM组件?》
https://www.zhihu.com/question/49433640/answer/115952604
《最简单的基于DirectShow的示例:获取Filter信息》
https://blog.csdn.net/leixiaohua1020/article/details/42649379
《c++ 调用com组件步骤》
https://blog.csdn.net/weixin_41915560/article/details/80065959
《c++——HRESULT用法、实例》
https://blog.csdn.net/liang841451955/article/details/80359362
《IBaseFilter :: QueryFilterInfo》
https://docs.microsoft.com/en-us/previous-versions/aa916619(v=msdn.10)
我花了近两天时间,看完了上面这些文章的内容,终于大概能够看得懂代码是什么意思了,也知道COM组件是一个被历史淘汰的东西了。其实在我初步了解COM组件之后,我就不太想知道它具体源码是怎么写的了,因为这里其实就是在调用COM组件,而COM组件我是没办法拿到它的源码的,所以研究了也白搭。不过最后还是把所有的这些文章给看完了,也大概能看懂ShowFilterPropertyPages()
函数的实现流程了。
写在最后
至此,我整个在源码中寻找opencv3.4.1的自动曝光设置历程在带着遗憾中结束了。我也知道了我想要知道的所有东西了。虽然花的时间和得到的回报不成正比,中间走了不少弯路。后面查资料时发现,可以用Qt或者VS打开opencv的整个源码工程。如果一开始就发现这个方法也就不用那么麻烦的用土方法搜索关键字了,很多地方可以通过快捷键自己跳转。那么所需的时间可以减少大半,也不会走那么多弯路。所以工具很重要,路更重要。
最后,我前后花了那么多时间去探索以及记录完成这篇文章。总算是可以证明opencv3.4.1没有提供独立接口给用户设置相机自动曝光了。虽然因为这样,我可能得修改我原本程序的整个框架了,以使用“
CV_CAP_PROP_SETTINGS
”宏给我提供的设置界面来设置相机的自动曝光,虽然这不是我最初期望的结果。但是当有人问起,我的程序为什么不独立提供一个自动曝光的设置按钮,而要打开另外一个界面来设置那么麻烦时,我可以把这篇文章甩他脸上去了。
零BUG是原则性问题。
最后
以上就是迷你狗为你收集整理的在源码中寻找opencv3.4.1的自动曝光设置历程-opencv的全部内容,希望文章能够帮你解决在源码中寻找opencv3.4.1的自动曝光设置历程-opencv所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复