Created
September 16, 2015 00:45
-
-
Save croxis/6f558bce01ac7469295a to your computer and use it in GitHub Desktop.
Ocular Ryla Evaluation Scanner and Tabulator for Python 3. Needs imagemagick installed on a system path and the python extension "wand"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# python eval.py test.pdf 'Top Person' 'Top topic' 'Bottom Person' 'Bottom topic' | |
import argparse | |
import os | |
import shlex | |
import subprocess | |
import glob | |
from wand.image import Image | |
from wand.display import display | |
from wand.color import Color | |
YEAR = '2014' | |
FOLDER = YEAR + '/*.pdf' | |
coords = ({'yes': (450, 70, 535, 95), 'no': (535, 70, 620, 95), 'na': (615, 70, 705, 95)}, | |
{'yes': (450, 95, 535, 120), 'no': (535, 95, 620, 120), 'na': (615, 95, 705, 120)}, | |
{'yes': (450, 120, 535, 140), 'no': (535, 120, 620, 140), 'na': (615, 120, 705, 140)}, | |
{'yes': (450, 140, 535, 160), 'no': (535, 140, 620, 160), 'na': (615, 140, 705, 160)}, | |
{'yes': (450, 160, 535, 180), 'no': (535, 160, 620, 180), 'na': (615, 160, 705, 180)}, | |
{'yes': (450, 180, 535, 205), 'no': (535, 180, 620, 205), 'na': (615, 180, 705, 205)}, | |
{'yes': (450, 205, 535, 225), 'no': (535, 205, 620, 225), 'na': (615, 205, 705, 225)}, | |
{'yes': (450, 225, 535, 250), 'no': (535, 225, 620, 250), 'na': (615, 225, 705, 250)}, | |
{'yes': (450, 250, 535, 270), 'no': (535, 250, 620, 270), 'na': (615, 250, 705, 270)}, | |
{'yes': (450, 270, 535, 290), 'no': (535, 270, 620, 290), 'na': (615, 270, 705, 290)}) | |
written_coords = 300 | |
questions = [ | |
'I learned something new or gained new insights', | |
'I learned a new skill that will be useful outside of RYLA', | |
'My perceptions were challenged by a new perspective', | |
'I feel motivated to serve my community', | |
'The speaker presented the topic clearly', | |
'The speaker responded well to questions', | |
'The presentation was well balanced and engaging', | |
'My overall impressions of the speaker was positive', | |
'This speaker should be at RYLA every year', | |
'This topic should be at RYLA every year' | |
] | |
def evaluate(path): | |
filename = path | |
topname = 'blank' | |
bottomname = 'blank' | |
top_topic = 'blank' | |
btm_topic = 'blank' | |
temp_name = path.lstrip(YEAR + '/').rstrip('.pdf') | |
split = temp_name.split(' - ') | |
topname = split[0] | |
top_topic = split[1] | |
if len(split) == 4: | |
bottomname = split[2] | |
btm_topic = split[3] | |
res = 50 | |
factor = res/100 | |
white = Color('#fff') | |
save_path = '/home/croxis/Dropbox/Ryla Results/' | |
default_white = [] | |
top_questions = [] | |
btm_questions = [] | |
def scan_a(img, coord): | |
white_count = 0 | |
with img.clone() as a: | |
a.crop(int(coord[0] * factor), int(coord[1] * factor), int(coord[2] * factor), int(coord[3] * factor)) | |
for row in a: | |
for col in row: | |
if col.red == 1.0 and col.blue == 1.0 and col.green == 1.0: | |
white_count += 1 | |
#if col.alpha_int8 != 0: | |
# white_count += 1 | |
return white_count | |
def split_page(page): | |
top_img = page.clone() | |
top_img.crop(0, int(145 * factor), int(page.width), int(590 * factor)) | |
#top_img.save(filename='a.png') | |
btm_img = page.clone() | |
#btm_img.crop(0, int(613 * factor), int(page.width), int(1057 * factor)) | |
btm_img.crop(0, int(613 * factor), int(page.width), page.height) | |
#btm_img.save(filename='b.png') | |
return top_img, btm_img | |
def tabulate_question(page, i, results): | |
result_yes = scan_a(page, coords[i]['yes']) | |
result_no = scan_a(page, coords[i]['no']) | |
result_na = scan_a(page, coords[i]['na']) | |
changeyes = abs(result_yes - default_white[i]['yes'])/float(default_white[i]['yes']) | |
changeno = abs(result_no - default_white[i]['no'])/float(default_white[i]['no']) | |
changena = abs(result_na - default_white[i]['na'])/float(default_white[i]['na']) | |
#print "Percent change:", changeyes, changeno, changena | |
if changeyes > changeno and changeyes > changena: | |
#print "CONCLUSION: YES" | |
results[i]['yes'] += 1 | |
elif changeno > changeyes and changeno > changena: | |
#print "CONCLUSION: NO" | |
results[i]['no'] += 1 | |
elif changena > changeno and changena > changeyes: | |
#print "CONCLUSION: N/A" | |
results[i]['na'] += 1 | |
else: | |
print("Ok something screwed up. Contact David and yell at him.") | |
print(result_yes, result_no, result_na) | |
print(changeyes, changeno, changena) | |
def generate_comment_page(): | |
#page = Image(width = 3400, height = 4400, background=white) # 400dpi | |
page = Image(width=2250, height=3300, background=white) # 300 dpi | |
page.format = 'pdf' | |
#blank_img.background_color = white | |
#blank_img.alpha_channel = False | |
return page | |
print('Initializing for ' + topname + ' and ' + bottomname) | |
print('Debug for reference questions:', default_white) | |
print("Loading survay") | |
top_feedback = [generate_comment_page()] | |
btm_feedback = [generate_comment_page()] | |
top_page_count = 0 | |
btm_page_count = 0 | |
top_scan_height = 0 | |
btm_scan_height = 0 | |
scan_int = 100 | |
max_height = 1000 | |
with Image(filename=filename, resolution=res) as img: | |
p = 0 | |
for image in img.sequence: | |
top_img, btm_img = split_page(image) | |
print("Scanning page", p, '/', len(img.sequence)) | |
if p is 0: | |
print("Calibrating blank page") | |
for i in range(10): | |
top_questions.append({'yes': 0, 'no': 0, 'na': 0}) | |
btm_questions.append({'yes': 0, 'no': 0, 'na': 0}) | |
default_white.append({'yes': 0, 'no': 0, 'na': 0}) | |
for i in range(10): | |
print("Calibrating question", i+1) | |
default_white[i]['yes'] = scan_a(top_img, coords[i]['yes']) | |
default_white[i]['no'] = scan_a(top_img, coords[i]['no']) | |
default_white[i]['na'] = scan_a(top_img, coords[i]['na']) | |
else: | |
for i in range(10): | |
#print("Scanning page", p, '/', len(img.sequence), "question", i+1) | |
tabulate_question(top_img, i, top_questions) | |
tabulate_question(btm_img, i, btm_questions) | |
p += 1 | |
print('') | |
print("RESULTS") | |
top_final = {'yes': 0, 'no': 0, 'na': 0} | |
bottom_final = {'yes': 0, 'no': 0, 'na': 0} | |
for i in range(10): | |
print("Top Question", i+1, top_questions[i]) | |
print("Btm Question", i+1, btm_questions[i]) | |
top_final['yes'] += top_questions[i]['yes'] | |
top_final['no'] += top_questions[i]['no'] | |
top_final['na'] += top_questions[i]['na'] | |
bottom_final['yes'] += btm_questions[i]['yes'] | |
bottom_final['no'] += btm_questions[i]['no'] | |
bottom_final['na'] += btm_questions[i]['na'] | |
print('') | |
print('Compiling comments') | |
print('Reloading surveys at full resolution') | |
top_feedback = [generate_comment_page()] | |
btm_feedback = [generate_comment_page()] | |
top_page_count = 0 | |
btm_page_count = 0 | |
top_scan_height = 0 | |
btm_scan_height = 0 | |
scan_int = 100 | |
#scan_int = 200 | |
max_height = 1000 | |
res=300 | |
factor = res/100 | |
#TODO: Write tests that scans line below main righting and bottom of section to see | |
#if anyoen wrote there | |
#If so expand selection | |
with Image(filename=filename, resolution=res) as img: | |
p = 0 | |
top_extra = 0 | |
btm_extra = 0 | |
for image in img.sequence: | |
print('Processing page', p) | |
if p is 0: | |
p += 1 | |
continue # Skip calibration page | |
top_img, btm_img = split_page(image) | |
nonwhite = 0 | |
for col in top_img[int(395*factor)]: | |
if col.red < 1.0 and col.blue < 1.0 and col.green < 1.0: | |
nonwhite += 1 | |
if nonwhite/top_img.width > 0.2: | |
top_extra = int(8 * factor) | |
nonwhite = 0 | |
for col in top_img[int(432*factor)]: | |
if col.red < 1.0 and col.blue < 1.0 and col.green < 1.0: | |
nonwhite += 1 | |
if nonwhite/top_img.width > 0.2: | |
top_extra = int(44 * factor) | |
nonwhite = 0 | |
for col in btm_img[int(395*factor)]: | |
if col.red < 1.0 and col.blue < 1.0 and col.green < 1.0: | |
nonwhite += 1 | |
if nonwhite/btm_img.width > 0.2: | |
btm_extra = int(8 * factor) | |
nonwhite = 0 | |
for col in btm_img[int(432*factor)]: | |
if col.red < 1.0 and col.blue < 1.0 and col.green < 1.0: | |
nonwhite += 1 | |
if nonwhite/btm_img.width > 0.2: | |
btm_extra = int(44 * factor) | |
top_img.crop(0, int(written_coords * factor), top_img.width, int(((written_coords + scan_int) * factor + top_extra))) | |
btm_img.crop(0, int(written_coords * factor), btm_img.width, int(((written_coords + scan_int) * factor + btm_extra))) | |
if top_scan_height + (scan_int * factor) + top_extra > max_height * factor: | |
print('Generating top review page', top_page_count + 2) | |
top_scan_height = 0 | |
top_feedback.append(generate_comment_page()) | |
top_page_count += 1 | |
if btm_scan_height + (scan_int * factor) + btm_extra > max_height * factor: | |
print('Generating btm review page', btm_page_count + 2) | |
btm_scan_height = 0 | |
btm_feedback.append(generate_comment_page()) | |
btm_page_count += 1 | |
top_feedback[top_page_count].composite(top_img, 0, top_scan_height + top_extra) | |
btm_feedback[btm_page_count].composite(btm_img, 0, btm_scan_height + btm_extra) | |
top_img.close() | |
btm_img.close() | |
top_scan_height += int(scan_int * factor) + top_extra + 10 | |
btm_scan_height += int(scan_int * factor) + btm_extra + 10 | |
top_extra = 0 | |
btm_extra = 0 | |
p += 1 | |
top_cmt = top_feedback[0] | |
for i in range(1, len(top_feedback)): | |
top_cmt.sequence.append(top_feedback[i].sequence[0]) | |
btm_cmt = btm_feedback[0] | |
for i in range(1, len(btm_feedback)): | |
btm_cmt.sequence.append(btm_feedback[i].sequence[0]) | |
'''for i in range(1, len(top_feedback)): | |
top_cmt.sequence.append(top_feedback.sequence[0]) | |
for i in range(1, len(btm_feedback)): | |
btm_cmt.sequence.append(btm_feedback.sequence[0])''' | |
# Prep feedback sheet | |
print('') | |
print('Saving Results') | |
with open(save_path + 'results.txt', 'a') as f: | |
f.write('----------------------------------------------------------\n') | |
f.write(topname + ' - ' + top_topic + '\n') | |
for i in range(10): | |
f.write(questions[i] + ' - \tYes: ' + str(top_questions[i]['yes']) + '\tNo: ' + str(top_questions[i]['no']) + '\tN/A: ' + str(top_questions[i]['na']) + '\n') | |
f.write('----------------------------------------------------------\n') | |
f.write(bottomname + ' - ' + btm_topic + '\n') | |
for i in range(10): | |
f.write(questions[i] + ' - \tYes: ' + str(btm_questions[i]['yes']) + '\tNo: ' + str(btm_questions[i]['no']) + '\tN/A: ' + str(btm_questions[i]['na']) + '\n') | |
print('') | |
print('Compiling final documents') | |
top_cmt.save(filename=save_path + topname + '-' + top_topic + '.pdf') | |
btm_cmt.save(filename=save_path + bottomname + '-' + btm_topic + '.pdf') | |
print('Finished as ' + topname + '-' + top_topic + '.pdf' + ' and ' + bottomname + '-' + btm_topic + '.pdf') | |
print('') | |
del top_feedback | |
del btm_feedback | |
del top_cmt | |
del btm_cmt | |
import gc | |
gc.collect() | |
if __name__ == '__main__': | |
from multiprocessing import Process | |
for path in glob.glob(FOLDER): | |
p = Process(target=evaluate, args=(path,)) | |
p.start() | |
p.join() | |
p.terminate() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment