broyang commited on
Commit
feca544
·
1 Parent(s): 56b0b58

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -0
app.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import math
4
+ from PIL import Image, ImageDraw, ImageFont, ImageOps
5
+ Image.MAX_IMAGE_PIXELS = None
6
+ import gradio as gr
7
+
8
+ def get_exif(image_path):
9
+ try:
10
+ with Image.open(image_path) as img:
11
+ exif_data = img.getexif()
12
+ # print(exif_data)
13
+ if not exif_data:
14
+ return None, None, None
15
+ if "Local Coordinates (m)" in exif_data[34737]:
16
+ return None, None, None
17
+ pixel_scale = exif_data[33550] # Tag ID for PixelScale
18
+ model_tie_point = exif_data[33922] # Tag ID for ModelTiePoint
19
+ pixel_scale_x, pixel_scale_y, _ = pixel_scale
20
+ _, _, _, _, latitude, _ = model_tie_point
21
+ return pixel_scale_x, pixel_scale_y, latitude
22
+ except Exception as e:
23
+ print(f"Error extracting metadata: {e}")
24
+ return None, None, None
25
+
26
+ def pixel_size_in_feet(x_scale_degrees, latitude):
27
+ meters_per_degree_lat = 111320 # Average meters per degree of latitude
28
+ meters_per_degree_lon = meters_per_degree_lat * math.cos(math.radians(latitude))
29
+ pixel_size_x_feet = x_scale_degrees * meters_per_degree_lon * 3.28084
30
+ return pixel_size_x_feet
31
+
32
+ def feet_per_inch(dpi, pixel_size_x_feet):
33
+ # Calculate the number of pixels in 1 inch
34
+ pixels_per_inch = dpi
35
+ # Calculate the number of feet in 1 inch
36
+ feet_per_inch = pixels_per_inch * pixel_size_x_feet
37
+ return feet_per_inch
38
+
39
+ def nearest_number(n):
40
+ numbers = [1, 5, 10, 20, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
41
+ return min(numbers, key=lambda x: abs(x - n))
42
+
43
+ def calculate_dpi(x_scale_degrees, latitude):
44
+ pixel_size_x_feet = pixel_size_in_feet(x_scale_degrees, latitude)
45
+ pixel_size_x_inches = pixel_size_x_feet / 12
46
+ dpi = 1 / pixel_size_x_inches
47
+
48
+ return dpi
49
+
50
+ def add_white_space(img):
51
+ _, height_px = img.size
52
+ bottom_space = int(height_px * 0.2) # Calculate the size of the bottom space
53
+ top_space = int(height_px * 0.1) # Calculate the size of the top space
54
+ new_height_px = int(height_px + bottom_space + top_space)
55
+ img = ImageOps.expand(img, border=(0, top_space, 0, bottom_space), fill='white')
56
+ return img, new_height_px
57
+
58
+ def add_white_space_right(img):
59
+ width_px, height_px = img.size
60
+ right_space = int(width_px * 0.3) # Calculate the size of the right space
61
+ left_space = int(width_px * 0.1) # Calculate the size of the left space
62
+ new_width_px = int(width_px + right_space)
63
+ img = ImageOps.expand(img, border=(0, 0, right_space, 0), fill='white')
64
+ return img
65
+
66
+ def draw_scale_bar(right_img, exif_data, compass, line_img, paste_x_position, paste_y_position):
67
+ pixel_scale_x = exif_data[0]
68
+ pixel_scale_y = exif_data[1]
69
+ latitude = exif_data[2]
70
+ if pixel_scale_x is None or pixel_scale_y is None or latitude is None:
71
+ return
72
+ # Calculate pixel size in feet
73
+ pixel_size_x = pixel_size_in_feet(pixel_scale_x, latitude)
74
+ image_width_feet = round(line_img.width * pixel_size_x)
75
+ scale_max = nearest_number(image_width_feet / 5)
76
+ # Calculate scale bar dimensions
77
+ scale_bar_width_px = int(line_img.width * (scale_max / image_width_feet))
78
+ scale_bar_height_px = int(scale_bar_width_px * 0.08)
79
+ # x_position = int(right_img.width * 0.90 - scale_bar_width_px) # Adjusted for 5% from the right
80
+ x_position = paste_x_position
81
+ y_position = int(right_img.height - (right_img.height - paste_y_position - scale_bar_height_px) * 2) # Adjusted for new height
82
+ font_size = int(scale_bar_width_px * 0.1)
83
+ # Draw scale bar
84
+ draw = ImageDraw.Draw(right_img)
85
+ try:
86
+ font = ImageFont.truetype("Arial Unicode.ttf", font_size) #DejaVuSans.ttf, Arial.ttf
87
+ print("loaded font")
88
+ except IOError:
89
+ font = ImageFont.load_default()
90
+ print("default :()")
91
+ section_width = scale_bar_width_px / 4
92
+ section_x_position = x_position - 1 * section_width #base 0 incremental position
93
+ text_position = (section_x_position + section_width - font_size / 4, y_position - font_size - 20)
94
+ draw.text(text_position, "0", fill="black", font=font)
95
+ for i in range(4): #other incremental positions
96
+ section_x_position = x_position + i * section_width
97
+ fill_color = "black" if i % 2 == 0 else "white"
98
+ draw.rectangle([section_x_position, y_position, section_x_position + section_width, y_position + scale_bar_height_px], fill=fill_color)
99
+ text = str(round(scale_max / 4 * (i + 1), 2))
100
+ if text.endswith('.0'):
101
+ text = text.rstrip('0').rstrip('.')
102
+ if i == 3:
103
+ text += " feet"
104
+ text_position = (section_x_position + section_width - font_size / 4, y_position - font_size - 20)
105
+ draw.text(text_position, text, fill="black", font=font)
106
+
107
+ # Draw outline around scale bar
108
+ outline_width = 3
109
+ draw.line([(x_position, y_position), (x_position + scale_bar_width_px, y_position)], fill="black", width=outline_width)
110
+ draw.line([(x_position, y_position), (x_position, y_position + scale_bar_height_px)], fill="black", width=outline_width)
111
+ draw.line([(x_position + scale_bar_width_px, y_position), (x_position + scale_bar_width_px, y_position + scale_bar_height_px)], fill="black", width=outline_width)
112
+ draw.line([(x_position, y_position + scale_bar_height_px), (x_position + scale_bar_width_px, y_position + scale_bar_height_px)], fill="black", width=outline_width)
113
+
114
+ #feet per inch
115
+ try:
116
+ font = ImageFont.truetype("Arial Unicode.ttf", int(font_size * 1.3)) #DejaVuSans.ttf, Arial.ttf
117
+ except IOError:
118
+ font = ImageFont.load_default()
119
+ dpi = calculate_dpi(pixel_scale_x, latitude)
120
+ dpi = 96
121
+ fpi = round(feet_per_inch(dpi, pixel_size_x), 2)
122
+ feet_per_inch_text = '1" = ' + str(fpi) + ' feet'
123
+ paste_y_position = int(right_img.height - (right_img.height - paste_y_position - scale_bar_height_px) * 3)
124
+ text_position = (x_position, paste_y_position)
125
+ # text_position = (x_position, y_position - font_size - 200)
126
+ draw.text(text_position, feet_per_inch_text, fill='black', font=font)
127
+
128
+ # # Add in a small compass
129
+ compass = compass.convert("RGBA")
130
+ new_compass_width = int(right_img.width * 0.05)
131
+ compass_ratio = new_compass_width / compass.width
132
+ new_compass_height = int(compass.height * compass_ratio)
133
+ compass = compass.resize((new_compass_width, new_compass_height))
134
+ # Paste the compass in the top right of the image with 5% margin
135
+ paste_compass_x_position = int(right_img.width - (right_img.width + new_compass_width * 2 - paste_x_position) / 2)
136
+ # paste_compass_x_position = int(right_img.width * 0.05)
137
+ paste_compass_y_position = int(right_img.height * 0.05) # 5% margin on the top
138
+ right_img.paste(compass, (paste_compass_x_position, paste_compass_y_position), compass)
139
+ return right_img
140
+
141
+ def watermark(right_img, sb_logo, line_img):
142
+ sb_logo = sb_logo.convert("RGBA")
143
+ new_logo_width = int(line_img.width * 0.2)
144
+ logo_ratio = new_logo_width / sb_logo.width
145
+ new_logo_height = int(sb_logo.height * logo_ratio)
146
+ sb_logo = sb_logo.resize((new_logo_width, new_logo_height))
147
+ # Calculate the position for the logo to be 5% from the right
148
+ paste_x_position = int(right_img.width * 0.95 - new_logo_width)
149
+ paste_y_position = int(right_img.height * 0.95 - new_logo_height)#new_height_px - new_logo_height - int(bottom_space / 4)
150
+ right_img.paste(sb_logo, (paste_x_position, paste_y_position), sb_logo)
151
+ return right_img, paste_x_position, paste_y_position
152
+
153
+ def freemium_watermark(img, sb_logo):
154
+ width_px, height_px = img.size
155
+ # Convert the logo to "RGBA" mode and resize it to 80% of the image width
156
+ sb_logo = sb_logo.convert("RGBA")
157
+ new_logo_width = int(width_px * 0.8) # 80% of the image width
158
+ logo_ratio = new_logo_width / sb_logo.width
159
+ new_logo_height = int(sb_logo.height * logo_ratio)
160
+ sb_logo = sb_logo.resize((new_logo_width, new_logo_height))
161
+ # Make the logo semi-translucent
162
+ transparent_img = Image.new('RGBA', (sb_logo.width, sb_logo.height), (0, 0, 0, 0)) # Create a transparent image of the same size
163
+ sb_logo = Image.blend(transparent_img, sb_logo, alpha=0.3) # Blend the logo with the transparent image
164
+ # Calculate the position to paste the logo at the center of the image
165
+ paste_x_position = (width_px - new_logo_width) // 2
166
+ paste_y_position = (height_px - new_logo_height) // 2
167
+ img.paste(sb_logo, (paste_x_position, paste_y_position), sb_logo)
168
+ # Save the image
169
+ return img
170
+
171
+ def create_line_drawing(input_path):
172
+ with Image.open(input_path) as img:
173
+ img_array = np.array(img)
174
+ # Line processing
175
+ blurred = cv2.GaussianBlur(img_array, (7, 7), 0)
176
+ edges = cv2.Canny(blurred, 100, 180)
177
+ structuring_element = cv2.getStructuringElement(cv2.MORPH_RECT, (4,3))
178
+ dilated_edges = cv2.dilate(edges, structuring_element, iterations=1)
179
+ line_drawing = 255 - dilated_edges
180
+ line_img = Image.fromarray(line_drawing)
181
+
182
+ right_img = add_white_space_right(line_img)
183
+ right_img, paste_x_position, paste_y_position = watermark(right_img, sb_logo, line_img)
184
+ exif_data = list(get_exif(input_path))
185
+ if str(exif_data) != str([None, None, None]):
186
+ print(str(exif_data))
187
+ print("drawing scale bar")
188
+ line_img = draw_scale_bar(right_img, exif_data, compass, line_img, paste_x_position, paste_y_position)
189
+ line_img = freemium_watermark(line_img, sb_logo)
190
+ return line_img
191
+ else:
192
+ line_img = freemium_watermark(line_img, sb_logo)
193
+ return line_img
194
+
195
+ sb_logo = Image.open("./SB_logo_horizontal.png")
196
+ compass = Image.open("./compass.jpg")
197
+
198
+ demo = gr.Interface(create_line_drawing,
199
+ inputs=gr.File(type="filepath"),
200
+ outputs="image",
201
+ live=True)
202
+ demo.queue(max_size=10).launch()