Spaces:
Runtime error
Runtime error
| from nest2D import Point, Box, Item, nest, SVGWriter | |
| import plotly | |
| import numpy as np | |
| import plotly.graph_objects as go | |
| import cv2 | |
| import gradio as gr | |
| def transform(point:list, x:float, y:float, rotation:float): | |
| if point is None: | |
| return None | |
| point = np.array([point[0], point[1], 1]) | |
| matrix = np.array([[np.cos(rotation), -np.sin(rotation), x], | |
| [np.sin(rotation), np.cos(rotation), y], | |
| [0,0,1]]) | |
| return (matrix@point)[:2] | |
| class BinPacking: | |
| def __init__(self, width:int, height:int, image:np.ndarray, imageScale:float=1) -> None: | |
| self.width = width | |
| self.height = height | |
| self.pgrp = None | |
| self.total = 0 | |
| self.image = cv2.resize(image, (int(image.shape[1]*imageScale), int(image.shape[0]*imageScale))) | |
| if self.image.shape[2] == 4: | |
| x,y = np.where(self.image[:,:,3]==0) | |
| self.image[x,y] = np.array([255,255,255,0]) | |
| self.imgray = cv2.cvtColor(self.image, cv2.COLOR_BGRA2GRAY) | |
| else: | |
| self.imgray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) | |
| self.imgray = cv2.bitwise_not(self.imgray) | |
| def box(self): | |
| return Box(self.width, self.height) | |
| def pack(self): | |
| # make margin | |
| imagem = cv2.dilate(self.imgray, np.ones((3,3), np.uint8), iterations=10) | |
| _, thresh = cv2.threshold(imagem, 127, 255, 0) | |
| contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
| contourList = [] | |
| for contour in contours: | |
| contourList.extend(contour) | |
| hull = cv2.convexHull(np.array(contourList).reshape(-1,2)) | |
| hull = np.append(hull, [hull[0]], axis=0).reshape(-1,2) | |
| item = Item( | |
| [ | |
| Point(point[0], point[1]) | |
| for point in np.flip(hull, 0) | |
| ] | |
| ) | |
| max_item = int(self.width*self.height/item.area) | |
| self.pgrp = nest([item,]*max_item, self.box) | |
| if self.pgrp is None or len(self.pgrp) == 0: | |
| self.total = 0 | |
| else: | |
| self.total = len(self.pgrp[0]) | |
| return self | |
| def visualize(self): | |
| fig = go.Figure() | |
| widthScale = self.width/self.height | |
| fig.update_layout( | |
| autosize=False, | |
| width=500*widthScale, | |
| height=500, | |
| margin=dict( | |
| l=50, | |
| r=50, | |
| b=50, | |
| t=50, | |
| pad=4 | |
| ), | |
| paper_bgcolor="LightSteelBlue", | |
| showlegend=False, | |
| ) | |
| if self.pgrp == None or len(self.pgrp) == 0: | |
| return fig | |
| _, thresh = cv2.threshold(self.imgray, 127, 255, 0) | |
| contours, _ = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | |
| transformedPoints = [] | |
| for item in self.pgrp[0]: | |
| for contour in contours: | |
| for point in contour: | |
| transformedPoints.append(transform(point[0], item.translation.x, item.translation.y, item.rotation)) | |
| transformedPoints.append([None,None]) | |
| transformedPoints.append([None,None]) | |
| fig.add_trace(go.Scatter( | |
| x=[0, self.width, self.width, 0, 0], | |
| y=[0, 0, self.height, self.height, 0], | |
| fill="toself", | |
| mode="lines", | |
| textposition="bottom right", | |
| )) | |
| fig.add_trace(go.Scatter( | |
| x=[point[0] for point in transformedPoints], | |
| y=[point[1] for point in transformedPoints], | |
| mode="lines", | |
| textposition="bottom right", | |
| )) | |
| return fig | |
| def process(width:int, height:int, scale:float, image: np.ndarray): | |
| packer = BinPacking(width, height, image, scale) | |
| packer.pack() | |
| figure = packer.visualize() | |
| if packer.total == 0: | |
| text = "Input too big" | |
| else: | |
| text = f"Fit {packer.total} instances" | |
| return [figure, text] | |
| def change_language(languageSelection): | |
| return [ | |
| gr.Dropdown.update(value="English" if languageSelection == "English" else "日本語"), | |
| gr.Slider.update(label="Width" if languageSelection == "English" else "横長"), | |
| gr.Slider.update(label="Height" if languageSelection == "English" else "縦長"), | |
| gr.Slider.update(label="Input Scale" if languageSelection == "English" else "入力拡大"), | |
| gr.Markdown.update( | |
| """ | |
| # Image fitting | |
| ### Given Image input, fit as many as possible x number of input on canvas | |
| """ | |
| if languageSelection == "English" else | |
| """ | |
| # 画像フィッティング | |
| ### 画像入力すると、キャンバス上の入力の数 x できるだけ多く収まります | |
| """), | |
| gr.Image.update(label="Image" if languageSelection == "English" else "画像入力", ), | |
| gr.Text.update(label="Result" if languageSelection == "English" else "結果"), | |
| gr.Button.update("Submit" if languageSelection == "English" else "送信"), | |
| gr.Plot.update(label="Plot" if languageSelection == "English" else "プロット"), | |
| ] | |
| if __name__ == "__main__": | |
| options = ["English", "日本語"] | |
| with gr.Blocks() as demo: | |
| with gr.Row(): | |
| with gr.Column(scale=8): | |
| pass | |
| with gr.Column(): | |
| languageSelection = gr.Dropdown(options, value="English", show_label=False) | |
| desc = gr.Markdown( | |
| """ | |
| # Image fitting | |
| ### Given Image input, fit as many as possible x number of input on canvas | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| image = gr.Image(image_mode="RGBA", label="Image") | |
| with gr.Row(): | |
| width = gr.Slider(value=1500, minimum=100, maximum=8000, label="Width") | |
| height = gr.Slider(value=1500, minimum=100, maximum=8000, label="Height") | |
| scale = gr.Slider(value=1.0, minimum=0, maximum=5, step=0.01, label="Input Scale") | |
| fit = gr.Button("Submit") | |
| with gr.Column(): | |
| plot_output = gr.Plot(label="Plot") | |
| text = gr.Text(label="Result") | |
| languageSelection.change(fn=change_language,inputs=[languageSelection] , outputs=[languageSelection, width, height, scale, desc, image, text, fit, plot_output]) | |
| fit.click(fn=process, inputs=[width, height, scale, image], outputs=[plot_output, text]) | |
| demo.launch() |