Create shoe_outlines_lib.py
Browse files- shoe_outlines_lib.py +99 -0
shoe_outlines_lib.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
from typing import Iterable, List
|
| 3 |
+
import cv2
|
| 4 |
+
import json
|
| 5 |
+
import numpy as np
|
| 6 |
+
import pandas as pd
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def norm_by_x(df):
|
| 10 |
+
df['x'] = df['x'] - df['x'].min()
|
| 11 |
+
df['y'] = df['y'] - df['y'].min()
|
| 12 |
+
maxx = df['x'].max()
|
| 13 |
+
df['x'] /= maxx
|
| 14 |
+
df['y'] /= maxx
|
| 15 |
+
return df
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def csv2dfs(filenames:Iterable[str], rotate_func:callable=None) -> List[pd.DataFrame]:
|
| 19 |
+
''' Extract x,y coordinates from a .csv/.xlsx file. Each file may include multiple outlines.'''
|
| 20 |
+
|
| 21 |
+
# if multiple x,y columns in the csv/xlsx file
|
| 22 |
+
def _sheet2dfs(df, df_name):
|
| 23 |
+
dfs_local = []
|
| 24 |
+
if 'Unnamed: 0' in df.columns:
|
| 25 |
+
df = df.drop(columns=['Unnamed: 0'])
|
| 26 |
+
column_pairs = [(df.columns[i], df.columns[i+1]) for i in range(0, len(df.columns)-1, 2)]
|
| 27 |
+
for x_col, y_col in column_pairs:
|
| 28 |
+
shoe_id = x_col
|
| 29 |
+
x, y = df[x_col].iloc[1:].astype(float), df[y_col].iloc[1:].astype(float)
|
| 30 |
+
if rotate_func: x, y = rotate_func(x, y)
|
| 31 |
+
shoe_df = pd.DataFrame({'x': x, 'y': y}).dropna()
|
| 32 |
+
shoe_df.name = shoe_id
|
| 33 |
+
dfs_local.append(shoe_df)
|
| 34 |
+
else:
|
| 35 |
+
df.name = df_name
|
| 36 |
+
dfs_local += [df]
|
| 37 |
+
return dfs_local
|
| 38 |
+
|
| 39 |
+
dfs = []
|
| 40 |
+
for filename in filenames:
|
| 41 |
+
filename = Path(filename)
|
| 42 |
+
|
| 43 |
+
if filename.suffix.lower() == '.csv':
|
| 44 |
+
df = pd.read_csv(filename)
|
| 45 |
+
dfs += _sheet2dfs(df, filename.name)
|
| 46 |
+
|
| 47 |
+
elif filename.suffix.lower() == '.xlsx':
|
| 48 |
+
xls = pd.ExcelFile(filename)
|
| 49 |
+
for sheet in xls.sheet_names:
|
| 50 |
+
df = pd.read_excel(xls, sheet)
|
| 51 |
+
dfs += _sheet2dfs(df, sheet)
|
| 52 |
+
|
| 53 |
+
elif filename.suffix.lower() == '.json':
|
| 54 |
+
vgg_json = json.load(filename.open())
|
| 55 |
+
for _,v in vgg_json.items():
|
| 56 |
+
fn = v['filename']
|
| 57 |
+
for region in v['regions']:
|
| 58 |
+
if region['shape_attributes']['name'] != 'polygon': continue
|
| 59 |
+
xs,ys = region['shape_attributes']['all_points_x'], region['shape_attributes']['all_points_y']
|
| 60 |
+
df = pd.DataFrame({'x':xs, 'y':ys})
|
| 61 |
+
df.name = fn
|
| 62 |
+
dfs.append(df)
|
| 63 |
+
break
|
| 64 |
+
|
| 65 |
+
return dfs
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def coordsdf2image(df:pd.DataFrame, target_height:int=256, margin:float=0.1) -> np.ndarray:
|
| 69 |
+
''' Render a footprint outline from x,y coordinates in a DataFrame into a binary image (filled shape). '''
|
| 70 |
+
|
| 71 |
+
x_coords, y_coords = df['x'].values, df['y'].values
|
| 72 |
+
|
| 73 |
+
# Compute the bounding box of the footprint
|
| 74 |
+
x_min, x_max = x_coords.min(), x_coords.max()
|
| 75 |
+
y_min, y_max = y_coords.min(), y_coords.max()
|
| 76 |
+
width = x_max - x_min
|
| 77 |
+
height = y_max - y_min
|
| 78 |
+
|
| 79 |
+
# Compute canvas width proportional to the footprint's aspect ratio
|
| 80 |
+
scale = target_height / (1 + 2 * margin) / height
|
| 81 |
+
target_width = int(scale * width + 2 * margin * target_height)
|
| 82 |
+
|
| 83 |
+
image = np.zeros((target_height, target_width), dtype=np.uint8)
|
| 84 |
+
|
| 85 |
+
# Scale coordinates to fit within the canvas
|
| 86 |
+
x_scaled = ((x_coords - x_min) * scale).astype(np.int32)
|
| 87 |
+
y_scaled = ((y_coords - y_min) * scale).astype(np.int32)
|
| 88 |
+
|
| 89 |
+
# Compute the size of the scaled footprint
|
| 90 |
+
scaled_width = x_scaled.max() - x_scaled.min()
|
| 91 |
+
scaled_height = y_scaled.max() - y_scaled.min()
|
| 92 |
+
|
| 93 |
+
# Compute and apply offsets for centering
|
| 94 |
+
x_scaled += (target_width - scaled_width) // 2 - x_scaled.min()
|
| 95 |
+
y_scaled += (target_height - scaled_height) // 2 - y_scaled.min()
|
| 96 |
+
|
| 97 |
+
contour = np.array([np.stack((x_scaled, y_scaled), axis=-1)], dtype=np.int32)
|
| 98 |
+
cv2.fillPoly(image, contour, color=255) # Fill the shape with white (255)
|
| 99 |
+
return image
|