forked from tooploox/SPCConvert
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrois2fullframes.py
274 lines (214 loc) · 8.66 KB
/
rois2fullframes.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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# -*- coding: utf-8 -*-
"""
spcconvert - batch conversion and webpage building for SPC images
"""
import cvtools
import cv2
import os
import sys
import glob
import time
import datetime
import json
import shutil
import math
from multiprocessing import Pool, Process, Queue
from threading import Thread
import multiprocessing
from itertools import repeat
from operator import itemgetter
from pytz import timezone
import pystache
import numpy as np
import xmlsettings
from scipy import stats
image_res = 22.0/1000
fullImageSize = [2824,4240]
class Counter(object):
def __init__(self):
self.val = multiprocessing.Value('i', 0)
def increment(self, n=1):
with self.val.get_lock():
self.val.value += n
@property
def value(self):
return self.val.value
def process_image(bundle):
image_path = bundle['image_path']
image = bundle['image']
data_path = bundle['data_path']
image_dir = bundle['image_dir']
cfg = bundle['cfg']
total_images = bundle['total_images']
filename = os.path.basename(image_path)
# Patch bug in PCAM where timestamp string is somtimes incorrectly set to
# 0 or a small value. Use the file creation time instead.
#
# This is okay so long as the queue in PCAM mostly empty. We can adapt
# the frame counter to fix this in the future.
timestamp = 0
for substr in filename.split('-'):
try:
timestamp = int(substr)
break;
except ValueError:
pass
# use the file creation time if the timestamp is funky
if timestamp < 100000:
timestamp = os.path.getctime(image_path)
prefix = filename.split('.')[0]
# image is preloaded so no need to load here
#image = cvtools.import_image(data_path,filename,bayer_pattern=cv2.COLOR_BAYER_BG2RGB)
img_c_8bit = cvtools.convert_to_8bit(image)
# images will be saved out later so set save_to_disk to False
features = cvtools.quick_features(
img_c_8bit,
save_to_disk=False,
abs_path=image_dir,
file_prefix=prefix
)
filename = os.path.basename(image_path).split('.')[0] + '.png'
timestring = datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
entry = {}
entry['maj_axis_len'] = features['major_axis_length']
entry['min_axis_len'] = features['minor_axis_length']
entry['aspect_ratio'] = features['aspect_ratio']
entry['area'] = features['area']
entry['clipped_fraction'] = features['clipped_fraction']
entry['orientation'] = features['orientation']*180/math.pi
entry['timestring'] = timestring
entry['timestamp'] = timestamp
entry['width'] = img_c_8bit.shape[1]
entry['height'] = img_c_8bit.shape[0]
entry['url'] = bundle['reldir'] + '/' + filename
entry['file_size'] = os.path.getsize(image_path)
output = {}
output['entry'] = entry
output['image_path'] = image_dir
output['prefix'] = prefix
output['features'] = features
return output
# threaded function for each process to call
# queues are used to sync processes
def process_bundle_list(bundle_queue,output_queue):
while bundle_queue.qsize() > 0:
output_queue.put(process_image(bundle_queue.get()))
# Split a list into sublists
def chunks(l, n):
n = max(1, n)
return [l[i:i+n] for i in xrange(0, len(l), n)]
# Process a directory of images
def run(data_path,cfg):
# get the base name of the directory
base_dir_name = os.path.basename(data_path)
# list the directory for tif images
print "Listing directory " + base_dir_name + "..."
image_list = sorted(glob.glob(os.path.join(data_path,"*.tif")))
# skip if no images were found
if len(image_list) == 0:
print "No images were found. skipping this directory."
return
# Get the total number of images in the directory
total_images = len(image_list)
# Create the output directories for the images and web app files
subdir = os.path.join(data_path,'..',base_dir_name + '_flowframes')
if not os.path.exists(subdir):
os.makedirs(subdir)
image_dir = os.path.join(subdir,'images')
if not os.path.exists(image_dir):
os.makedirs(image_dir)
print "Starting image conversion and page generation..."
# loop over the images and do the processing
images_per_dir = 2000
print "Loading images...\r",
bundle_queue = Queue()
for index, image in enumerate(image_list):
reldir = 'images/' + str(images_per_dir*int(index/images_per_dir)).zfill(5)
absdir = os.path.join(image_dir,str(images_per_dir*int(index/images_per_dir)).zfill(5))
filename = os.path.basename(image)
if not os.path.exists(absdir):
os.makedirs(absdir)
bundle = {}
bundle['image_path'] = image
bundle['image'] = cvtools.import_image(data_path,filename,bayer_pattern=cv2.COLOR_BAYER_BG2RGB)
bundle['data_path'] = data_path
bundle['image_dir'] = absdir
bundle['reldir'] = reldir
bundle['cfg'] = cfg
bundle['total_images'] = total_images
bundle_queue.put(bundle)
print "Loading images... (" + str(index) + " of " + str(total_images) + ")\r",
#if index > 2000:
# total_images = index
# break
# Get the number o proceess to use based on CPUs
n_threads = 1
if n_threads < 1:
n_threads = 1
# Create the set of processes and start them
start_time = time.time()
output_queue = Queue()
processes = []
for i in range(0,n_threads):
p = Process(target=process_bundle_list, args=(bundle_queue,output_queue))
p.start()
processes.append(p)
# Monitor processing of the images and save processed images to disk as they become available
print "\nProcessing Images...\r",
counter = 0
entry_list = []
raw_image = np.zeros((fullImageSize[0],fullImageSize[1],3))
image_index = 0
while True:
print "Processing and saving images... (" + str(counter).zfill(5) + " of " + str(total_images).zfill(5) + "), " + str(bundle_queue.qsize()).zfill(5)+ " images queued.\r",
if counter >= total_images:
break
if output_queue.qsize() == 0:
time.sleep(0.05)
else:
output = output_queue.get()
fileprefix = output['entry']['url'].split('.')[0]
# EXAMPLE SPC-NOAA-1363060960-000097-264-0-784-168-152
roi_index = int(fileprefix.split('-')[-6])
roi_x = int(fileprefix.split('-')[-4])
roi_y = int(fileprefix.split('-')[-3])
roi_w = int(fileprefix.split('-')[-2])
roi_h = int(fileprefix.split('-')[-1])
if roi_index == image_index:
raw_image[roi_y:(roi_y+roi_h):1,roi_x:(roi_x+roi_w):1,:] = output['features']['image']
else:
output_path = os.path.join(output['image_path'],'frame_'+str(image_index).zfill(5))
cv2.imwrite(os.path.join(output_path+".tif"),raw_image)
raw_image = 0*raw_image
image_index = roi_index
raw_image[roi_y:(roi_y+roi_h):1,roi_x:(roi_x+roi_w):1,:] = output['features']['image']
counter = counter + 1
# Record the total time for processing
proc_time = int(math.floor(time.time()-start_time))
# Terminate the processes in case they are stuck
for p in processes:
p.terminate()
print "Done."
if __name__ == '__main__':
if len(sys.argv) <= 1:
print "Please input a dirtectory of data directories, aborting."
else:
if len(sys.argv) <= 2:
# load the config file
cfg = xmlsettings.XMLSettings(os.path.join(sys.path[0],'settings.xml'))
# If given directory is a single data directory, just process it
if os.path.isfile(os.path.join(sys.argv[1],'config.xml')):
run(sys.argv[1],cfg)
exit()
# Otherwise look for data directories in the given directory
# List data directories and process each one
# expect the directories to be in the unixtime format
directory_list = sorted(glob.glob(os.path.join(sys.argv[1],"[0-9]"*10)))
if len(directory_list) == 0:
print "No data directories found."
exit()
# Process the daata directories in order
for directory in directory_list:
if os.path.isdir(directory):
if os.path.isfile(os.path.join(directory,'config.xml')):
run(directory,cfg)