Browse Source

added a simple gui

master
Holger Frey 6 years ago
parent
commit
7248403012
  1. 1
      mtor/__init__.py
  2. 54
      mtor/cli.py
  3. 93
      mtor/dataproc.py
  4. 186
      mtor/gui.py
  5. 4
      setup.py
  6. 316
      test.py

1
mtor/__init__.py

@ -13,6 +13,7 @@ warnings.filterwarnings("ignore")
__version__ = "0.1.0" __version__ = "0.1.0"
def run(): def run():
# pw = prescan_workflow("mtor-bilder", 50, 910, 300, 660) # pw = prescan_workflow("mtor-bilder", 50, 910, 300, 660)
pw = prescan_workflow("mtor-bilder", 50, 725 + 150, 300, 725) pw = prescan_workflow("mtor-bilder", 50, 725 + 150, 300, 725)

54
mtor/cli.py

@ -1,16 +1,54 @@
# -*- coding: utf-8 -*-
"""Console script for mtor.""" """Console script for mtor."""
import sys
import click import click
import sys
import warnings
from .workflows import (
prescan_workflow,
image_workflow,
data_workflow,
postprocessing_workflow,
)
warnings.filterwarnings("ignore")
@click.command() @click.command()
def main(args=None): @click.argument(
"""Console script for mtor.""" "folder",
click.echo("Replace this message by putting your code into " type=click.Path(
"mtor.cli.main") exists=True,
click.echo("See click documentation at http://click.pocoo.org/") file_okay=False,
dir_okay=True,
writable=True,
readable=True,
resolve_path=True,
allow_dash=False,
),
)
@click.argument("top", type=click.INT)
@click.argument("right", type=click.INT)
@click.argument("bottom", type=click.INT)
@click.argument("left", type=click.INT)
def main(folder, top, right, bottom, left):
"""Console script for analysing mtor images.
You need to provide the following information:
\b
FOLDER path to the directory containing tif images to analyse
TOP top edge position of the ROI in pixels
RIGHT right edge position of the ROI in pixels
BOTTOM bottom edge position of the ROI in pixels
LEFT left edge position of the ROI in pixels
"""
pw = prescan_workflow(folder, top, right, bottom, left)
iw = image_workflow(pw.parameters)
dw = data_workflow(iw.data, iw.parameters)
fw = postprocessing_workflow(dw.data, dw.parameters) # noqa: F841
return 0 return 0

93
mtor/dataproc.py

@ -23,6 +23,20 @@ from scipy.signal import savgol_filter
from .commons import ROI_STATISTIC_FUNCTIONS from .commons import ROI_STATISTIC_FUNCTIONS
IMAGE_NAMES = {
1: "1-histogram-of-guard-avarages-not-filtered.png",
2: "2-histogram-of-guard-avarages-filtered.png",
3: "3-histogram-of-guard-avarages-filtered-with-first-minima.png",
4: "4-image-selection-based-on-guard-values.png",
5: "5-selected-values-based-on-guard-values.png",
6: "6-boxplot-of-guarded-values.png",
7: "7-selected-images-outliers-removed.png",
8: "8-selected-images-outliers-removed-rolling-min-applied.png",
9: "9-selected-images-outliers-removed-rolling-min-savgol-filtered.png",
10: "11-finding-minima-and-maxima.png",
}
def peakplot_iloc(x, y, ix1, ix1_label="peaks", ix2=None, ix2_label="peaks"): def peakplot_iloc(x, y, ix1, ix1_label="peaks", ix2=None, ix2_label="peaks"):
""" """
Plots the original data with the peaks that were identified Plots the original data with the peaks that were identified
@ -112,9 +126,7 @@ def find_guard_threshold(data_frame, parameters):
pyplot.title("Histogram of Guard Avarages (not filtered)") pyplot.title("Histogram of Guard Avarages (not filtered)")
pyplot.xlabel("Average Intensity [au]") pyplot.xlabel("Average Intensity [au]")
pyplot.ylabel("Number of Observations [1]") pyplot.ylabel("Number of Observations [1]")
path = ( path = parameters.data_dir / IMAGE_NAMES[1]
parameters.data_dir / "1-histogram-of-guard-avarages-not-filtered.png"
)
pyplot.savefig(str(path)) pyplot.savefig(str(path))
guard_counts_filtered = savgol_filter( guard_counts_filtered = savgol_filter(
@ -128,7 +140,7 @@ def find_guard_threshold(data_frame, parameters):
pyplot.title("Histogram of Guard Avarages (Savitzky-Golay filter)") pyplot.title("Histogram of Guard Avarages (Savitzky-Golay filter)")
pyplot.xlabel("Average Intensity [au]") pyplot.xlabel("Average Intensity [au]")
pyplot.ylabel("Number of Observations [1]") pyplot.ylabel("Number of Observations [1]")
path = parameters.data_dir / "2-histogram-of-guard-avarages-filtered.png" path = parameters.data_dir / IMAGE_NAMES[2]
pyplot.savefig(str(path)) pyplot.savefig(str(path))
# Finding the first minima after the first peak # Finding the first minima after the first peak
@ -165,10 +177,7 @@ def find_guard_threshold(data_frame, parameters):
) )
pyplot.xlabel("Average Intensity [au]") pyplot.xlabel("Average Intensity [au]")
pyplot.ylabel("Number of Observations [1]") pyplot.ylabel("Number of Observations [1]")
path = ( path = parameters.data_dir / IMAGE_NAMES[3]
parameters.data_dir
/ "3-histogram-of-guard-avarages-filtered-with-first-minima.png"
)
pyplot.savefig(str(path)) pyplot.savefig(str(path))
@ -201,7 +210,7 @@ def check_guards(data_frame, parameters):
pyplot.title("Selection based on guard values") pyplot.title("Selection based on guard values")
pyplot.ylabel("Average Intensity [au]") pyplot.ylabel("Average Intensity [au]")
pyplot.ylabel("Frame Number [1]") pyplot.ylabel("Frame Number [1]")
path = parameters.data_dir / "4-image-selection-based-on-guard-values.png" path = parameters.data_dir / IMAGE_NAMES[4]
pyplot.savefig(str(path)) pyplot.savefig(str(path))
parameters.charts_y_limit = ax.get_ylim() parameters.charts_y_limit = ax.get_ylim()
@ -220,7 +229,7 @@ def check_guards(data_frame, parameters):
pyplot.xlabel("Frame Number [1]") pyplot.xlabel("Frame Number [1]")
pyplot.ylabel("Average Intensity [au]") pyplot.ylabel("Average Intensity [au]")
ax.set_ylim(parameters.charts_y_limit) ax.set_ylim(parameters.charts_y_limit)
path = parameters.data_dir / "5-selected-values-based-on-guard-values.png" path = parameters.data_dir / IMAGE_NAMES[5]
pyplot.savefig(str(path)) pyplot.savefig(str(path))
return data_frame return data_frame
@ -235,7 +244,7 @@ def find_outliers(data_frame, parameters):
seaborn.boxplot(data=guarded_df, x=parameters.roi_column) seaborn.boxplot(data=guarded_df, x=parameters.roi_column)
pyplot.title(f"Boxblot of guarded values") pyplot.title(f"Boxblot of guarded values")
pyplot.xlabel("Average Intensity [au]") pyplot.xlabel("Average Intensity [au]")
path = parameters.data_dir / "6-boxplot-of-guarded-values.png" path = parameters.data_dir / IMAGE_NAMES[6]
pyplot.savefig(str(path)) pyplot.savefig(str(path))
lower_quartil = guarded_df[parameters.roi_column].quantile(0.25) lower_quartil = guarded_df[parameters.roi_column].quantile(0.25)
@ -264,7 +273,7 @@ def select_on_guards_and_outliers(data_frame, parameters):
pyplot.xlabel("Frame Number [1]") pyplot.xlabel("Frame Number [1]")
pyplot.ylabel("Average Intensity [au]") pyplot.ylabel("Average Intensity [au]")
ax.set_ylim(parameters.charts_y_limit) ax.set_ylim(parameters.charts_y_limit)
path = parameters.data_dir / "7-selected-images-outliers-removed.png" path = parameters.data_dir / IMAGE_NAMES[7]
pyplot.savefig(str(path)) pyplot.savefig(str(path))
return selected_df return selected_df
@ -291,10 +300,7 @@ def smooth_rolling_min(selected_df, parameters):
pyplot.xlabel("Frame Number [1]") pyplot.xlabel("Frame Number [1]")
pyplot.ylabel("Average Intensity [au]") pyplot.ylabel("Average Intensity [au]")
ax.set_ylim(parameters.charts_y_limit) ax.set_ylim(parameters.charts_y_limit)
path = ( path = parameters.data_dir / IMAGE_NAMES[8]
parameters.data_dir
/ "8-selected-images-outliers-removed-rolling-min-applied.png"
)
pyplot.savefig(str(path)) pyplot.savefig(str(path))
return selected_df return selected_df
@ -320,10 +326,7 @@ def smooth_savgol_filter(selected_df, parameters):
) )
pyplot.xlabel("Frame Number [1]") pyplot.xlabel("Frame Number [1]")
pyplot.ylabel("Average Intensity [au]") pyplot.ylabel("Average Intensity [au]")
path = ( path = parameters.data_dir / IMAGE_NAMES[9]
parameters.data_dir
/ "9-selected-images-outliers-removed-rolling-min-savgol-filtered.png"
)
pyplot.savefig(str(path)) pyplot.savefig(str(path))
return selected_df return selected_df
@ -337,20 +340,6 @@ def find_extremas(selected_df, parameters):
min_dist=parameters.peak_min_distance, min_dist=parameters.peak_min_distance,
) )
maximas = selected_df.iloc[max_indexes].copy() maximas = selected_df.iloc[max_indexes].copy()
pyplot.clf()
peakplot_iloc(
selected_df["frame"],
selected_df[f"{parameters.roi_name}.savgol"],
max_indexes,
"maxima",
)
pyplot.title(f"Finding Maximas")
pyplot.xlabel("Frame Number [1]")
pyplot.ylabel("Average Intensity [au]")
path = parameters.data_dir / "10-finding-maximas.png"
pyplot.savefig(str(path))
inverted_series = ( inverted_series = (
max(selected_df[f"{parameters.roi_name}.savgol"]) max(selected_df[f"{parameters.roi_name}.savgol"])
- selected_df[f"{parameters.roi_name}.savgol"] - selected_df[f"{parameters.roi_name}.savgol"]
@ -372,7 +361,7 @@ def find_extremas(selected_df, parameters):
pyplot.title(f"Finding Minimas") pyplot.title(f"Finding Minimas")
pyplot.xlabel("Frame Number [1]") pyplot.xlabel("Frame Number [1]")
pyplot.ylabel("Average Intensity [au]") pyplot.ylabel("Average Intensity [au]")
path = parameters.data_dir / "11-finding-minimas.png" path = parameters.data_dir / IMAGE_NAMES[10]
pyplot.savefig(str(path)) pyplot.savefig(str(path))
maximas["is_maxima"] = True maximas["is_maxima"] = True
@ -423,12 +412,14 @@ def create_report(data_frame, selected_df, extremas_df, parameters):
num_selected = len(selected_df) num_selected = len(selected_df)
num_discarded = num_images - num_selected num_discarded = num_images - num_selected
def text_and_graph(text, name): def text_and_graph(image_nr, text):
flowable = KeepTogether( flowable = KeepTogether(
[ [
Paragraph(text, style_text), Paragraph(text, style_text),
Image( Image(
str(data_dir / name), width=img_width, height=img_height str(data_dir / IMAGE_NAMES[image_nr]),
width=img_width,
height=img_height,
), ),
Spacer(1, 7 * mm), Spacer(1, 7 * mm),
] ]
@ -440,80 +431,72 @@ def create_report(data_frame, selected_df, extremas_df, parameters):
Spacer(1, 10 * mm), Spacer(1, 10 * mm),
Paragraph("Estimating Guard Threshold", style_section), Paragraph("Estimating Guard Threshold", style_section),
text_and_graph( text_and_graph(
1,
( (
"In a first step, the histogram of the combined left and " "In a first step, the histogram of the combined left and "
"right guard values is calculated." "right guard values is calculated."
), ),
"1-histogram-of-guard-avarages-not-filtered.png",
), ),
text_and_graph( text_and_graph(
2,
( (
"A Savitzky-Golay filter is applied to the histogram to " "A Savitzky-Golay filter is applied to the histogram to "
"smooth the curve." "smooth the curve."
), ),
"2-histogram-of-guard-avarages-filtered.png",
), ),
text_and_graph( text_and_graph(
3,
( (
"The first minima after the first peak is used as the guard " "The first minima after the first peak is used as the guard "
f"threshold value: {int(parameters.guard_max_value)} au" f"threshold value: {int(parameters.guard_max_value)} au"
), ),
"3-histogram-of-guard-avarages-filtered-with-first-minima.png",
), ),
text_and_graph( text_and_graph(
4,
( (
"The images with one of the guard values above the threshold " "The images with one of the guard values above the threshold "
"are discarded." "are discarded."
), ),
"4-image-selection-based-on-guard-values.png",
), ),
Image( Image(
str(data_dir / "5-selected-values-based-on-guard-values.png"), str(data_dir / IMAGE_NAMES[5]), width=img_width, height=img_height
width=img_width,
height=img_height,
), ),
PageBreak(), PageBreak(),
Paragraph("Removing Outliers", style_section), Paragraph("Removing Outliers", style_section),
text_and_graph(6, "From the remaining values, outliers are removed."),
text_and_graph( text_and_graph(
"From the remaining values, outliers are removed.", 7,
"6-boxplot-of-guarded-values.png",
),
text_and_graph(
( (
f"From {num_images} images {num_discarded} images were " f"From {num_images} images {num_discarded} images were "
f"discarded, leaving {num_selected} selected. The finally " f"discarded, leaving {num_selected} selected. The finally "
"selected values are listed in the excel sheet 'selection' " "selected values are listed in the excel sheet 'selection' "
"in the data file." "in the data file."
), ),
"7-selected-images-outliers-removed.png",
), ),
PageBreak(), PageBreak(),
Paragraph( Paragraph(
"Experimental: Applying a rolling min calculation", style_section "Experimental: Applying a rolling min calculation", style_section
), ),
text_and_graph( text_and_graph(
8,
( (
"Due to the nature of the experiment, unusable images tend " "Due to the nature of the experiment, unusable images tend "
"to have a higher value as the desiered ones. Therfore a " "to have a higher value as the desiered ones. Therfore a "
"rolling min filter is applied" "rolling min filter is applied"
), ),
"8-selected-images-outliers-removed-rolling-min-applied.png",
), ),
Paragraph("Experimental: Finding Maxima and Minima", style_section), Paragraph("Experimental: Finding Maxima and Minima", style_section),
text_and_graph( text_and_graph(
9,
"To smooth the resulting curve, a Savitzky-Golay filter is used.", "To smooth the resulting curve, a Savitzky-Golay filter is used.",
(
"9-selected-images-outliers-"
"removed-rolling-min-savgol-filtered.png"
),
), ),
text_and_graph( text_and_graph(
10,
( (
"The most interesting data points should be the maxima and " "The most interesting data points should be the maxima and "
"minima of this curve. These are listed in the sheet " "minima of this curve. These are listed in the sheet "
"'extremas' in the data file" "'extremas' in the data file"
), ),
"11-finding-minimas.png",
), ),
] ]
doc.build(story) doc.build(story)

186
mtor/gui.py

@ -0,0 +1,186 @@
from pathlib import Path
home = Path.home()
import sys
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QPushButton,
QDesktopWidget,
QHBoxLayout,
QVBoxLayout,
QWidget,
QLabel,
QLineEdit,
QGridLayout,
QFileDialog,
)
from PyQt5.QtGui import QIcon, QIntValidator
from .workflows import (
prescan_workflow,
image_workflow,
data_workflow,
cached_data_workflow,
postprocessing_workflow,
)
class MtorImageAnalysis(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# analysis parameters
self.analysis_parameters = None
# directory browser
self.dir_label = QLabel("Image Folder")
self.dir_btn = QPushButton("Browse")
self.dir_btn.clicked.connect(self.get_tif_dir)
self.dir_selected = QLabel()
# roi input fields
self.roi_top_label = QLabel("Top edge of ROI")
self.roi_top_input = QLineEdit()
self.roi_top_input.setValidator(QIntValidator())
self.roi_top_input.textChanged.connect(self.check_button_state)
self.roi_left_label = QLabel("Left edge of ROI")
self.roi_left_input = QLineEdit()
self.roi_left_input.setValidator(QIntValidator())
self.roi_left_input.textChanged.connect(self.check_button_state)
self.roi_right_label = QLabel("Right edge of ROI")
self.roi_right_input = QLineEdit()
self.roi_right_input.setValidator(QIntValidator())
self.roi_right_input.textChanged.connect(self.check_button_state)
self.roi_bottom_label = QLabel("Bottom edge of ROI")
self.roi_bottom_input = QLineEdit()
self.roi_bottom_input.setValidator(QIntValidator())
self.roi_bottom_input.textChanged.connect(self.check_button_state)
# action buttons
self.btn_run = QPushButton("Run", self)
self.btn_run.setEnabled(False)
self.btn_run.clicked.connect(self.run_analysis)
self.btn_exit = QPushButton("Exit", self)
self.btn_exit.clicked.connect(QApplication.instance().quit)
# Layout
grid = QGridLayout()
grid.setSpacing(10)
grid.addWidget(self.dir_label, 1, 0)
grid.addWidget(self.dir_btn, 1, 1)
grid.addWidget(self.dir_selected, 2, 0, 1, 2)
grid.addWidget(QLabel(), 3, 0, 1, 2)
grid.addWidget(self.roi_top_label, 4, 0)
grid.addWidget(self.roi_top_input, 4, 1)
grid.addWidget(self.roi_right_label, 5, 0)
grid.addWidget(self.roi_right_input, 5, 1)
grid.addWidget(self.roi_bottom_label, 6, 0)
grid.addWidget(self.roi_bottom_input, 6, 1)
grid.addWidget(self.roi_left_label, 7, 0)
grid.addWidget(self.roi_left_input, 7, 1)
grid.addWidget(QLabel(), 8, 0, 1, 2)
grid.addWidget(self.btn_exit, 9, 0)
grid.addWidget(self.btn_run, 9, 1)
self.setLayout(grid)
#self.resize(350, 300)
self.center_window_on_desktop()
self.setWindowTitle("mTor Image Analysis")
self.setWindowIcon(QIcon("web.png"))
# helpers
self.dir_selected.setText("/Users/holgerfrey/Developer/mtor/mtor-bilder")
self.roi_top_input.setText("50")
self.roi_right_input.setText("875")
self.roi_bottom_input.setText("300")
self.roi_left_input.setText("725")
self.show()
def center_window_on_desktop(self):
cp = QDesktopWidget().availableGeometry().center()
fg = self.frameGeometry()
fg.moveCenter(cp)
self.move(fg.topLeft())
def get_tif_dir(self):
dlg = QFileDialog(directory=str(home))
dlg.setFileMode(QFileDialog.Directory)
if dlg.exec_():
filenames = dlg.selectedFiles()
folder = Path(filenames[0])
items = (i for i in folder.iterdir() if not i.stem.startswith("."))
tifs = [i for i in items if i.suffix == ".tif"]
if len(tifs) == 0:
self.dir_selected.setText("")
self.check_button_state()
else:
self.dir_selected.setText(filenames[0])
self.check_button_state()
def check_button_state(self):
values = self.get_values()
self.btn_run.setEnabled(all(values))
def get_values(self):
fields = [
(self.dir_selected, str),
(self.roi_top_input, int),
(self.roi_right_input, int),
(self.roi_bottom_input, int),
(self.roi_left_input, int),
]
result = []
for field, func in fields:
raw_data = field.text().strip()
if raw_data:
if func is int:
# in qt5, a point as 1000 separator is allowed
raw_data = raw_data.replace(".", "")
result.append(func(raw_data))
else:
result.append(None)
return tuple(result)
def run_analysis(self):
parameters = self.get_values()
if all(parameters):
self.analysis_parameters = parameters
self.hide()
QApplication.instance().quit()
def run_gui():
app = QApplication(sys.argv)
mia = MtorImageAnalysis()
app.exec_()
if mia.analysis_parameters is not None:
analysis_parameters = tuple( (p for p in mia.analysis_parameters) )
pw = prescan_workflow(*analysis_parameters)
iw = image_workflow(pw.parameters)
dw = data_workflow(iw.data, iw.parameters)
fw = postprocessing_workflow(dw.data, dw.parameters) # noqa: F841
sys.exit()

4
setup.py

@ -8,9 +8,6 @@ from setuptools import setup, find_packages
with open("README.md") as readme_file: with open("README.md") as readme_file:
readme = readme_file.read() readme = readme_file.read()
with open("HISTORY.rst") as history_file:
history = history_file.read()
requirements = [ requirements = [
"Click>=6.0", "Click>=6.0",
"pandas>=0.24", "pandas>=0.24",
@ -25,6 +22,7 @@ requirements = [
"xlwt>=1.3", "xlwt>=1.3",
"xlsxwriter>=1.1", "xlsxwriter>=1.1",
"reportlab>=3.5", "reportlab>=3.5",
"PyQt5>=5.12"
] ]
setup_requirements = [ ] setup_requirements = [ ]

316
test.py

@ -1,316 +1,4 @@
from pathlib import Path from mtor.gui import run_gui
from PIL import Image, ImageOps
from tqdm import tqdm
import numpy
import skimage
import warnings
FIRE_LUT = [ run_gui()
0, 0, 0,
0, 0, 7,
0, 0, 15,
0, 0, 22,
0, 0, 30,
0, 0, 38,
0, 0, 45,
0, 0, 53,
0, 0, 61,
0, 0, 65,
0, 0, 69,
0, 0, 74,
0, 0, 78,
0, 0, 82,
0, 0, 87,
0, 0, 91,
1, 0, 96,
4, 0, 100,
7, 0, 104,
10, 0, 108,
13, 0, 113,
16, 0, 117,
19, 0, 121,
22, 0, 125,
25, 0, 130,
28, 0, 134,
31, 0, 138,
34, 0, 143,
37, 0, 147,
40, 0, 151,
43, 0, 156,
46, 0, 160,
49, 0, 165,
52, 0, 168,
55, 0, 171,
58, 0, 175,
61, 0, 178,
64, 0, 181,
67, 0, 185,
70, 0, 188,
73, 0, 192,
76, 0, 195,
79, 0, 199,
82, 0, 202,
85, 0, 206,
88, 0, 209,
91, 0, 213,
94, 0, 216,
98, 0, 220,
101, 0, 220,
104, 0, 221,
107, 0, 222,
110, 0, 223,
113, 0, 224,
116, 0, 225,
119, 0, 226,
122, 0, 227,
125, 0, 224,
128, 0, 222,
131, 0, 220,
134, 0, 218,
137, 0, 216,
140, 0, 214,
143, 0, 212,
146, 0, 210,
148, 0, 206,
150, 0, 202,
152, 0, 199,
154, 0, 195,
156, 0, 191,
158, 0, 188,
160, 0, 184,
162, 0, 181,
163, 0, 177,
164, 0, 173,
166, 0, 169,
167, 0, 166,
168, 0, 162,
170, 0, 158,
171, 0, 154,
173, 0, 151,
174, 0, 147,
175, 0, 143,
177, 0, 140,
178, 0, 136,
179, 0, 132,
181, 0, 129,
182, 0, 125,
184, 0, 122,
185, 0, 118,
186, 0, 114,
188, 0, 111,
189, 0, 107,
190, 0, 103,
192, 0, 100,
193, 0, 96,
195, 0, 93,
196, 1, 89,
198, 3, 85,
199, 5, 82,
201, 7, 78,
202, 8, 74,
204, 10, 71,
205, 12, 67,
207, 14, 64,
208, 16, 60,
209, 19, 56,
210, 21, 53,
212, 24, 49,
213, 27, 45,
214, 29, 42,
215, 32, 38,
217, 35, 35,
218, 37, 31,
220, 40, 27,
221, 43, 23,
223, 46, 20,
224, 48, 16,
226, 51, 12,
227, 54, 8,
229, 57, 5,
230, 59, 4,
231, 62, 3,
233, 65, 3,
234, 68, 2,
235, 70, 1,
237, 73, 1,
238, 76, 0,
240, 79, 0,
241, 81, 0,
243, 84, 0,
244, 87, 0,
246, 90, 0,
247, 92, 0,
249, 95, 0,
250, 98, 0,
252, 101, 0,
252, 103, 0,
252, 105, 0,
253, 107, 0,
253, 109, 0,
253, 111, 0,
254, 113, 0,
254, 115, 0,
255, 117, 0,
255, 119, 0,
255, 121, 0,
255, 123, 0,
255, 125, 0,
255, 127, 0,
255, 129, 0,
255, 131, 0,
255, 133, 0,
255, 134, 0,
255, 136, 0,
255, 138, 0,
255, 140, 0,
255, 141, 0,
255, 143, 0,
255, 145, 0,
255, 147, 0,
255, 148, 0,
255, 150, 0,
255, 152, 0,
255, 154, 0,
255, 155, 0,
255, 157, 0,
255, 159, 0,
255, 161, 0,
255, 162, 0,
255, 164, 0,
255, 166, 0,
255, 168, 0,
255, 169, 0,
255, 171, 0,
255, 173, 0,
255, 175, 0,
255, 176, 0,
255, 178, 0,
255, 180, 0,
255, 182, 0,
255, 184, 0,
255, 186, 0,
255, 188, 0,
255, 190, 0,
255, 191, 0,
255, 193, 0,
255, 195, 0,
255, 197, 0,
255, 199, 0,
255, 201, 0,
255, 203, 0,
255, 205, 0,
255, 206, 0,
255, 208, 0,
255, 210, 0,
255, 212, 0,
255, 213, 0,
255, 215, 0,
255, 217, 0,
255, 219, 0,
255, 220, 0,
255, 222, 0,
255, 224, 0,
255, 226, 0,
255, 228, 0,
255, 230, 0,
255, 232, 0,
255, 234, 0,
255, 235, 4,
255, 237, 8,
255, 239, 13,
255, 241, 17,
255, 242, 21,
255, 244, 26,
255, 246, 30,
255, 248, 35,
255, 248, 42,
255, 249, 50,
255, 250, 58,
255, 251, 66,
255, 252, 74,
255, 253, 82,
255, 254, 90,
255, 255, 98,
255, 255, 105,
255, 255, 113,
255, 255, 121,
255, 255, 129,
255, 255, 136,
255, 255, 144,
255, 255, 152,
255, 255, 160,
255, 255, 167,
255, 255, 175,
255, 255, 183,
255, 255, 191,
255, 255, 199,
255, 255, 207,
255, 255, 215,
255, 255, 223,
255, 255, 227,
255, 255, 231,
255, 255, 235,
255, 255, 239,
255, 255, 243,
255, 255, 247,
255, 255, 251,
255, 255, 255,
255, 255, 255,
255, 255, 255,
255, 255, 255,
255, 255, 255,
255, 255, 255,
255, 255, 255,
255, 255, 255,
]
tif_dir = Path("original_tifs")
png_dir = Path("auto_pngs")
for item in png_dir.iterdir():
item.unlink()
visible_items = (i for i in tif_dir.iterdir() if not i.stem.startswith("."))
tifs = [i for i in visible_items if i.suffix == ".tif"]
lowest = 2**16
lowest = 309
highest = 0
highest = 23922//4
print("1/3: scanning tifs for common autocontrast values")
for path in tqdm(tifs):
break
with path.open("rb") as filehandle:
image = Image.open(filehandle)
mi, ma = image.getextrema()
lowest = min(lowest, mi)
highest = max(highest, ma)
print("lowest intensity found: ", lowest)
print("highest intensity found: ", highest)
scaling_factor = highest / 255
print("2/3: adjusting contrast, converting to png")
for path in tqdm(tifs):
break
with path.open("rb") as filehandle:
image = Image.open(filehandle)
image_array = numpy.array(image, dtype=numpy.int32)
converted = Image.fromarray((image_array - lowest) // scaling_factor)
adjusted = converted.convert(mode="L").convert(mode="P")
adjusted.putpalette(FIRE_LUT)
png_path = png_dir / (path.stem + ".png")
with png_path.open("wb") as outhandle:
adjusted.save(outhandle)
cut = image_array[50:300,660:910]
import mtor
print(mtor.analyse_cut(cut))
#x = 660, 50,
#w, h = 250, 250

Loading…
Cancel
Save