Adieee5 commited on
Commit
19dd704
Β·
verified Β·
1 Parent(s): 9cca4ab

Delete mesh-candidate_bestfit

Browse files
mesh-candidate_bestfit/README.md DELETED
@@ -1,102 +0,0 @@
1
- ## Pretraining Data Generation via Mesh-candidate Bestfit
2
-
3
- <p align="center">
4
- <img src="../assets/Mesh-candidate Bestfit.png" width=100%> <br>
5
- <i><small>Mesh-candidate Bestfit iteratively inserts elements from a small set of public datasets by searching for the best match between sampled candidates and the available grids in the current layout, ultimately achieving document synthesis.</i>
6
- </p>
7
-
8
- You can generate a large scale of diverse data for pretraining applying our proposed method Mesh-candidate Bestfit, just follow steps below:
9
-
10
- ### 1. Environment Setup
11
-
12
- You need to install [PyMuPDF](https://pypi.org/project/PyMuPDF/1.23.7/) for subsequent rendering via pip:
13
-
14
- ```bash
15
- cd mesh-candidate_bestfit
16
- pip install pymupdf==1.23.7
17
- ```
18
-
19
- ### 2. Preprocessing
20
-
21
- - **Data Preparation**
22
-
23
- Two primary things need to be well prepared before starting generation:
24
-
25
- 1\. **Original Annotation File of Initial Dataset**
26
-
27
- * The annotation file follows **COCO format**, a **JSON file** contains images and instances annotations.
28
- * Each instance should have a **unique** ```instance_id```.
29
- * The file should be placed under `./`.
30
-
31
- 2\. **Element Pool**
32
-
33
- Element Pool is constructed according to annotation file. Specifically, crop all the instances images and organize them in a category-wise manner. The structure of element pool is as follows (folder is named by each category and cropped image is named by unique ```instance_id```):
34
-
35
- ```bash
36
- ./element_pool
37
- β”œβ”€β”€ advertisement
38
- β”‚ β”œβ”€β”€ 727.jpg
39
- β”‚ β”œβ”€β”€ 919.jpg
40
- β”‚ β”œβ”€β”€ 1423.jpg
41
- β”‚ └── ...
42
- β”œβ”€β”€ algorithm
43
- β”‚ β”œβ”€β”€ 12653.jpg
44
- β”‚ β”œβ”€β”€ 17485.jpg
45
- β”‚ β”œβ”€β”€ 44364.jpg
46
- β”‚ └── ...
47
- └── ...
48
- ```
49
-
50
- **Note:** For convenience, we provide original annotation file and element pool for M6Doc-test dataset, which can be downloaded from [annotation file](https://drive.google.com/file/d/1ua41Gs3UW8iuoJp21tZ4-lczVrcEm-gP/view?usp=sharing) and [element pool](https://drive.google.com/file/d/1MrIFObKr1bDGgZLBQM_c_Dvobkp6mjFE/view?usp=sharing), respectively. And you can run the script below to decompress the element pool properly:
51
-
52
- ```bash
53
- unzip /path/to/your/element_pool.zip -d ./element_pool/
54
- ```
55
-
56
-
57
- - **Data Augmentation(Optional)**
58
-
59
- If you want to apply our designed augmentation pipeline to your element pool, you can just run:
60
-
61
- ```bash
62
- python augmentation.py --min_count 100 --aug_times 10
63
- ```
64
-
65
- The script will perform augmentation pipeline `aug_times` times on each element of categories whose element number is less than `min_count`. If you want to generate large amount of data, try larger `aug_times`. In contrast, you want to shorten this process, try smaller `aug_times`. During DocSynth300K generation, we use ```--aug_times 50```.
66
-
67
- - **Map Dict**
68
-
69
- To facilitate the random selection of candidates during the rendering phase, it is necessary to establish a mapping from candidate elements to all of their candidate paths (passing ```--use_aug``` is augmentation is implemented):
70
-
71
- ```bash
72
- python map_dict.py --save_path ./map_dict.json --use_aug
73
- ```
74
-
75
- ### 3. Layout Generation
76
-
77
- Now, you can generate diverse layouts using Mesh-candidate Bestfit algorithm. To prevent process blocking, it will save the result of each layout in a timely manner, but you can use the [combine_layouts.py](./combine_layouts.py) script to combine them all together like this:
78
-
79
- ```bash
80
- python bestfit_generator.py --generate_num 100 --n_jobs 5 --json_path ./annotation_file.json --output_dir ./generated_layouts/seperate
81
- python combine_layouts.py --seperate_layouts_dir ./generated_layouts/seperate --save_path ./generated_layouts/combined_layouts.json
82
- ```
83
-
84
- Afterwards, feel free to delete the seperate layouts since they are no longer used.
85
-
86
- **Note:** Due to multiprocessing used in layout generation, set proper ```--n_jobs``` to avoid process blocking.
87
-
88
- ### 4. Rendering
89
-
90
- Finally, you can render generated layouts and save the results in yolo format via the script below:
91
-
92
- ```bash
93
- python rendering.py --json_path ./generated_layouts/combined_layouts.json --n_jobs 5 --map_dict_path ./map_dict.json --save_dir ./generated_dataset
94
- ```
95
-
96
- ### Visualization
97
-
98
- We provide [visualize.ipynb](./visualize.ipynb) to visualize the layouts generated by our proposed methods. Here, we display some generation cases below:
99
-
100
- <p align="center">
101
- <img src="../assets/visualization.png" width=100%> <br>
102
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/augmentation.py DELETED
@@ -1,88 +0,0 @@
1
- import os
2
- import cv2
3
- import time
4
- import argparse
5
- import numpy as np
6
- from tqdm import tqdm
7
- import albumentations as A
8
-
9
-
10
- class EdgeDetection(A.ImageOnlyTransform):
11
- """
12
- A class for edge extraction of images with the sobel filter
13
- """
14
- def apply(self, img, **params):
15
- gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
16
- sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
17
- sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
18
- mag = np.hypot(sobelx, sobely)
19
- mag = mag / np.max(mag) * 255
20
- return np.uint8(mag)
21
-
22
-
23
- def pipeline(h, w):
24
- """
25
- Whole data augmentation pipeline with the input of image size
26
-
27
- Args:
28
- h (float): Height of the image.
29
- w (float): Width of the image.
30
- """
31
- return A.Compose([
32
- A.RandomBrightnessContrast(p=0.5),
33
- A.RandomResizedCrop(height=h, width=w, scale=(0.5, 0.9), ratio=(w / h, w / h), p=0.7), # keep h/w ratio the same
34
- EdgeDetection(p=0.2),
35
- A.ElasticTransform(alpha_affine=5, p=0.2),
36
- A.GaussNoise(var_limit=(100, 1200), p=1),
37
- ])
38
-
39
-
40
- def perform_augmentation(img, transform, save_dir, prefix_id, aug_times):
41
- """
42
- Perform augmentation for a single element with many times.
43
-
44
- Args:
45
- img (image): An elment.
46
- transform (sequence): Data augmentation pipeline.
47
- save_dir (str): Root directory to save.
48
- prefix_id (str): Raw id for the element.
49
- aug_times (int): Augmentation times.
50
- """
51
- for _ in range(aug_times):
52
- transformed = transform(image=img)
53
- transformed_image = transformed["image"]
54
- transformed_image_bgr = cv2.cvtColor(transformed_image, cv2.COLOR_RGB2BGR)
55
-
56
- suffix_id = str(time.time()).replace(".", "_")
57
- prefix_id_dir = os.path.join(save_dir, prefix_id)
58
- os.makedirs(prefix_id_dir, exist_ok=True)
59
- aug_element_path = os.path.join(prefix_id_dir, f'{prefix_id}_{suffix_id}.jpg')
60
- cv2.imwrite(aug_element_path, transformed_image_bgr)
61
-
62
-
63
-
64
- if __name__ == "__main__":
65
-
66
- parser = argparse.ArgumentParser(description="Perform Image Augmentation")
67
- parser.add_argument("--min_count", type=int, default=100, help="Minimum number of elements for categories that do not require data augmentation")
68
- parser.add_argument("--aug_times", type=int, default=50, help="Number of augmentations per element")
69
- args = parser.parse_args()
70
-
71
- root_dir = './element_pool'
72
-
73
- for category in tqdm(os.listdir(root_dir),desc='Categories done'):
74
- category_dir = os.path.join(root_dir,category)
75
- if len(os.listdir(category_dir)) > args.min_count:
76
- continue
77
- else:
78
- save_dir = os.path.join(category_dir, 'aug')
79
- for raw_element in os.listdir(category_dir):
80
- raw_element_path = os.path.join(category_dir, raw_element)
81
- img = cv2.imread(raw_element_path)
82
- img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
83
- h, w, c = img.shape
84
- element_id = raw_element.split('.')[0]
85
-
86
- transform = pipeline(h, w)
87
-
88
- perform_augmentation(img=img,transform=transform,save_dir=save_dir,prefix_id=element_id,aug_times=args.aug_times)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/bestfit_generator.py DELETED
@@ -1,143 +0,0 @@
1
- import os
2
- import json
3
- import time
4
- import torch
5
- import random
6
- import datetime
7
- import argparse
8
- import itertools
9
- import torchvision
10
- import multiprocessing
11
- from utils.process import *
12
-
13
- random.seed(datetime.datetime.now().timestamp())
14
-
15
-
16
- def bestfit_generator(element_all):
17
- """
18
- Apply the Mesh-candidate Bestfit algorithm to generate diverse layouts.
19
-
20
- Args:
21
- element_all (dict): Loaded elements from dataset json file.
22
- output_dir (str): Directory to save the generated layouts.
23
- """
24
- # Default candidate_num = 500
25
- candidate_num = 500
26
- large_elements_idx = random.sample(list(range(len(element_all['large']))), int(candidate_num*0.99))
27
- small_elements_idx = random.sample(list(range(len(element_all['small']))), int(candidate_num*0.01))
28
- cand_elements = [element_all['large'][large_idx] for large_idx in large_elements_idx] + [element_all['small'][small_idx] for small_idx in small_elements_idx]
29
-
30
- # Initially, randomly put an element
31
- put_elements = []
32
- e0 = random.choice(cand_elements)
33
- cx = random.uniform(min(e0.w/2, 1-e0.w/2), max(e0.w/2, 1-e0.w/2))
34
- cy = random.uniform(min(e0.h/2, 1-e0.h/2), max(e0.h/2, 1-e0.h/2))
35
- e0.cx, e0.cy = cx, cy
36
- put_elements = [e0]
37
- cand_elements.remove(e0)
38
- small_cnt = 1 if e0.w < 0.05 or e0.h < 0.05 else 0
39
-
40
- # Iterativelly insert elements
41
- while True:
42
- # Construct meshgrid based on current layout
43
- put_element_boxes = []
44
- xticks, yticks = [0,1], [0,1]
45
- for e in put_elements:
46
- x1, y1, x2, y2 = e.cx-e.w/2, e.cy-e.h/2, e.cx+e.w/2, e.cy+e.h/2
47
- xticks.append(x1)
48
- xticks.append(x2)
49
- yticks.append(y1)
50
- yticks.append(y2)
51
- put_element_boxes.append([x1, y1, x2, y2])
52
- xticks, yticks = list(set(xticks)), list(set(yticks))
53
- pticks = list(itertools.product(xticks, yticks))
54
- meshgrid = list(itertools.product(pticks, pticks))
55
- put_element_boxes = torch.Tensor(put_element_boxes)
56
-
57
- # Filter out invlid grids
58
- meshgrid = [grid for grid in meshgrid if grid[0][0] < grid[1][0] and grid[0][1] < grid[1][1]]
59
- meshgrid_tensor = torch.Tensor([p1 + p2 for p1, p2 in meshgrid])
60
- iou_res = torchvision.ops.box_iou(meshgrid_tensor, put_element_boxes)
61
- valid_grid_idx = (iou_res.sum(dim=1) == 0).nonzero().flatten().tolist()
62
- meshgrid = meshgrid_tensor[valid_grid_idx].tolist()
63
-
64
- # Search for the Mesh-candidate Bestfit pair
65
- max_fill, max_grid_idx, max_element_idx = 0, -1, -1
66
- for element_idx, e in enumerate(cand_elements):
67
- for grid_idx, grid in enumerate(meshgrid):
68
- if e.w > grid[2] - grid[0] or e.h > grid[3] - grid[1]:
69
- continue
70
- element_area = e.w * e.h
71
- grid_area = (grid[2] - grid[0]) * (grid[3] - grid[1])
72
- if element_area/grid_area > max_fill:
73
- max_fill = element_area/grid_area
74
- max_grid_idx = grid_idx
75
- max_element_idx = element_idx
76
-
77
- # Termination condition
78
- if max_element_idx == -1 or max_grid_idx == -1:
79
- break
80
- else:
81
- maxfit_element = cand_elements[max_element_idx]
82
- if maxfit_element.w < 0.05 or maxfit_element.h < 0.05:
83
- small_cnt += 1
84
- if small_cnt > 5:
85
- break
86
- else:
87
- pass
88
-
89
- # Put the candidate to the center of the grid
90
- cand_elements.remove(maxfit_element)
91
- maxfit_element.cx = (meshgrid[max_grid_idx][0] + meshgrid[max_grid_idx][2])/2
92
- maxfit_element.cy = (meshgrid[max_grid_idx][1] + meshgrid[max_grid_idx][3])/2
93
- put_elements.append(maxfit_element)
94
-
95
- # Apply a rescale transform to introduce more diversity
96
- for _, e in enumerate(put_elements):
97
- e.gen_real_bbox()
98
- layout = Layout(cand_elements=put_elements)
99
-
100
- # Convert the layout to json file format
101
- boxes, categories, relpaths = [], [], []
102
- for element in layout.cand_elements:
103
- cx, cy, w, h = element.get_real_bbox()
104
- x1, y1, x2, y2 = cx-w/2, cy-h/2, cx+w/2, cy+h/2
105
- boxes.append([x1, y1, x2, y2])
106
- categories.append(element.category-1) # Exclude the "__background__" category (category_id = 0)
107
- relpaths.append(element.filepath)
108
-
109
- output_layout = {
110
- "boxes": boxes,
111
- "categories": categories,
112
- "relpaths": relpaths
113
- }
114
-
115
- # To prevent process blocking, save the result of each layout in a timely manner.
116
- with open(os.path.join(OUTPUT_DIR,str(time.time()).replace(".", "_")+'.json'),'w') as f:
117
- json.dump(output_layout, f)
118
-
119
- return output_layout
120
-
121
-
122
-
123
- if __name__ == "__main__":
124
-
125
- parser = argparse.ArgumentParser()
126
- parser.add_argument('--generate_num', default=None, required=True, type=int, help='number of layouts to generate')
127
- parser.add_argument('--n_jobs', default=None, required=True, type=int, help='number of processes to use in multiprocessing')
128
- parser.add_argument('--json_path', default=None, required=True, type=str, help='original json file of the dataset')
129
- parser.add_argument('--output_dir', default='./generated_layouts/seperate', type=str, help='output directory of generated seperate layouts')
130
- args = parser.parse_args()
131
-
132
- element_all = read_data(args.json_path)
133
- OUTPUT_DIR = args.output_dir
134
- os.makedirs(OUTPUT_DIR,exist_ok=True)
135
-
136
- # Using multiprocessing to accelerate generation
137
- n_jobs = args.n_jobs
138
- with multiprocessing.Pool(n_jobs) as p:
139
- generated_layout = p.starmap(
140
- bestfit_generator, [(element_all,) for _ in range(args.generate_num)]
141
- )
142
- p.close()
143
- p.join()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/combine_layouts.py DELETED
@@ -1,32 +0,0 @@
1
- import os
2
- import json
3
- import argparse
4
- from tqdm import tqdm
5
-
6
-
7
- def combine_layouts(seperate_layouts_dir):
8
- """
9
- Combining seperate layouts into one json.
10
-
11
- Args:
12
- seperate_layouts_dir (str): Directory to save seperate layouts json files generated by bestfit_generator.py
13
- """
14
- combined_layouts = []
15
- for item in tqdm(os.listdir(seperate_layouts_dir),desc='Combining seperate layouts'):
16
- abs_path = os.path.join(seperate_layouts_dir,item)
17
- json_file = json.load(open(abs_path))
18
- combined_layouts.append(json_file)
19
- return combined_layouts
20
-
21
-
22
- if __name__ == "__main__":
23
-
24
- parser = argparse.ArgumentParser()
25
- parser.add_argument('--seperate_layouts_dir', default="./generated_layouts/seperate", type=str, help="directory to save seperate layouts")
26
- parser.add_argument('--save_path', default="./generated_layouts/combined_layouts.json", type=str, help='save path for combined generated layouts')
27
- args = parser.parse_args()
28
-
29
- combined_layouts = combine_layouts(seperate_layouts_dir=args.seperate_layouts_dir)
30
-
31
- with open(args.save_path,'w') as f:
32
- f.write(json.dumps(combined_layouts,indent=4))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/map_dict.py DELETED
@@ -1,48 +0,0 @@
1
- import os
2
- import json
3
- import argparse
4
- from tqdm import tqdm
5
-
6
-
7
- def get_map_dict(use_aug):
8
- """
9
- Get a map from a element to its corresponding save paths.
10
-
11
- Args:
12
- use_aug (bool): Whether use augmentation elements or not.
13
- """
14
- instance2pathlist = {}
15
- root_dir = './element_pool'
16
- for category in os.listdir(root_dir):
17
- if category == '.DS_Store':
18
- continue
19
- category_dir = os.path.join(root_dir,category)
20
- filelist = os.listdir(category_dir)
21
- for filename in tqdm(filelist):
22
- if filename == 'aug':
23
- continue
24
- else:
25
- sin_id_pathlist = []
26
- start_id = filename.split('.')[0]
27
- origin_path = os.path.join(category_dir,filename)
28
- sin_id_pathlist.append(origin_path)
29
- if 'aug' in filelist and use_aug:
30
- bottom_dir = os.path.join(category_dir,f'aug/{start_id}')
31
- aug_paths = os.listdir(bottom_dir)
32
- aug_pathlist = [os.path.join(bottom_dir,path) for path in aug_paths]
33
- sin_id_pathlist += aug_pathlist
34
- instance2pathlist[start_id] = sin_id_pathlist
35
- return instance2pathlist
36
-
37
-
38
- if __name__ == "__main__":
39
-
40
- parser = argparse.ArgumentParser()
41
- parser.add_argument('--use_aug', action='store_true', help="whether to use data augmentation")
42
- parser.add_argument('--save_path', default="./map_dict.json", type=str, help='save path for the map dict')
43
- args = parser.parse_args()
44
-
45
- map_dict = get_map_dict(use_aug=args.use_aug)
46
-
47
- with open(args.save_path,'w') as f:
48
- f.write(json.dumps(map_dict))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/rendering.py DELETED
@@ -1,83 +0,0 @@
1
- import os
2
- import time
3
- import fitz
4
- import json
5
- import random
6
- import argparse
7
- import datetime
8
- import multiprocessing
9
- from utils.process import *
10
-
11
- random.seed(datetime.datetime.now().timestamp())
12
-
13
-
14
- def render_layout(layouts):
15
- """
16
- Render layouts to images and save in the yolo format.
17
-
18
- Args:
19
- layouts (list): List of generated layouts information.
20
- """
21
- doc = fitz.open()
22
- w, h = sample_hw(
23
- width_range=[1200, 2000],
24
- ratio_range=[0.7,1.5],
25
- max_height=3000,
26
- )
27
- page = doc.new_page(width=w, height=h)
28
-
29
- annotation_json = {"bbox": [], "labels": [], "width":w, "height":h}
30
- for bbox, category, relpath in zip(layouts["boxes"], layouts["categories"], layouts["relpaths"]):
31
- bbox[0], bbox[2] = bbox[0]*w, bbox[2]*w
32
- bbox[1], bbox[3] = bbox[1]*h, bbox[3]*h
33
- rect = fitz.Rect([bbox[i] for i in range(4)])
34
-
35
- abs_filepath = os.path.join('./element_pool',relpath)
36
- start_str = abs_filepath.rsplit('/',1)[1].split('.')[0]
37
- sampled_path = random.choice(INSTANCE2PATHLIST[start_str])
38
-
39
- page.insert_image(rect, filename=sampled_path, keep_proportion=False)
40
-
41
- annotation_json["bbox"].append(bbox)
42
- annotation_json["labels"].append(category)
43
-
44
- _id = str(time.time()).replace(".", "_")
45
- pix = page.get_pixmap()
46
- pix.save(os.path.join(IMAGE_DIR, f"{_id}.jpg"))
47
- anno_txt = open(os.path.join(ANNO_DIR, f"{_id}.txt"), "w")
48
- for bbox, category_id in zip(annotation_json["bbox"], annotation_json["labels"]):
49
- w, h = annotation_json["width"], annotation_json["height"]
50
- x0, y0, x1, y1 = bbox
51
- x0, y0 = x0/w, y0/h
52
- x1, y1 = x1/w, y1/h
53
- anno_txt.write(f"{category_id} {x0} {y0} {x1} {y0} {x1} {y1} {x0} {y1}\n")
54
- anno_txt.close()
55
-
56
-
57
- if __name__ == "__main__":
58
-
59
- parser = argparse.ArgumentParser()
60
- parser.add_argument('--save_dir', default="./generated_dataset", type=str, help='planned root dir for generated dataset')
61
- parser.add_argument('--n_jobs', default=None, required=True, type=int, help='number of processes to use in multiprocessing')
62
- parser.add_argument('--json_path', default=None, required=True, type=str, help='json path for layouts generated by the Mesh-candidate Bestfit alogorithm')
63
- parser.add_argument('--map_dict_path', default=None, required=True, type=str, help='json path for element to pathlist map dict')
64
- args = parser.parse_args()
65
-
66
- # Setting save path
67
- IMAGE_DIR = os.path.join(args.save_dir, "images")
68
- ANNO_DIR = os.path.join(args.save_dir, "labels")
69
- os.makedirs(IMAGE_DIR, exist_ok=True)
70
- os.makedirs(ANNO_DIR, exist_ok=True)
71
-
72
- # Load layout data
73
- layout_json = json.load(open(args.json_path))
74
- INSTANCE2PATHLIST = json.load(open(args.map_dict_path))
75
-
76
- # Using multiprocessing to accelerate rendering
77
- n_jobs = args.n_jobs
78
- with multiprocessing.Pool(n_jobs) as p:
79
- result = p.starmap(
80
- render_layout, [(layout,) for layout in layout_json]
81
- )
82
- p.close()
83
- p.join()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/utils/base.py DELETED
@@ -1,29 +0,0 @@
1
- import random
2
-
3
- class element(object):
4
- def __init__(self, cx, cy, h, w, category, filepath):
5
- self.cx = cx
6
- self.cy = cy
7
- self.h = h
8
- self.w = w
9
- self.category = category
10
- self.filepath = filepath
11
- self.ratio = h / w
12
- self.area = h * w
13
-
14
- def gen_real_bbox(self):
15
- self.real_cx, self.real_cy = self.cx, self.cy
16
- self.real_w, self.real_h = self.w*random.uniform(0.8,0.95), self.h*random.uniform(0.8,0.95)
17
-
18
- def get_real_bbox(self):
19
- return self.real_cx, self.real_cy, self.real_w, self.real_h
20
-
21
- def __repr__(self):
22
- return f'cx: {self.cx}, cy: {self.cy}, h:{self.h}, w:{self.w}, category:{self.category}'
23
-
24
-
25
- class Layout(object):
26
- def __init__(self, cand_elements, align=None, fill=None):
27
- self.cand_elements = cand_elements
28
- self.align = align
29
- self.fill = fill
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/utils/process.py DELETED
@@ -1,42 +0,0 @@
1
- import os
2
- import json
3
- from .base import *
4
-
5
- def read_data(json_file):
6
- """
7
- Load elements from dataset json file.
8
-
9
- Args:
10
- json_file (str): A dataset json file path with coco format.
11
- """
12
- data = json.load(open(json_file))
13
- category_id2name = {item['id']:item['name'] for item in data['categories']}
14
- element_all = {'large':[], "small":[]}
15
- image2anno = {image["id"]:image for image in data["images"]}
16
- for anno in data["annotations"]:
17
- H, W = image2anno[anno["image_id"]]["height"], image2anno[anno["image_id"]]["width"]
18
- w, h = anno["bbox"][2], anno["bbox"][3]
19
- if w/W < 0.01 or h/H < 0.01:
20
- continue
21
- anno_id, category_id = anno['id'], anno["category_id"]
22
- e = element(cx=None, cy=None, h=h/H, w=w/W, category=category_id,filepath=f'{category_id2name[category_id]}/{anno_id}.jpg')
23
- if w/W >= 0.05 and h/H >= 0.05:
24
- element_all['large'].append(e)
25
- else:
26
- element_all['small'].append(e)
27
- return element_all
28
-
29
-
30
- def sample_hw(width_range, ratio_range, max_height):
31
- """
32
- Randomly sample a (w,h) size for rendering from a given range.
33
-
34
- Args:
35
- width_range (list): Given range of width.
36
- ratio_range (list): Given range of h/w ratio.
37
- max_height (int): Upper bound of height.
38
- """
39
- w = random.randint(width_range[0], width_range[1])
40
- ratio = random.uniform(ratio_range[0], ratio_range[1])
41
- h = min(max_height, int(w*ratio))
42
- return w, h
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mesh-candidate_bestfit/visualize.ipynb DELETED
The diff for this file is too large to render. See raw diff