OpenCV是一个拥有20年持续发展历史的图书馆。 开始挖掘自己,寻找目的地的年龄。 是否有任何以此为基础的项目使一个人的生活更美好,更快乐? 你能自己做吗? 为了寻找答案并渴望发现以前未知的OpenCV模块,我想构建“做得很漂亮”的应用程序-这样一来首先是“哇”,然后才说“哦,是的,这是计算机视觉”。
第一篇文章的右侧是对世界艺术家摄影风格转移的实验。 从本文中,您将了解过程的核心,以及相对较新的OpenCV.js(OpenCV库的JavaScript版本)。

风格转移
机器学习的反对者会原谅我,但今天的文章的主要内容将是深度卷积网络。 因为它有效。 无法在OpenCV中训练神经网络,但是您可以运行现有模型。 我们将使用经过预先训练的CycleGAN网络。 非常感谢他们的作者,他们提供了完全免费的下载网络,该网络将苹果图像转换为橙子,将马图像转换为斑马,将卫星图像转换为地图,将冬季照片转换为夏季照片,等等。 此外,网络训练过程使您可以同时使两个发电机模型同时在两个方向上工作。 也就是说,通过讲授冬天到夏天的转变,您将获得一个在夏天照片中绘制冬天风景的模型。 无法拒绝的独特报价。
在我们的示例中,我们采用将照片转换为艺术家绘画的模型。 即,文森特·梵高,克劳德·莫奈,保罗·塞尚或日本版画浮世绘的全部流派。 也就是说,我们将拥有四个独立的网络。 值得注意的是,为了训练每张照片,没有使用艺术家的一张照片,而是使用了整张图片,因此作者试图训练神经网络,以不改变一件作品的风格,而是采用写作风格。
Opencv.js
OpenCV是用C ++开发的库,而对于其大多数功能,可以创建调用本地方法的自动包装器。 正式地,支持Python和Java语言的包装器。 此外,还有针对Go和PHP的定制解决方案。 如果您有使用其他语言的经验,那么最好了解使用哪种语言,并感谢他们的努力。
OpenCV.js是一个因2017年的Google夏季代码计划而获得生命权的项目。 顺便说一下,一旦深度学习模块OpenCV本身被创建并在其框架中进行了显着改进。 与其他语言不同,目前,OpenCV.js并不是JavaScript中本机方法的包装,而是使用LLVM和Clang使用Emscripten进行的完整编译。 它允许您从C和C ++应用程序或库.js
,例如可以在浏览器中运行。
举个例子
#include <iostream> int main(int argc, char** argv) { std::cout << "Hello, world!" << std::endl; return 0; }
在asm.js
编译
emcc main.cpp -s WASM=0 -o main.js
并加载:
<!DOCTYPE html> <html> <head> <script src="main.js" type="text/javascript"></script> </head> </html>

您可以按照以下步骤(每晚构建)将OpenCV.js连接到您的项目:
<script src="https://docs.opencv.org/master/opencv.js" type="text/javascript"></script>
用JavaScript手动编写的,用于读取图像,使用相机和其他东西的附加库也可能有用:
<script src="https://docs.opencv.org/master/utils.js" type="text/javascript"></script>
上传图片
可以从canvas
或img
等元素读取OpenCV.js中的img
。 这意味着直接将图像文件下载到它们仍然是用户的任务。 为了方便起见,当单击按钮从磁盘上选择图片时,辅助功能addFileInputHandler
将自动将图像加载到所需的canvas
元素中。
var utils = new Utils(''); utils.addFileInputHandler('fileInput', 'canvasInput'); var img = cv.imread('canvasInput');
在哪里
<input type="file" id="fileInput" name="file" accept="image/*" /> <canvas id="canvasInput" ></canvas>
重要的一点是, img
将是一个4通道RGBA图像,这与创建cv::imread
图像的通常cv::imread
不同。 例如,当从其他语言移植算法时,应考虑到这一点。
使用渲染,一切都很简单-只需使用所需canvas
的id
(期望RGB或RGBA)调用imshow
。
cv.imshow("canvasOutput", img);
演算法
整个图像处理算法是神经网络的启动。 假设内部发生的事情仍然是不可思议的,我们只需要准备正确的输入并正确解释预测(网络输出)即可。
在此示例中考虑的网络接收float
值在区间[-1, 1]
中的四维张量。 每个尺寸(按变化速度顺序)是图片,通道,高度和宽度的索引。 这种样式称为NCHW,张量本身称为Blob,二进制大对象。 预处理任务是转换强度交错的OpenCV图像,该图像在NCHW Blob中具有unsigned char
类型的值[0, 255]
的间隔,范围为[-1, 1]
。

下诺夫哥罗德克里姆林宫的一块(一个人看到)

交错视图(OpenCV的存储方式)

平面图(网络需要什么)
作为后期处理,有必要执行逆变换:网络返回NCHW Blob,其值的间隔为[-1, 1]
,必须将其重新打包到图片中,并标准化为[0, 255]
并转换为unsigned char
。
因此,考虑到读写OpenCV.js图片的所有功能,正在逐步形成以下步骤:
imread -> RGBA -> BGR [0, 255] -> NCHW [-1, 1] -> [] [] -> NCHW [-1, 1] -> RGB [0, 255] -> imshow
查看生成的管道,就会出现问题,为什么网络无法在交错的RGBA上立即工作并返回交错的RGB? 为什么像素排列和归一化需要额外的转换? 答案是神经网络是对特定分布的输入数据进行转换的数学对象。 在我们的案例中,她接受了以这种形式接收数据的培训,因此,为了获得所需的结果,有必要重现作者在培训中使用的预处理。
实作
我们将运行的神经网络以二进制文件的形式存储,必须首先将其加载到本地文件系统中。
var net; var url = 'style_vangogh.t7'; utils.createFileFromUrl('style_vangogh.t7', url, () => { net = cv.readNet('style_vangogh.t7'); });
顺便说一下, url
是文件的完整链接。 在这种情况下,我们仅将文件上传到当前HTML页面旁边,但是您可以将其替换为原始源 (在这种情况下,下载时间可能会更长)。
从canvas
读取图像并将RGBA转换为BGR:
var imgRGBA = cv.imread('canvasInput'); var imgBGR = new cv.Mat(imgRGBA.rows, imgRGBA.cols, cv.CV_8UC3); cv.cvtColor(imgRGBA, imgBGR, cv.COLOR_RGBA2BGR);
创建一个4D Blob,其中blobFromImage
函数使用归一化常量将其转换为float
数据float
。 然后-启动网络。
var blob = cv.blobFromImage(imgBGR, 1.0 / 127.5,
结果将转换回所需类型的图像以及值[0, 255]
的间隔
目前,OpenCV.js正在半自动模式下构建。 从某种意义上说,并非所有模块和方法都从JavaScript接收相应的签名。 例如,对于dnn模块,有效功能的列表定义如下:
dnn = {'dnn_Net': ['setInput', 'forward'], '': ['readNetFromCaffe', 'readNetFromTensorflow', 'readNetFromTorch', 'readNetFromDarknet', 'readNetFromONNX', 'readNet', 'blobFromImage']}
实际上,最后的转换是将blob分为三个通道,然后将它们混合成图片,这可以imagesFromBlob
方法来执行,该方法尚未添加到上面的列表中。 也许这将是您对OpenCV开发的第一项贡献? ;)
结论
作为演示,我在GitHub上准备了一个页面,您可以在其中测试结果代码: https : //dkurtaev.imtqy.com/opencv4arts (注意!下载约22MB的网络,可节省流量。建议您为每个新图像重新加载页面,否则质量随后的处理会以某种方式严重失真)。 准备好进行长时间的处理或尝试调整图像的大小,这将是滑块。
在撰写文章并选择将要变成她的脸的图像时,我意外地发现了我的朋友的照片,其中描绘了我们城市的克里姆林宫,所有东西都汇聚在一起-想出了文章的名字,才觉得应该是那样。 我建议您在自己喜欢的地方的照片上尝试该应用程序,也许在评论或私人信件中讲述一些有趣的事情。
来自我-一个有趣的事实。 下诺夫哥罗德和下诺夫哥罗德地区的大多数居民在“适合”一词的意义上使用“下车”(找到一个自由的地方)。 例如,问题“我们会洗车吗?” 意思是“我们的车上有足够的空间吗?”,而不是“我们可以收拾你的车吗?”。 当来自其他地区的学生来我们这里进行暑期实习时,我们很乐意告诉您这一事实-许多人都感到非常惊讶。
有用的链接