您的位置:首页 > 编程语言

ImagePy智能标注工具源码学习记录 - 知乎

2020-03-19 20:05 309 查看

【推荐阅读】微服务还能火多久?>>>

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

] += 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()

[p]

一个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/1209216271340064768

ImagePy_Learn学习系列

土盐:ImagePy_Learn | 图形学绘制代码学习:core\draw\fill.py

土盐:ImagePy_Learn | 图形学绘制代码学习:paint.py

土盐:ImagePy_Learn | 图形学绘制代码学习:core\draw\polygonfill.py

土盐:基于ImagePy编写插件之迷途探索WXPython

土盐:ImagePy起手式IPy.py代码解析

学习记录:

1、python中数组(numpy.array)的基本操作

CSDN-专业IT技术社区-登录


2、buf=np.pad(img, 1, 'constant')

numpy中pad函数的常用方法 - hezhiyao - 博客园​ www.cnblogs.com

3、

CSDN-专业IT技术社区-登录


4、

" / "就表示 浮点数除法,返回浮点结果;" // "表示整数除法。


5、returnnp.dot(idx, acc[::-1])

对NumPy中dot()函数的理解​ www.cnblogs.com


6、s, line=0, img.ravel()

Numpy中扁平化函数ravel()和flatten()的区别 - weller - 博客园​ www.cnblogs.com


7、sort=np.argsort(key)

np.argsort()的用法


8、return rst[:unique(rst)].copy()

深拷贝数组 np.copy - 深度学习1 - 博客园​ www.cnblogs.com

9、

  • append() 方法向列表的尾部添加一个新的元素。
  • 列表是以类的形式实现的。“创建”列表实际上是将一个类实例化。因此,列表有多种方法可以操作。extend()方法只接受一个列表作为参数,并将该参数的每个元素都添加到原有的列表中。

Python List append()方法


源码:

imagepy/imagepy/tools/Draw/aibrush_tol.py /

https://github.com/Image-Py/imagepy/blob/0e3be4c056cc85de55e0294099656b85950397b8/imagepy/tools/Draw/aibrush_tol.py​ github.com
from 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.com
import 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.com
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 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)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  pen def mark h2 github