Skip to content

Instantly share code, notes, and snippets.

@croxis
Created September 16, 2015 00:45
Show Gist options
  • Save croxis/6f558bce01ac7469295a to your computer and use it in GitHub Desktop.
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"
# 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