-
Notifications
You must be signed in to change notification settings - Fork 2
/
MainWindow.py
203 lines (156 loc) · 7.99 KB
/
MainWindow.py
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This file is part of verysharp,
copyright (c) 2016 Björn Sonnenschein.
verysharp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
verysharp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with verysharp. If not, see <http://www.gnu.org/licenses/>.
"""
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit, QFileDialog,
QHBoxLayout, QVBoxLayout, QMessageBox, QListWidget)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot, pyqtSignal
import configparser
import ImageStacker
# TODO: make input and output dialog folders persistent!
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# read the config file todo: if config does not exist, create it.
config_file_path = "./config.cfg"
self.config = configparser.ConfigParser()
self.config.read(config_file_path)
self.output_file_field = None
self.filepaths = None
self.stacker = None
self.progress_box = None
self.initUI()
def initUI(self):
self.button_process = QPushButton('Process', self)
self.button_process.clicked.connect(self.startProcessing)
button_select_files = QPushButton('Select Images', self)
button_select_files.clicked.connect(self.selectInputFiles)
button_select_output_file = QPushButton('Set Output', self)
button_select_output_file.clicked.connect(self.selectOutputFile)
button_help = QPushButton('Help', self)
button_help.clicked.connect(self.showHelpBox)
self.setWindowIcon(QIcon('./Icons/vsIcon.png'))
hbox_buttons = QHBoxLayout()
hbox_buttons.addWidget(button_select_files)
hbox_buttons.addWidget(self.button_process)
hbox_buttons.addStretch(1)
hbox_buttons.addWidget(button_help)
hbox_inputfiles = QHBoxLayout()
self.input_files_list = QListWidget(self)
hbox_inputfiles.addWidget(self.input_files_list)
hbox_outputfile = QHBoxLayout()
self.output_file_field = QLineEdit()
hbox_outputfile.addWidget(self.output_file_field)
hbox_outputfile.addWidget(button_select_output_file)
vbox = QVBoxLayout()
vbox.addLayout(hbox_inputfiles)
vbox.addLayout(hbox_outputfile)
vbox.addLayout(hbox_buttons)
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('VerySharp')
self.setLayout(vbox)
def selectInputFiles(self):
filter_images = ("Images (*jpg *jpeg *JPG *jpe *bmp *dib *jp2 *png *tiff *tif *ppm *pgm *pbm)")
filepaths = QFileDialog.getOpenFileNames(self,
"Select Images",
filter=filter_images)[0]
self.filepaths = []
for filepath in filepaths:
self.filepaths.append(str(filepath))
self.input_files_list.clear()
for input_path in filepaths:
self.input_files_list.addItem(input_path)
# self.filepaths = QFileDialog.getOpenFileName(self,
# 'Select Files',
# filter=filter_images)[0]
def selectOutputFile(self):
output_file = QFileDialog.getSaveFileName(self, 'Set Output with file extension')[0]
self.output_file_field.setText(output_file)
def startProcessing(self):
output_path = str(self.output_file_field.text())
if self.filepaths is not None and output_path != "":
# grey out the processing button
self.button_process.setEnabled(False)
self.progress_box = self.showProcessingBox()
self.stacker = ImageStacker.ImageStacker(self.filepaths, output_path)
self.stacker.signal_finished.connect(self.processing_finished)
self.stacker.signal_status_update.connect(self.progress_box.setInformativeText)
self.stacker.start()
self.progress_box.exec_()
else:
self.showMissingPathsDialog()
def showMissingPathsDialog(self):
QMessageBox.information(self, 'No files specifies',
"Please select the input and output files.")
def showProcessingBox(self):
message_box = QMessageBox()
message_box.setIcon(QMessageBox.Information)
message_box.setText("Processing Image")
message_box.setInformativeText("Starting Process")
message_box.setWindowTitle("Progress")
message_box.setStandardButtons(QMessageBox.Abort)
message_box.buttonClicked.connect(self.abortProcessing)
return message_box
def abortProcessing(self):
self.button_process.setEnabled(True)
self.stacker.abort()
def processing_finished(self):
self.button_process.setEnabled(True)
try:
self.progress_box.accept()
except:
pass
def showHelpBox(self):
help_text = ("This program combines a series of handheld-shot photos into an image with doubled resolution and "
+ "greatly reduced moire and noise. "
+ "In the following, a short guide on how to obtain optimal results is given:\n"
+ "\n"
+ "1. Shooting photos:\n"
+ "Capture a series of six images of your subject with identical exposure. Do NOT use a tripod because VerySharp calculates "
+ "the extended image information based on little shifts between the individual images. "
+ "Hold the camera as steadily as possible. For now, processing will only work properly for static subjects. Use RAW format.\n"
+ "\n"
+ "2. Preprocessing the Images\n"
+ "Use your favorite RAW converter and process the Images to taste. Use the identical settings for all images so that they look the same. "
+ "It is important to turn off sharpening. "
+ "Turn on lens corrections like vignetting, CA and distortion correction.\n"
+ "\n"
+ "3. Using verysharp\n"
+ "Start VerySharp and select the preprocessed images using the Select Images button. "
+ "Define the output file using the Set Output button. Important: Filename must include the extension "
+ "of the desired image format. For example, type output.jpg to save the result as jpeg. \n"
+ "Start processing using the Process button. The process will take some time.\n"
+ "\n"
+ "4. Have fun! \n"
+ "For further information visit https://wilecoyote2015.github.io/VerySharp/ \n"
+ "\n \n"
+ "copyright (c) 2016 Björn Sonnenschein. \n"
+ "\n"
+ "verysharp is free software: you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation, either version 3 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "verysharp is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with verysharp. If not, see <www.gnu.org/licenses/>.\n"
+ "\n")
QMessageBox.information(self, 'Help',
help_text)