| from pathlib import Path |
| from typing import Iterable, List |
| import cv2 |
| import json |
| import numpy as np |
| import pandas as pd |
|
|
|
|
| def norm_by_x(df): |
| df['x'] = df['x'] - df['x'].min() |
| df['y'] = df['y'] - df['y'].min() |
| maxx = df['x'].max() |
| df['x'] /= maxx |
| df['y'] /= maxx |
| return df |
|
|
|
|
| def csv2dfs(filenames:Iterable[str], rotate_func:callable=None) -> List[pd.DataFrame]: |
| ''' Extract x,y coordinates from a .csv/.xlsx file. Each file may include multiple outlines.''' |
|
|
| |
| def _sheet2dfs(df, df_name): |
| dfs_local = [] |
| if 'Unnamed: 0' in df.columns: |
| df = df.drop(columns=['Unnamed: 0']) |
| column_pairs = [(df.columns[i], df.columns[i+1]) for i in range(0, len(df.columns)-1, 2)] |
| for x_col, y_col in column_pairs: |
| shoe_id = x_col |
| x, y = df[x_col].iloc[1:].astype(float), df[y_col].iloc[1:].astype(float) |
| if rotate_func: x, y = rotate_func(x, y) |
| shoe_df = pd.DataFrame({'x': x, 'y': y}).dropna() |
| shoe_df.name = shoe_id |
| dfs_local.append(shoe_df) |
| else: |
| df.name = df_name |
| dfs_local += [df] |
| return dfs_local |
|
|
| dfs = [] |
| for filename in filenames: |
| filename = Path(filename) |
|
|
| if filename.suffix.lower() == '.csv': |
| df = pd.read_csv(filename) |
| dfs += _sheet2dfs(df, filename.name) |
|
|
| elif filename.suffix.lower() == '.xlsx': |
| xls = pd.ExcelFile(filename) |
| for sheet in xls.sheet_names: |
| df = pd.read_excel(xls, sheet) |
| dfs += _sheet2dfs(df, sheet) |
| |
| elif filename.suffix.lower() == '.json': |
| vgg_json = json.load(filename.open()) |
| for _,v in vgg_json.items(): |
| fn = v['filename'] |
| for region in v['regions']: |
| if region['shape_attributes']['name'] != 'polygon': continue |
| xs,ys = region['shape_attributes']['all_points_x'], region['shape_attributes']['all_points_y'] |
| df = pd.DataFrame({'x':xs, 'y':ys}) |
| df.name = fn |
| dfs.append(df) |
| break |
|
|
| return dfs |
|
|
|
|
| def coordsdf2image(df:pd.DataFrame, target_height:int=256, margin:float=0.1) -> np.ndarray: |
| ''' Render a footprint outline from x,y coordinates in a DataFrame into a binary image (filled shape). ''' |
|
|
| x_coords, y_coords = df['x'].values, df['y'].values |
|
|
| |
| x_min, x_max = x_coords.min(), x_coords.max() |
| y_min, y_max = y_coords.min(), y_coords.max() |
| width = x_max - x_min |
| height = y_max - y_min |
|
|
| |
| scale = target_height / (1 + 2 * margin) / height |
| target_width = int(scale * width + 2 * margin * target_height) |
|
|
| image = np.zeros((target_height, target_width), dtype=np.uint8) |
|
|
| |
| x_scaled = ((x_coords - x_min) * scale).astype(np.int32) |
| y_scaled = ((y_coords - y_min) * scale).astype(np.int32) |
|
|
| |
| scaled_width = x_scaled.max() - x_scaled.min() |
| scaled_height = y_scaled.max() - y_scaled.min() |
|
|
| |
| x_scaled += (target_width - scaled_width) // 2 - x_scaled.min() |
| y_scaled += (target_height - scaled_height) // 2 - y_scaled.min() |
|
|
| contour = np.array([np.stack((x_scaled, y_scaled), axis=-1)], dtype=np.int32) |
| cv2.fillPoly(image, contour, color=255) |
| return image |