label2COCO(area).py

网上找到的都是要积分下载,自己尝试着补充了下area计算,不一定正确..

mask面积计算:

1.根据labelme生成的json文件里的points来生成mask

2.确定目标检测框的位置(左上角位置,右下角位置)

3.依次计算mask中一行像素与下一行像素组成的梯形的面积,由于mask一定是连续的,所以梯形的边长可以通过遍历当前行像素的值来求(像素为1表示属于mask),最后对每一行求和.

 

完整代码如下(除了relArea其他是照搬的) 

 

# -*- coding:utf-8 -*-
# !/usr/bin/env python

import argparse
import json
import matplotlib.pyplot as plt
import skimage.io as io
import cv2
from labelme import utils
import numpy as np
import glob
import PIL.Image
class labelme2coco(object):
	def __init__(self,labelme_json=[],save_json_path='./new.json'):
		'''
		:param labelme_json: 所有labelme的json文件路径组成的列表
		:param save_json_path: json保存位置
		'''
		self.labelme_json=labelme_json
		self.save_json_path=save_json_path
		self.images=[]
		self.categories=[]
		self.annotations=[]
		# self.data_coco = {}
		self.label=[]
		self.annID=1
		self.height=0
		self.width=0

		self.save_json()

	def data_transfer(self):
		for num,json_file in enumerate(self.labelme_json):
			with open(json_file,'r') as fp:
				data = json.load(fp)  # 加载json文件
				self.images.append(self.image(data,num))
				for shapes in data['shapes']:
					print (shapes['label'])
					label=shapes['label'].split('_')
					print (json_file,label)
					if label[1] not in self.label:
						self.categories.append(self.categorie(label))
						self.label.append(label[1])
					points=shapes['points']
					self.annotations.append(self.annotation(points,label,num))
					self.annID+=1

	def image(self,data,num):
		image={}
		img = utils.img_b64_to_arr(data['imageData'])  # 解析原图片数据
		# img=io.imread(data['imagePath']) # 通过图片路径打开图片
		# img = cv2.imread(data['imagePath'], 0)
		height, width = img.shape[:2]
		img = None
		image['height']=height
		image['width'] = width
		image['id']=num+1
		image['file_name'] = data['imagePath'].split('/')[-1]

		self.height=height
		self.width=width

		return image

	def categorie(self,label):
		categorie={}
		categorie['supercategory'] = label[0]
		categorie['id']=len(self.label)+1 # 0 默认为背景
		categorie['name'] = label[1]
		return categorie

	"""
		自己写的计算mask面积的方法(只适用于单个对象polygen形状标注),先生成mask,然后依次计算相邻行像素组成的mask面积(上底+下底)*h/2,h是像素1,底边长通过遍历当前行像素值得到(0为非mask),最后求和得到mask面积
		"""
	def rleArea(self,points):
		#points = [[100,105],[50,105],[50,200],[100,200]]
		mask = self.polygons_to_mask([self.height,self.width], points)
		# np.where(mask==1)
		index = np.argwhere(mask == 1)
		rows = index[:, 0]
		clos = index[:, 1]
		# 解析左上角行列号
		start_h = np.min(rows)  # y
		start_w = np.min(clos)  # x

		# 解析右下角行列号
		end_h = np.max(rows)
		end_w = np.max(clos)

		area = 0
		#print start_h,end_h,start_w,end_w
		for i in range(start_h,end_h):
			top = 0
			bottom = 0
			for j in range(start_w,end_w):
				if(mask[i,j] == 1):
					top+=1
			for j in range(start_w,end_w):
				if(mask[i+1,j] == 1):
					bottom+=1
			#print (i,top,bottom)
			area += (top+bottom)/2
		return area			

	def annotation(self,points,label,num):
		annotation={}
		annotation['segmentation']=[list(np.asarray(points).flatten())]
		annotation['iscrowd'] = 0
		annotation['image_id'] = num+1
		# annotation['bbox'] = str(self.getbbox(points)) # 使用list保存json文件时报错(不知道为什么)
		# list(map(int,a[1:-1].split(','))) a=annotation['bbox'] 使用该方式转成list
		annotation['bbox'] = list(map(float,self.getbbox(points)))
		"""
		   自己写的计算mask面积的方法(只适用于单个对象polygen形状标注),先生成一个全黑的原图片大小的图片,然后填充标注得到的多边形,然后依次计算相邻行像素组成的mask面积(上底+下底)*h/2,h是像素1,底边长通过遍历当前行像素值得到(0为非mask),最后求和得到mask面积
		"""
		annotation['area'] = self.rleArea(points)
		annotation['category_id'] = self.getcatid(label)
		annotation['id'] = self.annID
		return annotation

	def getcatid(self,label):
		for categorie in self.categories:
			if label[1]==categorie['name']:
				return categorie['id']
		return -1

	def getbbox(self,points):
		# img = np.zeros([self.height,self.width],np.uint8)
		# cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA)  # 画边界线
		# cv2.fillPoly(img, [np.asarray(points)], 1)  # 画多边形 内部像素值为1
		polygons = points
		mask = self.polygons_to_mask([self.height,self.width], polygons)
		return self.mask2box(mask)

	def mask2box(self, mask):
		'''从mask反算出其边框
		mask:[h,w]  0、1组成的图片
		1对应对象,只需计算1对应的行列号(左上角行列号,右下角行列号,就可以算出其边框)
		'''
		# np.where(mask==1)
		index = np.argwhere(mask == 1)
		rows = index[:, 0]
		clos = index[:, 1]
		# 解析左上角行列号
		left_top_r = np.min(rows)  # y
		left_top_c = np.min(clos)  # x

		# 解析右下角行列号
		right_bottom_r = np.max(rows)
		right_bottom_c = np.max(clos)

		# return [(left_top_r,left_top_c),(right_bottom_r,right_bottom_c)]
		# return [(left_top_c, left_top_r), (right_bottom_c, right_bottom_r)]
		# return [left_top_c, left_top_r, right_bottom_c, right_bottom_r]  # [x1,y1,x2,y2]
		return [left_top_c, left_top_r, right_bottom_c-left_top_c, right_bottom_r-left_top_r]  # [x1,y1,w,h] 对应COCO的bbox格式

	def polygons_to_mask(self,img_shape, polygons):
		mask = np.zeros(img_shape, dtype=np.uint8)
		mask = PIL.Image.fromarray(mask)
		xy = list(map(tuple, polygons))
		PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
		mask = np.array(mask, dtype=bool)
		return mask

	def data2coco(self):
		data_coco={}
		data_coco['images']=self.images
		data_coco['categories']=self.categories
		data_coco['annotations']=self.annotations
		return data_coco

	def save_json(self):
		self.data_transfer()
		self.data_coco = self.data2coco()
		# 保存json文件
		json.dump(self.data_coco, open(self.save_json_path, 'w'), indent=4)  # indent=4 更加美观显示

labelme_json=glob.glob('./jsons/*.json')
# labelme_json=['./1.json']

labelme2coco(labelme_json,'./new.json')

 

 

 

你可能感兴趣的:(优化,labeme2COCO)