imagepy库相关知识点——opencv-plgs包
发布日期:2021-05-08 05:03:28 浏览次数:22 分类:原创文章

本文共 18055 字,大约阅读时间需要 60 分钟。

OpenCV的-PLGS

**简介:** opencv不需要太多介绍,它是一个着名的计算机视觉库。ImagePy是一个交互式图像处理框架,可以包装任何基于numpy的库。并支持多通道,imagestack,lookuptable,roi,宏记录器......它是一个插件系统(就像ImageJ一样,但更方便)。这个项目是用于ImagePy插件的opencv的包装器!

现在这只是一个开始,我包含了一些opencv的算法,旨在介绍如何编写ImagePy插件,本文档中的Demo具有代表性。

执照

我知道许多基于numpy的项目都有BSD许可证,但是,对不起,我使用wxpython作为ui框架,因此,必须在LGPL下。

大型机

它是ImagePy的MainFrame,就像ImageJ一样。而ImagePy包含许多常见的功能,如打开图像,保存图像,做一些过滤,做一个roi,用铅笔绘图......它需要wxpython作为ui,Numpy作为基础结构,匀称地对待roi和scipy。 ndimage to so dome common filter。但是这个项目致力于为opencv做一个包装器。

做一个简单的过滤器

# - * - 编码:utf-8 - * 从 imagepy.core.engine导入过滤器导入 cv2

 

 

class Plugin(Filter):

标题= '拉普拉斯'

注释= [ '所有',' auto_msk ',' auto_snap ' ]

def run(self,ips,snap,img,para = None):

return cv2.Laplacian(img,- 1)

这些梯度算子是最简单的滤波器,没有参数。

  1. 类名必须是Plugin
  2. 标题是必要的,是插件的id,在菜单中显示。
  3. 设置注释,告诉ImagePy为您做什么。
  4. overwrite run方法返回结果

过滤器是引擎之一,意味着需要一个图像,然后对它进行一些更改,它有这样一种类型的run方法:

  • ips是图像的包装,带有一些其他信息(查找表,roi ......)
  • snap是图像的快照,如果注释中为“auto_snap”,ImagePy会将图像复制到snap befor run。(对于许多过滤方法必须在缓冲区中实现)
  • img是您正在处理的当前图像。
  • para是您获得交互的参数。(这里没有)

注意非常重要

  • 这意味着这个插件适用于所有类型的图像。
  • auto_snap表示ImagePy执行快照处理,然后您可以使用撤消。
  • auto_msk表示当图像上有一个roi时,插件只会影响像素。
  • 更多详细信息,请参阅!

 你看,我们没有编写处理彩色图像的代码,但是它有效,我们可以在图像上绘制ROI,只改变ROI区域!我们可以撤消持续的操作。即使它是一个图像堆栈,ImagePy会问你是否运行每一片!

使用参数过滤

# - * - 编码:utf-8 - * 从 imagepy.core.engine导入过滤器导入 cv2

 

 

class Plugin(Filter):

标题= '康力'

注= [ '所有',' auto_msk ',' auto_snap ','预览' ]

para = { ' sigma ':2,' low ':10,' high ':20 }

视图= [(浮子,(0,10),1, '西格玛','西格玛',' PIX '),

('滑动',(0,255),0,' low_threshold ','低'),

('滑动',(0,255),0,' high_threshold ','高')]

 

def run(self,ips,snap,img,para = None):

l = int(para [ ' sigma ' ] * 2.5)* 2 + 1

cv2.GaussianBlur(snap,(l,l),para [ ' sigma ' ],dst = img)

return cv2.Canny(img,para [ '低' ],段[ '高' ])

很多Filter需要一些参数。就像Canny一样。我们只需要多做一点。

  1. para是一个dict对象,它包含您需要的参数。
  2. view告诉ImagePy如何在这个插件运行时进行交互,(float,(0,10),1,'sigma','sigma','pix')表示它是0到10之间的一个浮点数,title是sigma,对应于单位为pix的sigma参数。更多详细信息请参见!

在note中添加'preview',然后在调整参数时,ImagePy立即运行此插件

# - * - 编码:utf-8 - * - 来自 imagepy import IPy

import numpy as np,cv2

from imagepy.core.engine import Filter

class Plugin(Filter):

title = '自适应阈值'

注意= [ ' 8位',' auto_msk ',' auto_snap ','预览' ]

para = { ' max ':255,' med ':' mean ',' size ':9,' offset ':2,' inv ':False }

视图= [(INT,(0,255),0,' MAXVALUE ','最大值',' '),

(list,[ ' mean ',' gauss ' ],str,' method ',' med ',' '),

(INT,(3,31),0,'块大小','尺寸',' PIX '),

(INT,(0,50),0,'偏移','偏移',' '),

(bool,' binary invert ',' inv ')]

#过程

DEF 运行(自, IPS,卡扣, IMG,第 = 无):

med = cv2。ADAPTIVE_THRESH_MEAN_C 如果 para [ ' med ' ] == '表示' 其他 cv2。ADAPTIVE_THRESH_GAUSSIAN_C

mtype = cv2。THRESH_BINARY_INV 如果对[ ' INV ' ] 其他 CV2。THRESH_BINARY

cv2.adaptiveThreshold(snap,para [ ' max ' ],med,para [ ' inv ' ],para [ ' size ' ],para [ ' offset' ], dst = img)

自适应阈值演示显示更多数据类型,(选择,布尔)

有些方法有一个输出参数dst,只需给img而不用返回(那样会节省内存,实际上ImagePy会复制返回图片,然后更新视图)

流域与交互式标记

# - * - coding:utf-8 - * from imagepy.core.engine import Filter

import numpy as np,cv2

 

class Plugin(Filter):

标题= '主动流域'

注释= [ ' RGB ',' req_roi ',' not_slice ',' auto_snap ' ]

def run(self,ips,snap,img,para = None):

a,msk = cv2.connectedComponents(ips.get_msk()。astype(np.uint8))

msk = cv2.watershed(img,msk)== - 1

img // = 2

img [msk] = 255

ImagePy支持ROI,你可以使用工具绘制一个roi(点,线,多边形...),我们可以使用ips.roi访问它,并使用ips.get_msk(mode ='in')来获取roi掩码图像。mode可以是'in','out'或int表示具有特定宽度的草图。然后使用面具作为标记进行分水岭,

  1. req_roi意味着这个插件需要一个roi,ImagePy会检查你,如果不是,就打断插件。
  2. not_slice告诉Imagepy,如果它是一个堆栈,则不需要迭代切片,因为这个交互式对于特定的图像是可以的,没有必要经过。

我们可以做分水岭并得到结果,然后我们可以添加一些错过段的笔划。然后再次使用Undo和分水岭,我们得到了完美的结果!

交互式Grabcut

这个演示使用构建工具,并在工具的事件中调用插件。 

标记

mark是在图像上绘制的叠加,它具有参数的绘制方法:

  1. dc a wx dc contex。
  2. f从图像坐标到画布坐标的投影。
  3. 关键其他参数,如切片编号。

# - * - coding:utf-8 - * from imagepy.core.engine import Tool,Filter

import numpy as np,wx,cv2

 

class Mark():

def __init __(self):

self .foreline,self .backline = [],[]

 

def draw(自我,dc,f,** 键):

dc.SetPen(wx.Pen((255,0,0),宽度= 2,式= WX。SOLID))

用于线在 自 .foreline:dc.DrawLines([F(* I)为我在线路])

dc.SetPen(wx.Pen((0,0,255),宽度= 2,式= WX。SOLID))

用于线在 自 .backline:dc.DrawLines([F(* I)为我在线路])

 

def 线(自我,img,线,颜色):

X0,Y0 =行[ 0 ]

为 X,Y 在线[ 1:]:

cv2.line(img,(int(x0),int(y0)),(int(x),int(y)),color,2)

x0,y0 = x,y

 

def buildmsk(自我,形状):

IMG = np.zeros(形状[:2 ],D型细胞= np.uint8)

img [:] = 3

for line in self .foreline:self .line(img,line,1)

for line in self .backline:self .line(img,line,0)

return img

  1. 绘制我们需要一个前景列表和一个背景列表,然后绘制不同的颜色
  2. buildmsk在grabcut我们需要建立的掩模的方法。

Grabcut

class GrabCut(Filter):

标题= '抢剪切'

注释= [ ' RGB ',' not_slice ',' auto_snap ',' not_channel ' ]

def run(self,ips,snap,img,para = None):

msk = ips.mark.buildmsk(img.shape)

bgdModel = np.zeros((1,65),np.float64)

fgdModel = np.zeros((1,65),np.float64)

msk,bgdModel,fgdModel = cv2.grabCut(snap,msk,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)

img [msk %2 == 0 ] // = 3

这是一个过滤器做的抓取方法,它从标记中获取掩码。

工具

工具是ImagePy的引擎之一。你需要实现这些方法:

  1. mousedown时mouse_down,你可以得到当前的imageplus,x,y。哪个按钮是关闭的,还有一些其他信息来自键,(如果按下ctrl,alt,shift ......)
  2. mouse_up就像mouse_down一样
  3. mouse_move就像mouse_down一样
  4. mouse_wheel就像mouse_down一样

class Plugin(工具):

title = ' Grabcut '

“”“具有事件回调的FreeLinebuf类插件”“”

def __init__(self):

self .status = - 1

def mouse_down(self,ips,x,y,btn,** key):

如果 不是 isinstance(ips.mark,Mark):

ips.mark = Mark()

如果 btn == 1 而 不是键[ ' ctrl ' ]:

self .status = 1

self .cur = [(x,y)]

ips.mark.foreline.append(self .cur)

如果 btn == 1 和 key [ ' ctrl ' ]:

del ips.mark.foreline [:]

del ips.mark.backline [:]

如果 btn == 3 而 不是 key [ ' ctrl ' ]:

self .status = 0

self .cur = [(x,y)]

ips.mark.backline.append(self .cur)

如果 btn == 3 和 key [ ' ctrl ' ]:

GrabCut()。开始()

ips.update = True

def mouse_up(self,ips,x,y,btn,** key):

如果 self .status == 1 和 len(self .cur)== 1:

ips.mark.foreline.remove(self .cur)

if self .status == 0 and len(self .cur)== 1:

ips.mark.backline.remove(self .cur)

self .status = - 1

ips.update = True

def mouse_move(self,ips,x,y,btn,** key):

if self .status != - 1:

self .cur.append((x,y))

ips.update = True

def mouse_wheel(self,ips,x,y,d,** key):

传递

在这里我们这样做:

  1. 移动按下左按钮时将轨迹放在前景列表中。
  2. 移动按下右按钮时将跟踪放在后台列表中。
  3. 如果按住ctrl左键单击,则清除前景和背景列表。
  4. 按住ctrl右键单击时执行抓取。

工具文件存储在工具的子文件夹中,并带有生成的16 * 16缩略图图标。图标和工具存储在与gif文件相同的名称中

冲浪演示

继续从交互式阈值分水岭演示此演示使用冲浪功能匹配两个点并找到同性矩阵。(不在此项目中但在imagepy>插件>冲浪)

我们可以使用IPy.write,IPy.table方便地生成文本日志和数据网格

宏是引擎之一,它是一个文本文件,每行代码为: “PluginID> {parameter}”,如果参数为None且Plugin需要参数,IPy将显示交互对话框,如果给出参数,ImagePy只是run使用给定的参数。

我们可以打开插件>宏>宏记录器来记录操作。然后在菜单文件夹下保存为.mc范围的文件。它将在下次启动时解析为菜单。这是宏,我们永远不需要实现自己。

然后我们尝试Surf Demo宏,哇!它会自动运行命令序列!

我们可以使用宏来做一些蝙蝠处理,还有什么?它可以作为一个很好的教程,我们只是实现基本方法,并使用宏来显示这个方法可以解决这样的问题!

关于插件的订单

ImagePy是一个插件框架。Catlog将被解析为相应的菜单。您只需在菜单文件夹或其子文件夹下复制包。但问题是,我们的功能将处于无序状态。所以我们可以在每个init文件下添加一个名为catlog的列表。

现在OpenCV菜单在帮助之前,Threshold是第一个Item,然后是Filter,Segmentation,最后是Demo。如果我们在catlog中放入' - ',它将被解析为spliter线。

好!那是一个开始,我希望更多的开发者可以加入。我认为让Opencv更加接近是有意义的,Benifit更多的科学家并不掌握编程。但是我不能自己做,我的英语不太好,而且没有空余时间,但我会尽我所能!

 

 

 

opencv-plgs

**Introduction:**opencv need not much introductions, It is a famous computer vision library. ImagePy is a interactive image processing framework which can wrap any numpy based library esaily. And supporting multi-channels, imagestack, lookuptable, roi, macros recorder...It is a Plugin system(just like ImageJ but more convenient). This project is a wrapper of opencv for ImagePy plugins!

Now It is just a start, I wrap little of opencv's algrism, aimed to introduct how to wrote ImagePy plugin, The Demo in this document is representative.

License

I know many numpy based project has a BSD license, but, sorry, I use wxpython as ui framework, so, must be under LGPL.

MainFrame

It is ImagePy's MainFrame, like ImageJ. And ImagePy has contains many common function, such as open image, save image, do some filter, do a roi, draw with pencil... It requires wxpython as ui, Numpy as base structure, shapely to treat the roi, and scipy.ndimage to so dome common filter. But this project devotes to do a wrapper for opencv.

Do a simple filter

# -*- coding: utf-8 -*import cv2from imagepy.core.engine import Filterclass Plugin(Filter):    title = 'Laplacian'    note = ['all', 'auto_msk', 'auto_snap']        def run(self, ips, snap, img, para = None):        return cv2.Laplacian(img, -1)

These gradient operator is simplest filter with no parameter.

  1. class name must be Plugin
  2. title is necessary, be the plugin's id, show in menus.
  3. set the note, which tells ImagePy what to do for you.
  4. overwrite run method return the result

Filter is one of engines, means need a image, then do some change on it, It has a run method in such type:

  • ips is the wrapper of image with some other information (lookup table, roi...)
  • snap is a snapshot of the image, if 'auto_snap' in note, ImagePy will copy the image to snap befor run. (for many filter method must be implemented in a buffer)
  • img is the current image you are processing.
  • para is the parameter you got interactive. (there is no here)

note is very important

  • all means this plugin works for all type image.
  • auto_snap means ImagePy do a snapshot befor processing, then you can use Undo.
  • auto_msk means when there is a roi on the image, Plugin will only influnce the pixel in.
  • more detail information please see !

 You see, we didnot write code to treat the color image, but it works, and We can draw a ROI on the image, only the ROI area be changed! And we can undo the lasted operation. Even if it is a imagestack, ImagePy will ask you if run every slice!!

Filter with parameter

# -*- coding: utf-8 -*import cv2from imagepy.core.engine import Filterclass Plugin(Filter):    title = 'Canny'    note = ['all', 'auto_msk', 'auto_snap', 'preview']    para = {'sigma':2, 'low':10, 'high':20}    view = [(float, (0,10), 1,  'sigma', 'sigma', 'pix'),            ('slide',(0,255), 0, 'low_threshold', 'low'),            ('slide',(0,255), 0, 'high_threshold', 'high')]    def run(self, ips, snap, img, para = None):    	l = int(para['sigma']*2.5)*2+1    	cv2.GaussianBlur(snap, (l, l), para['sigma'], dst=img)    	return cv2.Canny(img, para['low'], para['high'])

Many Filter need some parameter. Just like Canny. We just need do a little more.

  1. para is a dict object, which contains the parameter you need.
  2. view tell ImagePy how to interact when this plugin run, (float, (0,10), 1, 'sigma', 'sigma', 'pix') means it is a float between 0 and 10, title is sigma, corresponding to the sigma parameter with unit pix. More detail information please see !

Add 'preview' in note, then when you adjust the parameter, ImagePy run this plugin immediately

# -*- coding: utf-8 -*-from imagepy import IPyimport numpy as np, cv2from imagepy.core.engine import Filter        class Plugin(Filter):    title = 'Adaptive Threshold'    note = ['8-bit', 'auto_msk', 'auto_snap', 'preview']    para = {'max':255, 'med':'mean', 'size':9, 'offset':2, 'inv':False}    view = [(int, (0, 255), 0, 'maxvalue', 'max', ''),            (list, ['mean', 'gauss'], str, 'method', 'med', ''),            (int, (3, 31), 0, 'blocksize', 'size', 'pix'),            (int, (0, 50), 0, 'offset', 'offset', ''),            (bool, 'binary invert', 'inv')]        #process    def run(self, ips, snap, img, para = None):        med = cv2.ADAPTIVE_THRESH_MEAN_C if para['med']=='mean' else cv2.ADAPTIVE_THRESH_GAUSSIAN_C        mtype = cv2.THRESH_BINARY_INV if para['inv'] else cv2.THRESH_BINARY        cv2.adaptiveThreshold(snap, para['max'], med, para['inv'], para['size'], para['offset'], dst=img)

Adaptive Threshold demo shows more data type, (choice, bool)

some method has a output parameter dst, just give the img and need not return(That will save memory, In fact ImagePy will copy the return to image, then update view)

Watershed with interactive marker

# -*- coding: utf-8 -*from imagepy.core.engine import Filterimport numpy as np, cv2class Plugin(Filter):	title = 'Active Watershed'	note = ['rgb', 'req_roi', 'not_slice', 'auto_snap']		def run(self, ips, snap, img, para = None):		a, msk = cv2.connectedComponents(ips.get_msk().astype(np.uint8))		msk = cv2.watershed(img, msk)==-1		img //= 2		img[msk] = 255

ImagePy support ROI, you can use tool to draw a roi(point, line, polygon...), And We can use ips.roi access it, and ips.get_msk(mode='in') to get the roi mask image. mode can be 'in','out',or int means a sketch with specific width. Then use the mask as marker to do a watershed,

  1. req_roi means this plugin need a roi, ImagePy will check for you, if ther is not, interrupt the plugin.
  2. not_slice tells Imagepy need not to iterate slices if it is a stack, because this interactive is ok for specific image, there is no need to go through.

we can do watershed and get the result, then we can add some stroke where missed segment. then use Undo, and watershed again, we got a perfect result!

Interactive Grabcut

this demo use build a Tool, and call a plugin in the tool's event. 

Mark

mark is a overlay drawn on a image, It has draw method with parameter:

  1. dc a wx dc contex.
  2. f project from image coordinate to canvas coordinate.
  3. key other parameter such as slice number.
# -*- coding: utf-8 -*from imagepy.core.engine import Tool, Filterimport numpy as np, wx, cv2class Mark():    def __init__(self):        self.foreline, self.backline = [], []    def draw(self, dc, f, **key):        dc.SetPen(wx.Pen((255,0,0), width=2, style=wx.SOLID))        for line in self.foreline: dc.DrawLines([f(*i) for i in line])        dc.SetPen(wx.Pen((0,0,255), width=2, style=wx.SOLID))        for line in self.backline: dc.DrawLines([f(*i) for i in line])    def line(self, img, line, color):        x0, y0 = line[0]        for x, y in line[1:]:            cv2.line(img, (int(x0), int(y0)), (int(x), int(y)), color, 2)            x0, y0 = x, y    def buildmsk(self, shape):        img = np.zeros(shape[:2], dtype=np.uint8)        img[:] = 3        for line in self.foreline: self.line(img, line, 1)        for line in self.backline: self.line(img, line, 0)        return img
  1. draw we need a foreground list and a background list, then draw in diffrent colors
  2. buildmsk in the grabcut we need a method to build a mask.

Grabcut

class GrabCut(Filter):    title = 'Grab Cut'    note = ['rgb', 'not_slice', 'auto_snap', 'not_channel']        def run(self, ips, snap, img, para = None):        msk = ips.mark.buildmsk(img.shape)        bgdModel = np.zeros((1,65),np.float64)        fgdModel = np.zeros((1,65),np.float64)        msk, bgdModel, fgdModel = cv2.grabCut(snap, msk,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)        img[msk%2 == 0] //= 3

this is a Filter do the grabcut method, It get mask from the mark.

Tool

Tool is one of ImagePy's engines. you need implements these method:

  1. mouse_down when mousedown, youcan got the current imageplus, the x, y. and which button is down, and some other informationg from key,(if ctrl, alt, shift is pressed...)
  2. mouse_up like mouse_down
  3. mouse_move like mouse_down
  4. mouse_wheel like mouse_down
class Plugin(Tool):    title = 'Grabcut'    """FreeLinebuf class plugin with events callbacks"""    def __init__(self):        self.status = -1                def mouse_down(self, ips, x, y, btn, **key):        if not isinstance(ips.mark, Mark):            ips.mark = Mark()        if btn==1 and not key['ctrl']:            self.status = 1            self.cur = [(x, y)]            ips.mark.foreline.append(self.cur)        if btn==1 and key['ctrl']:            del ips.mark.foreline[:]            del ips.mark.backline[:]        if btn==3 and not key['ctrl']:            self.status = 0            self.cur = [(x, y)]            ips.mark.backline.append(self.cur)        if btn==3 and key['ctrl']:            GrabCut().start()        ips.update = True        def mouse_up(self, ips, x, y, btn, **key):        if self.status==1 and len(self.cur)==1:            ips.mark.foreline.remove(self.cur)        if self.status==0 and len(self.cur)==1:            ips.mark.backline.remove(self.cur)        self.status = -1        ips.update = True        def mouse_move(self, ips, x, y, btn, **key):        if self.status!=-1:            self.cur.append((x, y))            ips.update = True            def mouse_wheel(self, ips, x, y, d, **key):        pass

here we do these:

  1. put track in foreground list when move whith left button pressed.
  2. put track in background list when move whith right button pressed.
  3. clear foreground and background list if left click with ctrl pressed.
  4. do grabcut when right click with ctrl pressed.

Tool files are stored in the sub-folder of tools, with a generated 16 * 16 thumbnail icon. The icon and the tool are stored in the same name as the gif file

Surf Demo

continued from the interactive threshold watershed demo this demo use surf feature to match two points and find the homo Matrix.(not in this project but in imagepy>plugin>surf)

we can use IPy.write, IPy.table to generate text log and data grid conviniently

Macros

Macros is one of engines, It is a text file with every line as: "PluginID > {parameter}", If the parameter is None and the Plugin need parameter, IPy will show dialog to interact, if the parameter is given, ImagePy just run use the given parameter.

We can Open the Plugin > Macros > Macros Recorder to record the operate. Then save as a file with .mc extent under the menus folder. It will be parsed as a menu when started next. This is Macros, We never need to implements ourself.

Then we Try the Surf Demo macros, Wow!, It run the command sequence automatically!

We can use Macros to do some bat processing, what more? It can be used as a good tutorial, We just implement the baseic method, and use macros to show this method can solve such problem!!!

About the plugin's order

ImagePy is a plugin framework. The Catlog will be parsed as the corresponding menus. You just copy package under the menus folder or it's sub folder. But the question is, Our function will be in a disordered order. So we can add a list called catlog under every init file.

Now OpenCV menu is before the Help, and the Threshold is the first Item, then Filter, Segmentation, last is Demo. and if we put '-' in catlog, It will be parsed as a spliter line.

OK! That is a start, I want more developer can join. I think it is significative to let Opencv be esaier to approach, Benifit more scientists who does not master programming. But I cannot do it by myself, My English is not so good, and have little spare time, But I will do my best!

上一篇:imagepy库安装后出现的问题汇总
下一篇:imagepy库相关知识点——suff ——在参数中显示不同的后缀

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月13日 10时28分26秒