原文转自:
http://blog.csdn.net/tutuguaiguai0427/article/details/6646051
这阵子,确切说这几天,还是看了好多东西的。虽然无用功居多。
上篇日志说的东西做完以后暂时就没事了,然后窝实验室吹着空调做我的小屋。
后来实在觉得无聊找了点事做。
第一天是打算消除视频水印的。其实最土或者说其实最有效的方法是单帧PS,但是,明显我不是这么勤快的人。我学的可不是PS,总觉得这是搞设计之类的人用的。
然后记得上次在xiaotie博客看过程序除水印的,又翻出那篇文章,具体代码没有,只有思路。
虽然他说半透明的水印才可以去,不然修复不了。
但,为了消除那个彻底不透明的水印,我还是试了他的方法。
1.手动做mask图片。想想一个视频也就P一个图还是能承受的,如果不是手动的话这个程序可就麻烦了,何况效果不一定好。我先把视频用opencv播放,放一帧写一张图片,这样可以挑一张纯一点的图片方便抠水印。
2.试验单张图片效果。随便载入一张有那个水印的图片,然后用PS的水印图片做MASK,用inpaint函数。调了几下半径,效果也就一般,可以去掉水印但是那一块地方总有杂色。如果视频本来就不清晰,杂色比较多,或者需要重新打上你自己的水印(这个比较邪恶)那还行。MASK不同出来的效果也不同,我试过精确按文字形状的和直接抹成一条的各种mask。有的出来是一团杂色,有的则是一小块一小块的。
3.其实我没做3,第二步效果好的话其实第三步就是类似于批处理了,就是播放视频,读帧,处理,写帧。然后就木有然后了。
需要注意的是用inpaint函数的时候,应该说用mask的时候,那个mask不是直接用PS涂成黑白就可以的。mask需要单通道8位的图片,试了几次失败以后我就把图片载入,然后在程序处理成8位单通道。处理完也可以存盘,然后以后直接读那个图作为MASK就可以了。处理的时候用threshold()函数处理一下,每个像素不是0就是1。用mask的时候就不处理0的点了。
然后那个就告一段落了,再做一个视频捕捉,播放,截图,录制功能的软件,图片还要增加文字和当前系统时间,界面用C#。
出于惯性思维直接打开opencv,一小时之内绝对能搞定。然后C#写界面,C++托管,搞定。然后悲剧的根源就是试图将opencv跳出的框塞进C#,反正就那效果,懂得。
其实之前就有这个问题,C#+opengcv那个播放视频的窗口固定不了,只能是从界面蹦出来的。但是当时逃避了一下,后来改用了WMP的控件,因为那次只是播放本地的视频,WMP还直接支持滚动条前进后退的,真爽。但这次是逃不过了。纠结于各种诸如bitmap、句柄之类的问题后,发现可以用设置父窗口的办法。
[cpp] view plaincopy
- cvNamedWindow("Capture");
- // 将这个窗口缩至最小
- cvResizeWindow("Capture",1,1);
- // 获取窗口句柄
- HWND hWnd = (HWND) cvGetWindowHandle("Capture");
- // 获取该窗口的父窗口句柄
- HWND hParent = ::GetParent(hWnd);
- // 获取C#form1窗口句柄
- HWND hwnd1=::FindWindowW(NULL,L"Form1");
- //HWND hwnd2=::FindWindowEx(hwnd1,NULL,NULL,L"pictureBox1");//这个居然就失败,会定位到桌面的左上角HWND hwnd3=::FindWindowEx(hwnd1,NULL,NULL,NULL);
- if(!hwnd3)cvNamedWindow("C");//其实这句作用类似于message,我随手写的,神奇的是,不加这句的时候怎么都不行,一加居然就好了,然后我也就没改
- // 将GUI窗口设置为视频播放窗口的父窗口,使视频在 GUI 的指定区域播放
- ::SetParent(hWnd, hwnd3);
- // 隐藏所创建的视频播放窗口 ::ShowWindow(hParent, SW_HIDE);
但是这样还是会先跳出一个框,然后它就钻进C#的界面了,估计电脑卡会很明显。呜呜。
之前用opencv的时候都是用waitKey的办法用键盘控制录制、截图之类的功能。
但是按键的时候焦点肯定需要在opencv的窗口,于是又悲剧了。
花了很久都没有搞定,不知道怎么让焦点选到那个跳出的窗口,此时已经是隐藏了的。
反正我到现在还不知道怎么搞。在这荒凉到长草的博客里,我想应该也不会有几个人看我日志,然后就更没什么人会解答这个问题了吧。
想了很久,觉得其实就这样几个思路,一是想办法把那个隐藏的设为焦点,二是传递事件,从C#传到dll里的C++,三是opencv写的那部分只返回图片,还是要bitmap的。
前两个我都失败了,第三个各种纠结以后发现如果不在opencv转换的话也不行,C#和c++都只认识自己的图片的类型,据说CLR也是可以支持C#那个,但是我的不行。
opencv转换有一个函数,2.2版本刚好取消,有人把它抠出来,我添加以后提示缺少一个头文件,加入以后发现是MFC的,然后配置也要改,改完不支持原来的。总之,也失败了。
求助师兄的时候他说那些按键的控制不能写在opencv,必须从opencv返回图片,至于转换他是内存RGB流写成bitmap。于是,我知道,我的路走不下去了。等转换完这效率都不知道啥样了。
网上搜的那些大部分都用的是emgu,在C#用托管用opencv的貌似不多。我也发现这样调试不方便。
继续挣扎了很久,未遂,决定用MFC,但是,又放弃了,重回C#。
这次选择了emgu。果然很方便,不用托管,函数也现成。
满怀希望的运行,发现摄像头显示的画面始终黑色,自己加的文字可以看到。
去emgu自带的例子运行,也是这个情况。
然后我就崩溃了,上次用emgu就是各种配置问题,当时opencv和emgu都换成64位就可以了,这次连64都不行啊。程序在别人32的机子上跑,emgu换成32位,工程也选择32位,连一帧都没取到。ORZ。
挣扎了很久我决定继续放弃emgu,然后,目标转向Aforge.NET。当时就听说它很强大但是资料很少。山穷水尽的时候管它有没有资料,反正摄像头捕捉这种对视觉库本来就感觉有点杀鸡用牛刀的意思。从来没接触过这个,下载,安装。发现最新版本是27号才发布的,里面刚好添加了写视频文件的新的类。NICE。
跟emgu一样,开发效率也很高。这次吸取教训先试试系统自带例子能否运行。事实证明很成功。
放心大胆的写。也没多久就OK了。运行。又崩溃。那个新添加的库无法加载。"Could not load file or assembly ‘AForge.Video.FFMPEG.dll‘ or one of its dependencies. The specified module could not be found."想死的心都有了。
这个库果然资料很少。找到官网的论坛,发现整个论坛AFoge.NET Framework部分只有为数不多的人发个帖子问问题,然后基本只有管理员在回答。
管理员的location还是英国。不知道是哪国人,反正都是英语发帖。
发了个帖子问完以后因为上一天寝室太热一整晚没睡着所以就趴着睡了觉。睡醒发现管理员回复了。让我把Externals\ffmpeg\bin下的dll自己拷到工程的output文件夹。照做以后
“Mixed mode assembly is built against version ‘v2.0.50727‘ of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.",继续把错误信息发到帖子上。很快管理员就回复了。真好的人啊。给了我一个帖子的链接,是google出来的结果,还很含蓄的告诉我要勤于google。汗。
第一种方法是修改app.exe.config
[html] view plaincopy
- <?xml version="1.0"?>
- <configuration>
- <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration>
第二种是把4.0降下来。
因为没有成功编译,所以我没有那个config文件。(后来想想真傻,把那个库注释掉不就行了么。)
所以只能降成.NET3.5。还自己编译了2.0的dll。再编译我的工程。结果那个之前出问题的dll居然依赖.NET4.0的文件。ORZ。
于是我只能换回来4.0。这时候居然发现可以运行了说。但保险起见我还是把config给修改了。
再跑的时候发现录制的时候我可以用USB的摄像头,笔记本的不能用。预览都可以的。
再问管理员GG,人家又迅速答复了,说这个库不认你用的是啥设备,应该是别的问题。
然后当我把fps设置去掉的时候,自带的可以用了,USB的罢工了。
之后就是尝试各种fps,发现设置8的时候都可以用。
用系统自带的例子测了下摄像头的fps,USB的就8-9,自带的9-10的样子,因为那个是动态测量的。
然后就只能设fps,试试会不会挂了。
还有之前说的加时间加文字。时间很好实现,C#有对应的函数。但opencv是不支持添加中文的字符串的,emgu所以也不支持。用aforge.NET的时候就可以了。opencv下有人是安装字库来实现的,看着好复杂。
至于很多人也有的一个问题,就是录进去的视频特别快。尤其我这样添加了时间,走快了很明显。
今天终于想通了。我太高估我摄像头了。AVI的帧率设的25,以前没发现摄像头连它一半帧率都没到,也就是一秒才捕10帧,我楞写25帧到avi,当然就走的快了,再加压缩的时候应该也是有损失的。但是当我把文件设到很低的时候有时候有会出错,跟先前设fps的时候一样的错误,说视频文件无法打开(其实就是创建)。
写到这里的时候我突然在想,如果还是fps25,忽略连贯的问题,只考虑准确走时,也许可以设一个定时器,固定时间写入,不管有没有新帧,反正某个变量里面有新帧就替换,没有就继续写原来的。一会试试,这个估计不太花时间。如果还是不行就先这样吧。
因为现在有新任务了,做视频摘要。
贝贝加油,哦耶。