前言
早前做分割任务用的标注工具生成的只有json,训练需要mask图片,于是手写了一个效率极低的根据点集制作掩膜图片,最近使用opencv自带的多边形填充方法优化了下,瞬间觉得自己以前的顺势思维太简单,还是直接调用别人的方法用着好。
1.问题描述
使用lableme或者labelimg的多边形标注做分割任务,生成点集json,想要根据点集生成一张点集区域内为白色,区域外纯黑的mask图片。
2.代码原逻辑
纯黑图片上每个小范围取一个点P,每个点判断是否在json的点集包围的区域内,如果点P在区域内,则P的小范围都白色。(其中利用点P发射的一条射线与点集形成的线段做相交判断,P在区域内,射线与线段相交数为奇数,否则为偶数)
3.代码新逻辑
opencv自带根据点集合填充内容的方法cv2.fillPoly,速度惊人。
4.全部代码附下:
import json
import time
import cv2
import numpy as np
'''
判断点p是否在pointList围城的多边形内
思路:线段相交,点发射射线与边交点个数为奇数
'''
def PointInPolygon(pointList,p):
#比全部顶点x最大值小,比全部x最小值大,比全部y最小值大,比全部y最大值小
pointList_min=np.min(pointList,axis=0)
pointList_max=np.max(pointList,axis=0)
p1=np.array(p)
if (p1[0]>=pointList_min[0] and p1[0]<=pointList_max[0] and p1[1]>=pointList_min[1] and p1[1]<=pointList_max[1] ):
p2=np.array([-2,-2])#任意图像外一点即可
intersect_count=0
for i,q_point in enumerate(pointList):
# 方法:点发射线与全部边相交的个数为奇数
if(i<len(pointList)-1):
q1=q_point
q2=pointList[i+1]
if (intersect(p1, p2, q1, q2)):
intersect_count += 1
if(intersect_count%2==1):
return True
return False
'''
优化策略:只取横纵坐标i,j奇数点加入PointInPolygon判断,如果是直接将其和周围九个点加到集合,返回最终集合
area_range越大速度越快
'''
def OptimizePointInPolygon(pointList,w,h,area_range=2):
lastArr=[]
for i in range(w):
for j in range(h):
if(i%area_range==(area_range-1) and j%area_range==(area_range-1)):#这里没必要所有的都检查,根据加一个之后,area_range内的点不加
if (PointInPolygon(pointList, [i, j])):
nearPoints = GetNearByPoints([i, j], w, h, area_range)
lastArr += nearPoints
return lastArr
def limit_range(x,min,max):
if(x<min):x=min
if(x>max):x=max
return x
def GetNearByPoints(point,w,h,area_range=2):
assemble=[]
tmp_left=(area_range+1)//2#奇数时左边多一个
tmp_right=(area_range)//2
left0=limit_range(point[0]-tmp_left,0,w-1)
right0=limit_range(point[0]+tmp_right,0,w-1)
left1 = limit_range(point[1] - tmp_left, 0, h - 1)
right1 = limit_range(point[1] + tmp_right, 0, h - 1)
for i in range(left0,right0+1,1):
for j in range(left1,right1+1, 1):
assemble.append((i,j))
return assemble
'''
用于判断ab与cd相交
'''
def intersect(a,b,c,d):
ca=c-a
ba=b-a
da=d-a
dc=d-c
cb=c-b
u=ca[0]*ba[1]-ba[0]*ca[1]
v=da[0]*ba[1]-ba[0]*da[1]
w=ca[0]*dc[1]-dc[0]*ca[1]
z=cb[0]*dc[1]-dc[0]*cb[1]
return u * v <= 0 and w * z <= 0
def getPointListFromJson(jsonPath):
resultPoints=[]
with open(jsonPath, 'r', encoding='gb2312') as f:
ret_dic = json.load(f)
# print(ret_dic) # 结果 pengjunlee
data = ret_dic["shapes"]
image_name = ret_dic["imagePath"]
# print(image_name)
single_data_list = []
single_data_list.append(image_name)
for k, v in enumerate(data):
# print(v["points"])
for point in v["points"]:
resultPoints.append(point)
resultPoints.append(resultPoints[0]) # 把第一个也加到最后
return resultPoints
def gen_mask_by_json(imgPath,jsonPath):
pointList=getPointListFromJson(jsonPath)
pointList = np.array(pointList)
img_cv2_gray= cv2.imread(imgPath,0)
h,w=img_cv2_gray.shape
empty_img=np.zeros((h,w)).astype(np.uint8)
start_time=time.time()
#####fun1,cv2系统自带,效率极快:
cv2.fillPoly(empty_img,[pointList.astype(np.int32)], (255, 255, 255))
#####func2,自己写的,速度太慢:
# getMaskPoint = OptimizePointInPolygon(pointList, w, h,area_range=4)
# for point in getMaskPoint:
# empty_img[point[1]][point[0]] = 255
print("use time:",time.time()-start_time)
cv2.imshow("1",empty_img)
cv2.waitKey(0)
# cv2.imwrite("./data/gray.jpg", empty_img)
pass
if __name__ == '__main__':
imgPath="./data/test.jpg"
jsonPath = "./data/test.json"
gen_mask_by_json(imgPath,jsonPath)
请将图片和json路径替换为你的即可看效果。

1665

被折叠的 条评论
为什么被折叠?



