likes
comments
collection
share

基于节点编辑的openCV

作者站长头像
站长
· 阅读数 16

引子:

opencv学习梯度不算很平坦,其中一个很重要的原因就是cv复杂度,cv中函数其特定的使用场景,对不同函数使用的参数不同,结果会差距很大。cv虽然提供了快速gui接口,也可以用cvui直接渲染控件到界面上,简单的任务基本应付。但对一些复杂算法,除了需要大量的方法、参数微调之外,还需要有记录和分析对比等一系列数据报告。前一段时间在学习Blender的节点系统,参数调节所见即所得非常直观,工作效率大为提升。试用一段时间后感觉可以在opencv中搞点动作,用最直观的方法来开发opencv功能。

选型

但在节点系统选型上,纠结了很久,imgui-node-editor是第一选择,因为它依赖少,跨平台性很好,渲染上显示上没有太大的缺陷,但是没有节点计算逻辑涉及,就是说自己去实现节点计算逻辑,缺乏较好的应用案例,这也是我最终放弃imgui-node-editor的一个主要原因。

Litegraph.js 是基于javascript的,互交以canvas为基础的,原生节点拿来可就用。以此为基础,可以实现大部分界面互交。虽然关于litegraph.js开发的资料比较少,但是litegraph.js本体就是一个很好的学习案例,可以参考如shader节点、MIDI处理等模块,webglstudio.js-master也非常值得参考。另外litegraph.js也是支持节点计算和节点拓展功能。自定义节点写起来比较清晰,我后面会花一点时间来介绍。

js和python接口:EEL是一个可选项,在python程序中标注下接口,即可以通过js来访问该接口以此来执行python函数,同样道理,也可以在Web中标注函数接口,让python来调用该接口进行页面更新。EEL可以作为一个服务器后台程序运行也可以一个Chrome独立程序直接运行。

图像接口:基础对象如数值、字符串等都可以方便的传输,图像稍微麻烦点,传输需要用到base64格式作为中间格式往来于各个节点之间,python接口在收到base64格式的参数后,转换成为np的array格式后即可进行后续处理,计算结束后再以base64格式返回js。

举个简单例子:

常规方法

比如需要对图像做一个消除孤立点的工作,所需的python代码如下,代码需要对图像做几步操作,打开原始图像,一次dilate,一次Canny,一次connectedComponentsWithStats,最后根据阈值进行孤立点涂色或标注等等,最后输出图像,代码如下

import cv2
import numpy as np
filename="image/test.jpg"
img = cv2.imread(filename,0)
kernel = np.ones((3,3),np.uint8)
dilate = cv2.dilate(img,kernel,iterations = 1)
canny1=cv2.Canny(dilate,100,200)
_, labels, stats, centroids = cv2.connectedComponentsWithStats(canny1)
for istat in stats:
    if istat[4]<120:
        if istat[3]>istat[4]:
            r=istat[3]
        else:r=istat[4]
        cv2.rectangle(canny1,tuple(istat[0:2]),tuple(istat[0:2]+istat[2:4]) , 0,thickness=-1) 
cv2.imwrite('canny1.jpg',canny1)

我们的方法

通过节点实现的,开发的界面如下 基于节点编辑的openCV

一个典型节点的例子,旋转图片,两个接口,有两个控件

基于节点编辑的openCV

第一个参数控制图像旋转的角度,用拖动控制角度的大小 第二个参数控制图像是否需要保留裁剪(图像原始大小会改变)

节点功能划分不一定非常科学,所以按颜色、输入输出、变换、算子来划分。已经实现的Opencv节点如下,

颜色

名称简介
rgbrgb三色
hsvhsv三色
hsv2rgb颜色系统转换
rgb2hsv颜色系统转换

输入

名称简介
image文件图像输入
camera摄像机输入
weburlWeb文件视频输入
#### 输出
名称简介
----
Preview图像显示
Save image图像保存

图像变换

名称简介
rotate旋转
scale拉伸
shape获取大小
Split分色
Merge合色
connectedComponents联通区域

图像算子

名称简介
Threshold旋转
Canny拉伸
Gauss高斯模糊
Erode腐蚀
Dilate和膨胀
Filter筛选

标注

名称简介
Hist直方图
Drawstr标注文本(不支持中文)
Rect标注矩形
Line标注线形

集合操作

名称简介
each对每个对象操作

Litegraph节点接口实现

为了实现对opencv图像功能的封装,除了需要进行节点初始化外,还自定义节点包括如下内容: 输入/输出节点、属性、节点部件(用于具体参数的控制或其他) 添加输入节点,第一个参数是节点名,第二个参数是节点类型,类型不同不允许连接

输入输出

//初始化阶段
this.addInput("A","number");
//添加输入节点,调用方式同输入节点
this.addOutput("A+B","number");
//其次需要实现liteGraph Node几个重要接口,最后要注册自己的节点

节点执行

//OnExecute阶段
//获得第一个输入节点的内容
this.getInputData(0);
//输出值到第一个输出节点
this.setOutputData(0,value);
//获得数据
A = getInputData(0)
//做点什么
var B = do_something(A)
//返回数据
setOutputData(0,B)

节点属性

属性很简单,是可以被序列化的内部变量,结构也不难

    this.properties = {
        kernel_size: 5,
        iterate_times: 1,
        kernel_type:"MORPH_RECT",
   };

执行

Litegraph.js 会根据连接结构,自动计算节点优先级,决定哪些节点先计算,哪些节点后计算。这里只需要把每个节点的”任务”安排好,坐享其成即可,看上去是不是很简单。 OnExecute接口在graph.runStep() 或graph.run() 执行时会被调用,runStep()是进行指定有限数量,run则是不断进行计算直到接受到stop()信号,在计算负荷较重的场景,建议使用runStep()替代run()

节点高级内容

节点部件

包括基本的组件: slider 、text、button都是一致的

text输入的时候会出现一个输入框,在触屏的环境没有试验过,这个困扰了我很久很久,到最后才发现是css引用出了问题,eel调试js还是要用chrome的日志来解决,这和js调试是一致的,

基于节点编辑的openCV

slider 滑轨

基于节点编辑的openCV

combo 类似于下拉框

基于节点编辑的openCV

toggle 类似于checkbox

基于节点编辑的openCV

缺点:

没有color picker ,slider仅支持浮点,但都不是大问题,对于自定义节点绘图,使用此接口进行二次开发,当节点塌陷的情况不需要执行,静态为主的节点可以绘制到image对象中减少2d重绘,背景绘制可以参考如下代码

node.onDrawBackground = function(){
  if(this.flags.collapsed)
    return;
  ctx.save();
  ctx.fillColor = "black";
  ctx.fillRect(0,0,10,this.size[1]);
  ctx.restore();
  }

类似的js问题还有不少,

比如that和this的问题,js老鸟都懂的

还有比如 EEL返回值的问题

之前是这样想的,结果一直取不到,折腾了将近一个礼拜

var B = eel.color_filter(A,low,upper);
this.setOutputData(0,B);

后来只有阅读eel的源码,知道eel返回的是一个promise对象,因为以前做js异步编程的机会比较少,没真正学透造成的

var B = eel.color_filter(A,low,upper);

B().then(
	(data)=>{
		this.setOutputData(0,data);
	},
	(err)=>	{this.setOutputData(0,"data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=");}
)

这三个接口仅在需要处理用户互交的场景使用,比如绘图、标记等,可以参考源码CurveEditor部分来学习。

onMouseDown()
onMouseMove()
onMouseUp()

基于节点编辑的openCV

效果展示

gitee似乎没法上传了,github代码地址如下 github.com/touchmaker/…

eel_run.py     <-- Python scripts
switch.py
web/           <-- Web folder
  test01.jpg
  test02.jpg
  test03.jpg
  main.html
  css/
    menu.css
  js/
    litegraph.core.js
    comm.js
    curvenode.js
    nodecv.js
    menu.js

基于节点编辑的openCV

文章写到这里,觉得屏幕前的自己比较磨叽

项目从开始到现在陆陆续续做了2个月左右,自己写的代码绝没有超过2000行,能用如此精简的代码实现该需求,自己也感到不可思议,

我只做代码的搬运工,自然也没有必要孤芳自赏,稍微修改后转投github,希望有兴趣的同志一起加入,维护和issue问题,提出想法

很多同学现在的也在磨刀霍霍准备跳槽,不管是做前端的还是后台猴子,能坚守在一线的程序员越来越少了

转载自:https://juejin.cn/post/7148329447014432781
评论
请登录