-
Notifications
You must be signed in to change notification settings - Fork 0
/
analyze_scan.py
executable file
·93 lines (75 loc) · 3.39 KB
/
analyze_scan.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
#!/usr/bin/env python
"""Reads an image and lets the user click on positions of that image. The
resulting pixel cooredinates are returned to the calling process on stdout, in
JSON format. It is a list of four two-tuples, which represent the (x, y)
coordinates of the four corners in arbitrary order.
The command-line parameters are:
- x coordinate of the ROI centre
- y coordinate of the ROI centre
- scaling
- path to image
- number of points to click
The image can be any file format that ImageMagick can handle.
"""
import subprocess, json, sys, os, contextlib
os.environ["KIVY_NO_FILELOG"] = "1"
os.environ["KIVY_NO_CONSOLELOG"] = "1"
os.environ["KIVY_NO_CONFIG"] = "1"
with contextlib.redirect_stdout(None):
from kivy.app import App
from kivy.uix.image import Image
class Result(Exception):
def __init__(self, points, *args, **kwargs):
super().__init__(*args, **kwargs)
self.points = points
class ImageWindow(Image):
def __init__(self, x, y, scaling, source, number_of_points, *args, **kwargs):
raw_width, raw_height = subprocess.check_output(["identify", source]).decode().split()[2].split("x")
raw_width, raw_height = int(raw_width), int(raw_height)
self.crop_width = min(raw_width, 1100 / scaling)
self.crop_height = min(raw_height, 900 / scaling)
self.x0 = x - self.crop_width / 2
self.y0 = y - self.crop_height / 2
if self.x0 < 0:
self.crop_width += self.x0
self.x0 = 0
if self.x0 + self.crop_width > raw_width:
self.crop_width = raw_width - self.x0
if self.y0 < 0:
self.crop_height += self.y0
self.y0 = 0
if self.y0 + self.crop_height > raw_height:
self.crop_height = raw_height - self.y0
subprocess.check_call(["convert", "-extract", "{}x{}+{}+{}".format(self.crop_width, self.crop_height,
self.x0, self.y0), source, "+repage",
"-resize", "{}%".format(scaling * 100), "/tmp/analyze_scan.ppm"])
kwargs["source"] = "/tmp/analyze_scan.ppm"
super().__init__(*args, **kwargs)
self.number_of_points = number_of_points
self.points = []
def on_touch_down(self, touch):
image_width, image_height = self.norm_image_size
offset_x = (self.width - image_width) / 2
offset_y = (self.height - image_height) / 2
x = (touch.x - offset_x) * self.crop_width / image_width
y = self.crop_height - (touch.y - offset_y) * self.crop_height / image_height
self.points.append((int(x + self.x0), int(y + self.y0)))
if len(self.points) == self.number_of_points:
raise Result(self.points)
class AnalyzeApp(App):
def __init__(self, x, y, scaling, source, number_of_points, *args, **kwargs):
self.x = x
self.y = y
self.scaling = scaling
self.source = source
self.number_of_points = number_of_points
super().__init__(*args, **kwargs)
def build(self):
return ImageWindow(self.x, self.y, self.scaling, self.source, self.number_of_points)
def run(self):
try:
super().run()
except Result as result:
return result.points
result = AnalyzeApp(int(sys.argv[1]), int(sys.argv[2]), float(sys.argv[3]), sys.argv[4], int(sys.argv[5])).run()
json.dump(result, sys.stdout)