ImagePy智能标注工具源码学习记录 - 知乎
https://zhuanlan.zhihu.com/p/105621501
这几天,ImagePy群聊很热烈,讲到PS的标注很好用,但是不能二次开发,不利于打通上下游。
于是ImagePy作者闫大搞了一个智能标注工具,拓展了ImagePy框架,方便科研工作者基于ImagePy的智能标注工具来提高数据标注的精确性和方便性,下一步准备融合深度学习功能。
我闲着无事就把群聊内容进行了备份,如下:
智能画笔其实是小范围内,做了一个superpixel,像素聚类。
包括:缩放,描边,颜色优先级,填充等功能。
https://www.zhihu.com/video/1209231248096587776智能画笔全部代码,主要是框住的两行:
这个参数可以调节智能画笔粘性。也可以按住shift用滚轮调节。
细节的地方,用10就可以了
杂谈:
四色渲染
因为染色是按照标记顺序,但是决定冲突的是图的连接顺序。所以遇到冲突会一个个后退。
我想先用贪心法,然后从大于4的,局部一一解决冲突,以冲突点为中心扩散遍历,这样应该不会太深
普通遍历的问题是,决策顺序是从左到右,从上到下,但是冲突的决定性因素是邻居,图大一点,就循环出不来了.这个就是按照label顺序压线,遇到冲突重新决策上一个
好比一个迷宫,在很早之前就走错了分支,但是深度遍历会把错误分支可能性都尝试了才会退出。
对与染色问题,冲突的重要因素是邻居,然而遍历顺序是label. 就要一个个label后退,直到退到邻居才有可能走到正确的分支。
决策顺序是按照label来压栈的,但是遇到冲突,其实往往在很早之前的一个邻居就已经注定错了.但是按照顺序压栈,就会把这个过程中的所有组合都测试了,才会退回去。
我想做一个启发式算法,就是如果遇到冲突,就暂时给5,然后回过头来,对每个5做扩散装解决冲突。数论和图论很多时候都是和自己过不去,用5种啥事都没有。
这种规模的,十几个ms,1000个节点,渲染个全国的县级地图没什么问题的
启发式的,陷入局部死循环,就来个随机数打乱
超像素聚类,四色,floodfill
四色只是想一张图做两份事,不然你看,底图,超像素图,标记图,要三张
我就是想把超像素和标记合二为一。标记最多几种,超像素理论上只用四种。
图太多了,设计和维护会变复杂。目前ipy的ips只有一个background
上面几个视频没用四色,最后那个半透明的才用了。自动的把四色弄成了200-255,然后假彩色映射成黑色。
前几个位是映射成彩色的,后面没用的映射成黑色。刚好把超像素装进去
没太懂为什么要留着超像素,不是应该用完就扔吗
一种是局部的,用了就扔
还有一种是全局先算完,然后后续染色
四色代码
four_color_fill.py
import numpy as np from numba import jit import random from scipy.ndimage import generate_binary_structure def neighbors(shape, conn=1): dim = len(shape) block = generate_binary_structure(dim, conn) block[tuple([1]*dim)] = 0 idx = np.where(block>0) idx = np.array(idx, dtype=np.uint8).T idx = np.array(idx-[1]*dim) acc = np.cumprod((1,)+shape[::-1][:-1]) return np.dot(idx, acc[::-1]) @jit(nopython=True) def search(img, nbs): s, line = 0, img.ravel() rst = np.zeros((len(line),2), img.dtype) for i in range(len(line)): if line[i]==0:continue for d in nbs: if line[i+d]==0: continue if line[i]==line[i+d]: continue rst[s,0] = line[i] rst[s,1] = line[i+d] s += 1 return rst[:s] def connect(img, conn=1): buf = np.pad(img, 1, 'constant') nbs = neighbors(buf.shape, conn) rst = search(buf, nbs) if len(rst)<2: return rst rst.sort(axis=1) key = (rst[:,0]<<16) key += rst[:,1] order = np.argsort(key) key[:] = key[order] diff = key[:-1]!=key[1:] idx = np.where(diff)[0]+1 idx = np.hstack(([0], idx)) return rst[order][idx] def mapidx(idx): dic = {} for i in np.unique(idx): dic[i] = [] for i,j in idx: dic[i].append(j) dic[j].append(i) return dic # give a touch map: {1:[2,3], 2:[1], 3:[1]} def render_net(conmap, n=4, rand=12, shuffle=True): nodes = list(conmap.keys()) colors = dict(zip(nodes, [0]*len(nodes))) counter = dict(zip(nodes, [0]*len(nodes))) if shuffle: random.shuffle(nodes) while len(nodes)>0: k = nodes.pop(0) counter[k] += 1 hist = [1e4] + [0] * n for p in conmap[k]: hist[colors[p]] += 1 if min(hist)==0: colors[k] = hist.index(min(hist)) counter[k] = 0 continue hist[colors[k]] = 1e4 minc = hist.index(min(hist)) if counter[k]==rand: counter[k] = 0 minc = random.randint(1,4) colors[k] = minc for p in conmap[k]: if colors[p] == minc: nodes.append(p) return colors if __name__ == '__main__': from time import time from skimage.io import imread, imsave from skimage.data import coffee from skimage.segmentation import slic import matplotlib.pyplot as plt lab = slic(coffee(), 1000, 10, 10, 0)+1 #lab = imread('lab.tif') a = time() idx = connect(lab, 2) print(time()-a) a = time() idx = connect(lab, 2) print(time()-a) a = time() idx = mapidx(idx) print(time()-a) a = time() colors = render_net(idx, 4, 10) lut = np.ones(lab.max()+1, dtype=np.uint8) for i in colors: lut[i] = colors[i] lut[0] = 0 print(time()-a) plt.imshow(lut[lab]) plt.figure() plt.imshow(lab) plt.show()
一个shapely的问题
ipy显示这个定位到的点是什么格式的ROI吗?
这个不是roi,是mark。可以看看measure工具栏。
ipy的根基,其实一个numpy,一个pandas,一个shapely
局部做超像素,整合了很多逻辑运算,比如自动描边,绘制颜色优先级
有了shapely,做很多事情都不怕了,比如判定点击是否落在某个对象内,距离某个多段线的距离是多少。
类似这种,两个圆roi,按住shift,自动合并
鼠标点击,是否落在某个多边形内,到底点中了谁
一个简单的问题,你想在一个多段线的某一段上,加一个节点
其实自己写也很复杂的。
tool里面维护自己的矢量,然后通过鼠标交互来判定,点在哪个对象上,做什么操作。
矢量计算,有shapely库;矢量绘制,core. mark。按照规范整理成json
jcore.mark是图形的配置json,就是点线面,颜色,线形,透明度,之类的。roi其实属于特殊的一种mark,特点是,可以编辑,并且可以转化为掩膜。
其实你要做的,就是维护一个对象,可以在shapely,mark之间转换,同时可以响应你要的交互。比如节点编辑,拖动什么的,其实和roi差不多。
tool里面维护自己的几何对象,处理自己的交互,做自己的展示。
mark只是一个中间格式,把要展示的东西,组织成特定的json,然后ipy来绘制。
还是类似的东西,维护若干条线,处理鼠标行为,同时更新plot
是一个东西,mark只是方便的把集合对象绘制处理的中间格式
如果没有mark,就不得不直接面对gdi,draw。这个水就深了
dc,双缓冲的,纯界面的东西,绘图上下文。
ctrl z 是undo,本质是一个simple,关联了快捷键,只要在需要镜像的时候,ips.snap一下,就可以了。每次落笔的时候,ips.snap一下,就可以了
闫大的视频讲解:
细胞标注https://www.zhihu.com/video/1209216271340064768ImagePy_Learn学习系列
土盐:ImagePy_Learn | 图形学绘制代码学习:core\draw\fill.py
土盐:ImagePy_Learn | 图形学绘制代码学习:paint.py
土盐:ImagePy_Learn | 图形学绘制代码学习:core\draw\polygonfill.py
学习记录:
1、python中数组(numpy.array)的基本操作
2、buf=np.pad(img, 1, 'constant')
numpy中pad函数的常用方法 - hezhiyao - 博客园 www.cnblogs.com3、
4、
" / "就表示 浮点数除法,返回浮点结果;" // "表示整数除法。
5、returnnp.dot(idx, acc[::-1])
对NumPy中dot()函数的理解 www.cnblogs.com6、s, line=0, img.ravel()
Numpy中扁平化函数ravel()和flatten()的区别 - weller - 博客园 www.cnblogs.com7、sort=np.argsort(key)
8、return rst[:unique(rst)].copy()
深拷贝数组 np.copy - 深度学习1 - 博客园 www.cnblogs.com9、
- append() 方法向列表的尾部添加一个新的元素。
- 列表是以类的形式实现的。“创建”列表实际上是将一个类实例化。因此,列表有多种方法可以操作。
extend()
方法只接受一个列表作为参数,并将该参数的每个元素都添加到原有的列表中。
源码:
imagepy/imagepy/tools/Draw/aibrush_tol.py /
https://github.com/Image-Py/imagepy/blob/0e3be4c056cc85de55e0294099656b85950397b8/imagepy/tools/Draw/aibrush_tol.py github.comfrom imagepy.core.engine import Tool import numpy as np from time import time from imagepy.core.manager import ColorManager from skimage.morphology import flood_fill, flood from skimage.draw import line, circle from skimage.segmentation import felzenszwalb from imagepy.core.mark import GeometryMark from scipy.ndimage import binary_fill_holes, binary_dilation, binary_erosion def fill_normal(img, r, c, color, con, tor): img = img.reshape((img.shape+(1,))[:3]) msk = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): msk &= flood(img[:,:,i], (r, c), connectivity=con, tolerance=tor) img[msk] = color def local_brush(img, r, c, color, sigma, msize): lab = felzenszwalb(img, 1, sigma, msize) msk = flood(lab, (r, c), connectivity=2) img[msk] = color def local_pen(img, r, c, R, color): img = img.reshape((img.shape+(1,))[:3]) rs, cs = circle(r, c, R/2+1e-6, shape=img.shape) img[rs, cs] = color def local_in_fill(img, r, c, R, color, bcolor): img = img.reshape((img.shape+(1,))[:3]) msk = (img == color).min(axis=2) filled = binary_fill_holes(msk) filled ^= msk rs, cs = circle(r, c, R/2+1e-6, shape=img.shape) msk[:] = 0 msk[rs, cs] = 1 msk &= filled img[msk] = bcolor def local_out_fill(img, r, c, R, color, bcolor): img = img.reshape((img.shape+(1,))[:3]) msk = (img != color).max(axis=2) rs, cs = circle(r, c, R/2+1e-6, shape=img.shape) buf = np.zeros_like(msk) buf[rs, cs] = 1 msk &= buf img[msk] = bcolor def local_sketch(img, r, c, R, color, bcolor): img = img.reshape((img.shape+(1,))[:3]) msk = (img == color).min(axis=2) dilation = binary_dilation(msk, np.ones((3,3))) dilation ^= msk rs, cs = circle(r, c, R/2+1e-6, shape=img.shape) msk[:] = 0 msk[rs, cs] = 1 msk &= dilation img[msk] = bcolor def global_both_line(img, r, c, color): img = img.reshape((img.shape+(1,))[:3]) msk = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): msk &= flood(img[:,:,i], (r, c), connectivity=2) dilation = binary_dilation(msk, np.ones((3,3))) dilation ^= msk img[dilation] = color def global_out_line(img, r, c, color): img = img.reshape((img.shape+(1,))[:3]) msk = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): msk &= flood(img[:,:,i], (r, c), connectivity=2) msk = binary_fill_holes(msk) dilation = binary_dilation(msk, np.ones((3,3))) dilation ^= msk img[dilation] = color def global_in_line(img, r, c, color): img = img.reshape((img.shape+(1,))[:3]) msk = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): msk &= flood(img[:,:,i], (r, c), connectivity=2) inarea = binary_fill_holes(msk) inarea ^= msk inarea ^= binary_erosion(inarea, np.ones((3,3))) img[inarea] = color def global_in_fill(img, r, c, color): img = img.reshape((img.shape+(1,))[:3]) msk = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): msk &= flood(img[:,:,i], (r, c), connectivity=2) filled = binary_fill_holes(msk) filled ^= msk img[filled] = color def global_out_fill(img, r, c, color): img = img.reshape((img.shape+(1,))[:3]) ori = np.ones(img.shape[:2], dtype=np.bool) for i in range(img.shape[2]): ori &= flood(img[:,:,i], (r, c), connectivity=2) filled = binary_fill_holes(ori) dilation = binary_dilation(ori) dilation ^= filled rs, cs = np.where(dilation) if len(rs)==0: return msk = ((img == img[r,c]).min(axis=2)).astype(np.uint8) flood_fill(msk, (rs[0], cs[0]), 2, connectivity=2, inplace=True) img[msk==2] = color ''' general: size >>> local =================================== block: minsize | left in fill: r | left shift pen: r | left ctrl sketch: r | left alt out fill: r | left ctrl + alt >>> global ================================== flood: | right in fill: | right shift out line: | right ctrl in line: | right alt out fill: | right ctrl + alt scale and move: | wheel ''' class Plugin(Tool): title = 'AI Painter' para = {'win':48, 'tor':10, 'con':'8-connect', 'ms':20, 'r':2, 'color':(255,0,128)} view = [(int, 'win', (28, 64), 0, 'window', 'size'), ('color', 'color', 'color', 'mark'), ('lab', None, '======= Brush ======='), (float, 'ms', (10, 50), 0, 'stickiness', 'pix'), ('lab', None, '======= Pen ======='), (int, 'r', (1, 30), 0, 'radius', 'pix'), ('lab', None, '======= Flood ======='), (int, 'tor', (0,1000), 0, 'tolerance', 'value'), (list, 'con', ['4-connect', '8-connect'], str, 'connect', 'pix')] def __init__(self): self.status = None self.pickp = (0,0) self.oldp = (0,0) def mouse_down(self, ips, x, y, btn, **key): if btn==2: self.oldp = key['canvas'].to_panel_coor(x,y) self.status = 'move' return self.oldp = self.pickp = (y, x) color = ColorManager.get_front() x = int(round(min(max(x,0), ips.img.shape[1]))) y = int(round(min(max(y,0), ips.img.shape[0]))) color = (np.mean(color), color)[ips.img.ndim==3] self.pickcolor = ips.img[y, x] ips.snapshot() if btn==1 and key['ctrl'] and key['alt']: self.status = 'local_out' elif btn==1 and key['ctrl']: self.status = 'local_pen' elif btn==1 and key['alt']: self.status = 'local_sketch' elif btn==1 and key['shift']: self.status = 'local_in' elif btn==1: self.status = 'local_brush' elif btn==3 and key['ctrl'] and key['alt']: self.status = 'global_out_fill' global_out_fill(ips.img, y, x, color) ips.update() elif btn==3 and key['ctrl']: self.status = 'global_out_line' global_out_line(ips.img, y, x, color) ips.update() elif btn==3 and key['alt']: self.status = 'global_in_line' global_in_line(ips.img, y, x, color) ips.update() elif btn==3 and key['shift']: self.status = 'global_in_fill' global_in_fill(ips.img, y, x, color) ips.update() elif btn==3: if (ips.img[y, x] - color).sum()==0: return conn = {'4-connect':1, '8-connect':2} conn = conn[self.para['con']] tor = self.para['tor'] fill_normal(ips.img, y, x, color, conn, tor) ips.update() def mouse_up(self, ips, x, y, btn, **key): if btn==1 and (y,x)==self.pickp and key['ctrl']: x = int(round(min(max(x,0), ips.img.shape[1]))) y = int(round(min(max(y,0), ips.img.shape[0]))) ColorManager.set_front(ips.img[y, x]) self.status = None ips.mark = None ips.update() def make_mark(self, x, y): wins = self.para['win'] rect = {'type':'rectangle', 'body':(x, y, wins*2, wins*2), 'color':self.para['color']} mark = {'type':'layer', 'body':[rect]} r = 2 if self.status=='local_brush' else self.para['r']/2 mark['body'].append({'type':'circle', 'body':(x, y, r), 'color':self.para['color']}) mark['body'].append({'type':'text', 'body':(x-wins, y-wins, 'S:%s W:%s'%(self.para['ms'], self.para['win'])), 'pt':False, 'color':self.para['color']}) return GeometryMark(mark) def mouse_move(self, ips, x, y, btn, **key): if self.status == None and ips.mark != None: ips.mark = None ips.update() if not self.status in ['local_pen','local_brush', 'local_sketch','local_in','local_out','move']: return img, color = ips.img, ColorManager.get_front() x = int(round(min(max(x,0), img.shape[1]))) y = int(round(min(max(y,0), img.shape[0]))) if self.status == 'move': x,y = key['canvas'].to_panel_coor(x,y) key['canvas'].move(x-self.oldp[0], y-self.oldp[1]) self.oldp = x, y ips.update() print('move') return rs, cs = line(*[int(round(i)) for i in self.oldp + (y, x)]) np.clip(rs, 0, img.shape[0]-1, out=rs) np.clip(cs, 0, img.shape[1]-1, out=cs) color = (np.mean(color), color)[img.ndim==3] for r,c in zip(rs, cs): start = time() w = self.para['win'] sr = (max(0,r-w), min(img.shape[0], r+w)) sc = (max(0,c-w), min(img.shape[1], c+w)) r, c = min(r, w), min(c, w) clip = img[slice(*sr), slice(*sc)] if self.status == 'local_pen': local_pen(clip, r, c, self.para['r'], color) if self.status == 'local_brush': if (clip[r,c] - color).sum()==0: continue local_brush(clip, r, c, color, 0, self.para['ms']) if self.status == 'local_in': local_in_fill(clip, r, c, self.para['r'], self.pickcolor, color) if self.status == 'local_sketch': local_sketch(clip, r, c, self.para['r'], self.pickcolor, color) if self.status=='local_out': local_out_fill(clip, r, c, self.para['r'], self.pickcolor, color) ips.mark = self.make_mark(x, y) self.oldp = (y, x) ips.update() def mouse_wheel(self, ips, x, y, d, **key): if key['shift']: if d>0: self.para['ms'] = min(50, self.para['ms']+1) if d<0: self.para['ms'] = max(10, self.para['ms']-1) ips.mark = self.make_mark(x, y) elif key['ctrl'] and key['alt']: if d>0: self.para['win'] = min(64, self.para['win']+1) if d<0: self.para['win'] = max(28, self.para['win']-1) ips.mark = self.make_mark(x, y) elif key['ctrl']: if d>0: self.para['r'] = min(30, self.para['r']+1) if d<0: self.para['r'] = max(2, self.para['r']-1) ips.mark = self.make_mark(x, y) elif self.status == None: if d>0:key['canvas'].zoomout(x, y, 'data') if d<0:key['canvas'].zoomin(x, y, 'data') ips.update()
imagepy/imagepy/core/mark/mark.py /
https://github.com/Image-Py/imagepy/blob/0e3be4c056cc85de55e0294099656b85950397b8/imagepy/core/mark/mark.py github.comimport numpy as np from math import sin, cos from ..manager import ConfigManager point = {'type':'point', 'color':(255,0,0), 'lw':1, 'body':(10,10)} points = {'type':'points', 'color':(255,0,0), 'lw':1, 'body':[(10,10),(100,200)]} line = {'type':'line', 'color':(255,0,0), 'lw':1, 'style':'-', 'body':[(10,10),(100,200),(200,200)]} lines = {'type':'lines', 'color':(255,0,0), 'lw':1, 'style':'-', 'body':[[(10,10),(100,200),(200,200)],[(150,10),(50,250)]]} polygon = {'type':'polygon', 'color':(255,0,0), 'fcolor':(255,255,0), 'lw':1, 'style':'o', 'body':[(10,10),(100,200),(200,200)]} polygons = {'type':'polygons', 'color':(255,0,0), 'fcolor':(255,255,0,30), 'fill':False, 'lw':1, 'style':'o', 'body':[[(10,10),(100,200),(200,200)],[(150,10),(50,250),(288,0)]]} circle = {'type':'circle', 'color':(255,0,0), 'fcolor':(255,255,0), 'fill':False, 'body':(100,100,50)} circles = {'type':'circles', 'color':(255,0,0), 'fcolor':(255,255,0), 'fill':False, 'body':[(100,100,50),(300,300,100)]} ellipse = {'type':'ellipse', 'color':(255,0,0), 'fcolor':(255,255,0), 'fill':False, 'body':(100,100,100,50,1)} ellipses = {'type':'ellipses', 'color':(255,0,0), 'fcolor':(255,255,0), 'fill':False, 'body':[(100,100,100,50,1),(200,250,50,100,3.14)]} rectangle = {'type':'rectangle', 'color':(255,0,0), 'fcolor':(255,255,0), 'fill':True, 'body':(100,100,80,50)} rectangles = {'type':'rectangles', 'color':(255,0,0), 'fcolor':(255,255,0), 'fill':False, 'body':[(100,100,80,50),(200,200,80,100)]} text = {'type':'text', 'color':(255,255,0), 'fcolor':(0,0,0), 'size':8, 'pt':True, 'body':(100,200,'id=0')} texts = {'type':'texts', 'color':(255,255,0), 'fcolor':(0,0,0), 'size':8, 'pt':True, 'body':[(100,200,'id=0'),(180,250,'id=1')]} layer = {'type':'layer', 'num':-1, 'clolor':(255,255,0), 'fcolor':(255,255,255), 'fill':False, 'body':[point, points, line, lines, polygon, polygons, circle, circles, ellipse, ellipses, rectangle, rectangles, text, texts]} layers = {'type':'layers', 'num':-1, 'clolor':(255,255,0), 'fcolor':(255,255,255), 'fill':False, 'body':{1:points, 2:line, 3:layer}} def plot(pts, dc, f, **key): pen, brush = dc.GetPen(), dc.GetBrush() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() if 'color' in pts: pen.SetColour(pts['color']) if 'fcolor' in pts: brush.SetColour(pts['fcolor']) if 'lw' in pts: pen.SetWidth(pts['lw']) if 'fill' in pts: brush.SetStyle((106,100)[pts['fill']]) dc.SetPen(pen) dc.SetBrush(brush) if pts['type'] == 'point': pen.SetWidth(1) brush.SetStyle(100) brush.SetColour(pen.GetColour()) dc.SetPen(pen) dc.SetBrush(brush) r = pts['r'] if 'r' in pts else 2 x, y = f(*pts['body']) dc.DrawEllipse (x-r,y-r,r*2,r*2) pen.SetWidth(pts['lw'] if 'lw' in pts else width) brush.SetStyle((106,100)[pts['fill']] if 'fill' in pts else style) brush.SetColour(pts['fc'] if 'fc' in pts else fcolor) dc.SetPen(pen) dc.SetBrush(brush) elif pts['type'] in {'points','line','polygon'}: lst, plst = [], [] r = pts['r'] if 'r' in pts else 2 for p in pts['body']: x, y = f(*p) lst.append((x-r,y-r,r*2,r*2)) plst.append((x,y)) isline = 'style' in pts and '-' in pts['style'] ispoint = 'style' in pts and 'o' in pts['style'] if pts['type'] == 'polygon': dc.DrawPolygon(plst) if isline or pts['type'] == 'line': dc.DrawLines(plst) if pts['type']=='points' or ispoint: pen.SetWidth(1) brush.SetStyle(100) brush.SetColour(pen.GetColour()) dc.SetPen(pen) dc.SetBrush(brush) dc.DrawEllipseList(lst) pen.SetWidth(pts['lw'] if 'lw' in pts else width) brush.SetStyle((106,100)[pts['fill']] if 'fill' in pts else style) brush.SetColour(pts['fc'] if 'fc' in pts else fcolor) dc.SetPen(pen) dc.SetBrush(brush) elif pts['type'] in {'lines','polygons'}: lst, plst = [], [] r = pts['r'] if 'r' in pts else 2 for i in pts['body']: line = [] for p in i: x, y = f(*p) lst.append((x-r,y-r,r*2,r*2)) line.append((x,y)) plst.append(line) isline = 'style' in pts and '-' in pts['style'] ispoint = 'style' in pts and 'o' in pts['style'] if pts['type'] == 'polygons': dc.DrawPolygonList(plst) if isline or pts['type'] == 'lines': for line in plst: dc.DrawLines(line) if pts['type']=='points' or ispoint: pen.SetWidth(1) brush.SetStyle(100) brush.SetColour(pen.GetColour()) dc.SetPen(pen) dc.SetBrush(brush) dc.DrawEllipseList(lst) pen.SetWidth(pts['lw'] if 'lw' in pts else width) brush.SetStyle((106,100)[pts['fill']] if 'fill' in pts else style) brush.SetColour(pts['fc'] if 'fc' in pts else fcolor) dc.SetPen(pen) dc.SetBrush(brush) pen.SetWidth(width) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) def draw_circle(pts, dc, f, **key): pen, brush = dc.GetPen(), dc.GetBrush() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() if 'color' in pts: pen.SetColour(pts['color']) if 'fcolor' in pts: brush.SetColour(pts['fcolor']) if 'lw' in pts: pen.SetWidth(pts['lw']) if 'fill' in pts: brush.SetStyle((106,100)[pts['fill']]) dc.SetPen(pen) dc.SetBrush(brush) if pts['type'] == 'circle': x, y ,r = pts['body'] x, y = f(x, y) dc.DrawCircle(x, y, r*key['k']) if pts['type'] == 'circles': lst = [] for x, y ,r in pts['body']: x, y = f(x, y) r *= key['k'] lst.append((x-r,y-r,r*2,r*2)) dc.DrawEllipseList(lst) pen.SetWidth(width) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) def make_ellipse(l1, l2, ang): m = np.array([[l1*cos(-ang),-l2*sin(-ang)], [l1*sin(-ang),l2*cos(-ang)]]) a = np.linspace(0, np.pi*2, 36) xys = np.array((np.cos(a), np.sin(a))) return np.dot(m, xys).T def draw_ellipse(pts, dc, f, **key): pen, brush = dc.GetPen(), dc.GetBrush() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() if 'color' in pts: pen.SetColour(pts['color']) if 'fcolor' in pts: brush.SetColour(pts['fcolor']) if 'lw' in pts: pen.SetWidth(pts['lw']) if 'fill' in pts: brush.SetStyle((106,100)[pts['fill']]) dc.SetPen(pen) dc.SetBrush(brush) if pts['type'] == 'ellipse': x, y ,l1, l2, a = pts['body'] elp = make_ellipse(l1,l2,a) elp = elp*key['k']+f(x,y) dc.DrawPolygon(elp) if pts['type'] == 'ellipses': lst = [] for x, y, l1, l2, a in pts['body']: elp = make_ellipse(l1,l2,a) lst.append(elp*key['k']+f(x,y)) dc.DrawPolygonList(lst) pen.SetWidth(width) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) def draw_rectangle(pts, dc, f, **key): pen, brush = dc.GetPen(), dc.GetBrush() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() if 'color' in pts: pen.SetColour(pts['color']) if 'fcolor' in pts: brush.SetColour(pts['fcolor']) if 'lw' in pts: pen.SetWidth(pts['lw']) if 'fill' in pts: brush.SetStyle((106,100)[pts['fill']]) dc.SetPen(pen) dc.SetBrush(brush) if pts['type'] == 'rectangle': x, y, w, h = pts['body'] x, y = f(x, y) w, h = w*key['k'], h*key['k'] dc.DrawRectangle(x-w/2, y-h/2, w, h) if pts['type'] == 'rectangles': lst = [] for x, y, w, h in pts['body']: x, y = f(x, y) w, h = w*key['k'], h*key['k'] lst.append((x-w/2, y-h/2, w, h)) dc.DrawRectangleList(lst) pen.SetWidth(width) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) def draw_text(pts, dc, f, **key): pen, brush, font = dc.GetPen(), dc.GetBrush(), dc.GetFont() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() size = font.GetPointSize() tcolor = dc.GetTextForeground() bcolor = dc.GetTextBackground() if 'color' in pts: pen.SetColour(pts['color']) dc.SetTextForeground(pts['color']) brush.SetColour(pen.GetColour()) brush.SetStyle(100) if 'fcolor' in pts: dc.SetTextBackground(pts['fcolor']) if 'size' in pts: font.SetPointSize(pts['size']) dc.SetPen(pen) dc.SetBrush(brush) dc.SetFont(font) if pts['type'] == 'text': x, y, text = pts['body'] x, y = f(x, y) dc.DrawText(text, x+3, y+3) if not 'pt' in pts or pts['pt']: dc.DrawEllipse(x-2,y-2,4,4) if pts['type'] == 'texts': tlst, clst, elst = [], [], [] for x, y, text in pts['body']: x, y = f(x, y) tlst.append(text) clst.append((x+3, y+3)) elst.append((x-2, y-2, 4, 4)) dc.DrawTextList(tlst, clst) if not 'pt' in pts or pts['pt']: dc.DrawEllipseList(elst) font.SetPointSize(size) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) dc.SetFont(font) dc.SetTextForeground(tcolor) dc.SetTextBackground(bcolor) draw_dic = {'points':plot, 'point':plot, 'line':plot, 'polygon':plot, 'lines':plot, 'polygons':plot, 'circle':draw_circle, 'circles':draw_circle, 'ellipse':draw_ellipse, 'ellipses':draw_ellipse, 'rectangle':draw_rectangle, 'rectangles':draw_rectangle, 'text':draw_text, 'texts':draw_text} def draw(obj, dc, f, **key): draw_dic[obj['type']](obj, dc, f, **key) def draw_layer(pts, dc, f, **key): pen, brush = dc.GetPen(), dc.GetBrush() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() if 'color' in pts: pen.SetColour(pts['color']) if 'fcolor' in pts: brush.SetColour(pts['fcolor']) if 'lw' in pts: pen.SetWidth(pts['lw']) if 'fill' in pts: brush.SetStyle((106,100)[pts['fill']]) dc.SetPen(pen) dc.SetBrush(brush) for i in pts['body']:draw(i, dc, f, **key) pen.SetWidth(width) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) draw_dic['layer'] = draw_layer def draw_layers(pts, dc, f, **key): pen, brush = dc.GetPen(), dc.GetBrush() width, color = pen.GetWidth(), pen.GetColour() fcolor, style = brush.GetColour(), brush.GetStyle() if 'color' in pts: pen.SetColour(pts['color']) if 'fcolor' in pts: brush.SetColour(pts['fcolor']) if 'lw' in pts: pen.SetWidth(pts['lw']) if 'fill' in pts: brush.SetStyle((106,100)[pts['fill']]) dc.SetPen(pen) dc.SetBrush(brush) if key['cur'] in pts['body']: draw(pts['body'][key['cur']], dc, f, **key) pen.SetWidth(width) pen.SetColour(color) brush.SetColour(fcolor) brush.SetStyle(style) dc.SetPen(pen) dc.SetBrush(brush) draw_dic['layers'] = draw_layers class GeometryMark: def __init__(self, body): self.body = body def draw(self, dc, f, **key): pen, brush, font = dc.GetPen(), dc.GetBrush(), dc.GetFont() pen.SetColour(ConfigManager.get('mark_color') or (255,255,0)) brush.SetColour(ConfigManager.get('mark_fcolor') or (255,255,255)) brush.SetStyle((106,100)[ConfigManager.get('mark_fill') or False]) pen.SetWidth(ConfigManager.get('mark_lw') or 1) dc.SetTextForeground(ConfigManager.get('mark_tcolor') or (255,0,0)) font.SetPointSize(ConfigManager.get('mark_tsize') or 8) dc.SetPen(pen); dc.SetBrush(brush); dc.SetFont(font); draw(self.body, dc, f, **key) if __name__ == '__main__': print(make_ellipse(0,0,2,1,0))
imagepy/imagepy/ipyalg/graph/connect.py /
https://github.com/Image-Py/imagepy/blob/0e3be4c056cc85de55e0294099656b85950397b8/imagepy/ipyalg/graph/connect.py github.comimport numpy as np from numba import jit import random from scipy.ndimage import generate_binary_structure def neighbors(shape, conn=1): dim = len(shape) block = generate_binary_structure(dim, conn) block[tuple([1]*dim)] = 0 idx = np.where(block>0) idx = np.array(idx, dtype=np.uint8).T idx = np.array(idx-[1]*dim) acc = np.cumprod((1,)+shape[::-1][:-1]) return np.dot(idx, acc[::-1]) @jit(nopython=True) def unique(idx): msk = idx[:,0]<idx[:,1] key = idx[:,0]<<16 key += idx[:,1] sort = np.argsort(key) idx[:] = idx[sort] s = i = 1 while s<len(idx): if key[sort[s]]!=key[sort[s-1]]: idx[i,0] = idx[s,0] idx[i,1] = idx[s,1] i += 1 s += 1 return i @jit(nopython=True) def search(img, nbs, back): s, line = 0, img.ravel() rst = np.zeros((len(line)//2, 2), img.dtype) for i in range(len(line)): if line[i]==0:continue for d in nbs: if not back and line[i+d]==0: continue if line[i]==line[i+d]: continue rst[s,0] = line[i] rst[s,1] = line[i+d] s += 1 if s==len(rst): s = unique(rst) return rst[:s] def connect_graph(img, conn=1, back=False): buf = np.pad(img, 1, 'constant') nbs = neighbors(buf.shape, conn) rst = search(buf, nbs, back) if len(rst)<2: return rst rst.sort(axis=1) return rst[:unique(rst)].copy() def mapidx(idx): dic = {} for i in np.unique(idx): dic[i] = [] for i,j in idx: dic[i].append(j) dic[j].append(i) return dic if __name__ == '__main__': img = np.array([[1,1,1,1,1], [1,1,2,2,1], [1,3,0,0,1], [1,3,1,1,4]]) rst = connect_graph(img, 2, True) print(rst)
椭圆生成源码:
def make_ellipse(l1, l2, ang): m = np.array([[l1*cos(-ang),-l2*sin(-ang)], [l1*sin(-ang),l2*cos(-ang)]]) a = np.linspace(0, np.pi*2, 36) xys = np.array((np.cos(a), np.sin(a))) return np.dot(m, xys).T if pts['type'] == 'ellipse': x, y ,l1, l2, a = pts['body'] elp = make_ellipse(l1,l2,a) elp = elp*key['k']+f(x,y) dc.DrawPolygon(elp) if pts['type'] == 'ellipses': lst = [] for x, y, l1, l2, a in pts['body']: elp = make_ellipse(l1,l2,a) lst.append(elp*key['k']+f(x,y)) dc.DrawPolygonList(lst)
- 个人学习记录-常用抓包工具/技术的总结 - 杨文的文章 - 知乎 https://zhuanlan.zhihu.com/p/25804326...
- JSON工具学习记录--FastJSON
- jQuery源码学习8——工具方法之init
- NLP大赛冠军总结:300万知乎多标签文本分类任务(附深度学习源码)
- Swoole源码学习记录(七)——MsgQueue
- 通过weui-1.1.3源码学习前端开发(二)构建工具gulp
- [置顶] TensorFlow RNN深度学习 BiLSTM+CRF 实现 sequence labeling 序列标注 源码
- 使用 AppFuse 的七个理由--学习 Java 开放源码工具 —— 并使用这些工具提高生产效率
- iperf工具学习记录
- [DB2 学习记录]2. DB2 工具
- Spring Framework Reference 5.0.2 源码学习记录 使用p-namespace和c-namespace
- 如何学习源码----转自知乎
- 自动布局(AutoLayout)[附带源码]【学习记录二】
- 记录学习LinkedList源码过程
- 麻雀虽小,五脏俱全:分析CVS活动情况的小工具(有源码供学习)
- NLP大赛冠军总结:300万知乎多标签文本分类任务(附深度学习源码)
- Blackarch工具学习记录--工具分类
- Handler消息机制源码学习记录
- Linux学习记录(2)安装Linux系统以及VirtualBox增强工具
- <学习记录>Queue源码学习