|
- # -*- coding: utf-8 -*-#
- #-------------------------------------------------------------------------------
- # Name: ccpd_to_coco_keypoints.py
- # Author: wdf
- # Date: 2019/10/18
- # IDE: PyCharm
- # Description: 把ccod车牌检测数据集转化为coco格式(keypoints)
- # Usage:
- # python ccpd_to_coco_keypoints.py --data "./data"
- #-------------------------------------------------------------------------------
-
- import datetime
- import json
- import cv2
- from random import randint
- import numpy as np
- from pathlib import Path
-
- from PIL import Image, ImageDraw
-
- import time
-
- from multiprocessing import pool
- '''
- from pycococreatortools import pycococreatortools
-
- import os
- file_path = os.getcwd() + '/map/' # 在当前目录下新建map文件夹,用于存储map中间结果图
- if not os.path.exists(file_path):
- os.mkdir(file_path)
- '''
- import argparse
-
- parser = argparse.ArgumentParser()
- ## 从命令行指定kjdz文件夹
- '''目录树如下
- |- KJDZ
- |-- IMAGES
- |---- *.jpg
- |-- ANNOTATIONS
- |---- *.txt
- '''
- parser.add_argument("--data",
- default=None,
- type=str,
- required=True,
- help="The input data dir. Should contain all the images")
-
- args = parser.parse_args()
-
- IMAGE_DIR = Path(args.data)
-
-
- INFO = {
- "description": "CCPD Dataset in COCO Format",
- "url": "",
- "version": "0.1.0",
- "year": 2019,
- "contributor": "Tristan, Onlyyou intern",
- "date_created": datetime.datetime.utcnow().isoformat(' ') # 显示此刻时间,格式:'2019-04-30 02:17:49.040415'
- }
-
- LICENSES = [
- {
- "id": 1,
- "name": "ALL RIGHTS RESERVED",
- "url": ""
- }
- ]
- # 初始化类别(背景)
- CATEGORIES = [
- {
- 'id': 1,
- 'name': 'license plate',
- 'supercategory': 'shape',
- },
- {
- 'id': 2,
- 'name': 'background',
- 'supercategory': 'shape',
- }
- ]
-
-
- # 根据车牌的四个角点绘制精确的segmentation map
- def make_seg_mask(map, segmentions,color=(0,255,0)):
- c = np.array([[segmentions]], dtype=np.int32)
- cv2.fillPoly(map, c, color)
-
- def random_color(class_id):
- '''预定义12种颜色,基本涵盖kjdz所有label类型
- 颜色对照网址:https://tool.oschina.net/commons?type=3'''
- colorArr = [(255,0,0), # 红色
- (255,255,0), # 黄色
- (0, 255, 0), # 绿色
- (0,0,255), # 蓝色
- (160, 32, 240), # 紫色
- (165, 42, 42), # 棕色
- (238, 201, 0), # gold
- (255, 110, 180), # HotPink1
- (139, 0 ,0), #DarkRed
- (0 ,139 ,139),#DarkCyan
- (139, 0 ,139),# DarkMagenta
- (0 ,0 ,139) # dark blue
- ]
- if class_id < 11:
- return colorArr[class_id]
- else: # 如有特殊情况,类别数超过12,则随机返回一个颜色
- rm_col = (randint(0,255),randint(0,255),randint(0,255))
- return rm_col
-
- # 获取 bounding-box, segmentation 信息
- # 输入:image path
- # 返回:
- # bounding box
- # four locations
-
- def get_info(im_file):
- img_name = str(im_file)
- lbl = img_name.split('/')[-1].rsplit('.', 1)[0].split('-')[-3] # label: '16_2_32_30_25_29_6'
- iname = img_name.rsplit('/', 1)[-1].rsplit('.', 1)[0].split('-')
- [leftUp, rightDown] = [[float(eel) for eel in el.split('&')] for el in iname[2].split('_')] # bounding box
- height = rightDown[1]-leftUp[1]
- width = rightDown[0]-leftUp[0]
- left = leftUp[0]
- top = leftUp[1]
- segmentation = [[float(eel) for eel in el.split('&')] for el in iname[3].split('_')] # four vertices locations
-
- return [left, top, width, height], segmentation
-
-
- # 计算任意多边形的面积,顶点按照顺时针或者逆时针方向排列
- def compute_polygon_area(points):
- point_num = len(points)
- if(point_num < 3):
- return 0.0
- s = points[0][1] * (points[point_num-1][0] - points[1][0])
- #for i in range(point_num): # (int i = 1 i < point_num ++i):
- for i in range(1, point_num):
- s += points[i][1] * (points[i-1][0] - points[(i+1)%point_num][0])
- return abs(s/2.0)
-
-
- def create_image_info(image_id, file_name, image_size,
- date_captured=datetime.datetime.utcnow().isoformat(' '),
- license_id=1, coco_url="", flickr_url=""):
- image_info = {
- "id": image_id,
- "file_name": file_name,
- "width": image_size[0],
- "height": image_size[1],
- "date_captured": date_captured,
- "license": license_id,
- "coco_url": coco_url,
- "flickr_url": flickr_url
- }
-
- return image_info
-
- # 汇总 mask、bounding-box等信息
- def mask_create_annotation_info(annotation_id, image_id, category_id, image_size=None, bounding_box=None,segmentation= None):
- annotation_info = {
- "id": annotation_id,
- "image_id": image_id,
- "category_id": category_id,
- "iscrowd": 0, # 0或1,指定为0,表示“单个的对象(不存在多个对象重叠)”.只要是iscrowd=0那么segmentation就是polygon格式
- "area": compute_polygon_area(segmentation), # area是area of encoded masks,是标注区域的面积。如果是矩形框,那就是高乘宽; 浮点数,需大于0,因icdar数据没有segmentation,所以本项人为指定为10
- "bbox": bounding_box,
- "segmentation": segmentation, #polygon格式.这些数按照相邻的顺序两两组成一个点的xy坐标,如果有n个数(必定是偶数),那么就是n/2个点坐标。
- "keypoints":[segmentation[0][0],segmentation[0][1],2,segmentation[1][0],segmentation[1][1],2,segmentation[2][0],segmentation[2][1],2,segmentation[3][0],segmentation[3][1],2],
- # 12个数,每个数都是浮点数,表示一个关键点的坐标,以及一个关键点的可见性。可见性是0,1,2,其中0表示不可见,2表示可见。如果有n个关键点,那么就是3n个数。这里只有4个关键点,所以是12个数
-
- "width": image_size[0],
- "height": image_size[1],
- }
-
- return annotation_info
-
-
- def main():
- # coco lable文件(如training2017.json)需要存储的信息
- coco_output = {
- "info": INFO,
- "licenses": LICENSES,
- "categories": CATEGORIES,
- "images": [],
- "annotations": []
- }
-
- # 初始化id(以后依次加一)
- image_id = 1
- annotation_id = 1
-
- # 加载图片信息
- im_files = [f for f in IMAGE_DIR.iterdir()]
- im_files.sort(key=lambda f: f.stem,reverse=True) # 排序,防止顺序错乱、数据和标签不对应
- # print("im-length:",len(im_files),"\n im_files:",im_files)
-
- myPool = pool.Pool(processes=4) # 并行化处理
-
- for im_file in im_files:
- # 写入图片信息(id、图片名、图片大小),其中id从1开始
- image = Image.open(im_file)
- im_info = create_image_info(image_id, im_file.name, image.size) # 图片信息
- coco_output['images'].append(im_info) # 存储图片信息(id、图片名、大小)
-
-
- annotation_info_list = [] # 存储标注信息
-
- # 处理label信息, 包括左上角、右下角、四个角点(用于分割)
- bounding_box, segmentation = get_info(im_file)
- class_id = 1 # id 为数字形式,如 1,此时是list形式,后续需要转换 # 指定为1,因为只有”是车牌“这一类
-
- # 显示日志
- print(bounding_box, segmentation)
-
- '''
- draw = ImageDraw.Draw(image)
- points = [tuple(point) for point in segmentation]
- draw.polygon(points, outline=(255, 0, 0))
- image.save('result/'+im_file.name + '-draw.jpg')
- '''
-
- annotation_info = mask_create_annotation_info(annotation_id, image_id, class_id, image.size, bounding_box, segmentation)
- if annotation_info is not None:
- if (segmentation[0][0]**2 + segmentation[0][1]**2) > (segmentation[1][0]**2 + segmentation[1][1]**2) and (segmentation[0][0]**2 + segmentation[0][1]**2) > (segmentation[2][0]**2 + segmentation[2][1]**2) and (segmentation[0][0]**2 + segmentation[0][1]**2) > (segmentation[3][0]**2 + segmentation[3][1]**2):
- coco_output['annotations'].append(annotation_info)
- image_id += 1
-
- # 保存成json格式
- print("[INFO] Storing annotations json file...")
- output_json = Path(f'ccpd_annotations_test.json')
- with output_json.open('w', encoding='utf-8') as f:
- json.dump(coco_output, f)
- print("[INFO] Annotations JSON file saved in:", str(output_json))
-
- if __name__ == "__main__":
- start_time = time.time()
- main()
- end_time = time.time()
- print(f"Elapsed time(s): {end_time - start_time}")
|