-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
150 lines (126 loc) · 5.9 KB
/
Copy pathapp.py
File metadata and controls
150 lines (126 loc) · 5.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
import cv2 as cv
import numpy as np
import skimage
from PIL import ImageTk, Image
from piece import pieces_from_masks
from utils import image_in_scale, masks_in_scale
from puzzle import paint_facets_by_type, paint_facets_distinct
from puzzle_piece_detector.inference_callable import Inference
class Application(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.weightsFilename: str = None
self.imageFilename: str = None
self.masks = None
self.pieces = None
self.imageWidth: int = 800
self.imageOnCanvas: int = None
self.button: Button = None
self.photoImage: PhotoImage = None
self.viewWindow: Canvas = None
self.fileMenu: Menu = None
self.menuBar: Menu = None
self.pack(fill=BOTH, expand=True)
self.create_menu()
self.create_widgets()
def create_menu(self):
self.menuBar = Menu(self)
self.fileMenu = Menu(self.menuBar, tearoff=0)
self.fileMenu.add_command(label="Image and Weights", command=self.pick_args)
self.fileMenu.add_separator()
self.fileMenu.add_command(label="Exit", command=self.quit)
self.menuBar.add_cascade(label="File", menu=self.fileMenu)
root.config(menu=self.menuBar)
def create_widgets(self):
self.button = Button(self, anchor="nw", text="Run segmentation", command=self.run_segmentation_and_update_image)
self.button.pack(side=TOP, fill=BOTH)
self.viewWindow = Canvas(self, bg="white")
self.viewWindow.pack(side=TOP, fill=BOTH, expand=True)
def pick_args(self):
self.pick_image_via_fd()
self.pick_weights_via_fd()
def pick_image_via_fd(self):
filename = filedialog.askopenfile(
title='Pick Puzzle scan image',
initialdir='./plots/',
filetypes=(
('Image file', '*.png'),
),
).name
self.imageFilename: str = filename
self.update_photo_image(PhotoImage(file=filename))
def pick_weights_via_fd(self):
filename = filedialog.askopenfile(
title='Pick weights',
initialdir='./weights/',
filetypes=(
('Weights file', '*.h5'),
),
).name
self.weightsFilename: str = filename
def update_photo_image(self, photo_image: PhotoImage):
if self.photoImage is None or photo_image.width() >= self.photoImage.width():
scale = int(photo_image.height() / int(self.winfo_height() * (2 / 3)))
self.photoImage = photo_image.subsample(scale, scale)
else:
scale = int(int(self.winfo_height() * (2 / 3)) / photo_image.height())
self.photoImage = photo_image.zoom(scale, scale)
self.imageOnCanvas: int = self.viewWindow.create_image(0, 0, anchor="nw", image=self.photoImage)
self.viewWindow.itemconfig(self.imageOnCanvas, image=self.photoImage)
def run_segmentation_and_update_image(self):
if self.imageFilename is None:
messagebox.showerror(title="No image picked",
message="Press on the menu top left and pick image with puzzle")
return
elif self.weightsFilename is None:
messagebox.showerror(title="No weights picked",
message="Press on the menu top left and pick weights file")
return
weights_path, image_path = self.weightsFilename, self.imageFilename
inference = Inference(weights_path)
self.masks = inference.infer_masks_and_blur(image_path)
self.update_photo_image(_photo_image(np.invert(np.sum(self.masks, -1, keepdims=True))))
# rebinding button to
self.button.config(command=self.run_piece_classification_with_facet_segmentation_and_update_image,
text="Run piece classification and facet segmentation")
def run_piece_classification_with_facet_segmentation_and_update_image(self):
print("Piece classification")
image_path = self.imageFilename
masks = self.masks
image = skimage.io.imread(image_path)
scale = 1
masks = masks_in_scale(masks, scale)
image = image_in_scale(image, scale)
pieces = pieces_from_masks(masks, image)
self.pieces = pieces
masks_with_facets = paint_facets_distinct(masks, pieces)
self.update_photoImage_using_np_array(masks_with_facets)
# rebinding button to
self.button.config(command=self.show_facets_by_classification,
text="Show facets by classification")
def show_facets_by_classification(self):
pieces = self.pieces
masks = self.masks
masks_with_facets = paint_facets_by_type(masks, pieces)
self.update_photoImage_using_np_array(masks_with_facets)
# TODO add next screens from here
def update_photoImage_using_np_array(self, masks_with_facets):
masks_with_facets = cv.resize(masks_with_facets, (self.photoImage.width(), self.photoImage.height()))
self.photoImage = ImageTk.PhotoImage(Image.fromarray(masks_with_facets))
self.imageOnCanvas: int = self.viewWindow.create_image(0, 0, anchor="nw", image=self.photoImage)
self.viewWindow.itemconfig(self.imageOnCanvas, image=self.photoImage)
def _photo_image(image: np.ndarray):
height, width, _ = image.shape
data = f'P5 {width} {height} 255 '.encode() + image.astype(np.uint8).tobytes()
return PhotoImage(width=width, height=height, data=data, format='PPM')
root = Tk()
root.title("Puzzle Solver")
app = Application(root)
root.attributes('-fullscreen', True)
root.bind("<F11>", lambda event: root.attributes("-fullscreen", not root.attributes("-fullscreen")))
root.bind("<Escape>", lambda event: root.attributes("-fullscreen", False))
root.iconbitmap('favicon.ico')
root.mainloop()