views.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. # django imports
  2. from django.shortcuts import render
  3. from django.http import HttpResponse
  4. from django.conf import settings
  5. # main imports
  6. import os
  7. import json
  8. import base64
  9. import random
  10. import numpy as np
  11. from datetime import datetime
  12. import pickle
  13. import time
  14. # expe imports
  15. from .quest.quest_plus import QuestPlus
  16. from .quest.expe import psychometric_fun
  17. # image processing imports
  18. import io
  19. from PIL import Image
  20. # api imports
  21. from .utils import api
  22. from .utils import functions
  23. from .quest.processing import crop_images
  24. from . import config as cfg
  25. def expe_list(request):
  26. # get all scenes from dataset
  27. scenes = api.get_scenes()
  28. # get list of experiences
  29. expes = cfg.expe_name_list
  30. return render(request, 'expe/expe_list.html', {'scenes': scenes, 'expes': expes})
  31. # Create your views here.
  32. def expe(request):
  33. # get param
  34. expe_name = request.GET.get('expe')
  35. scene_name = request.GET.get('scene')
  36. # unique user ID during session (user can launch multiple exeperiences)
  37. if 'id' not in request.session:
  38. request.session['id'] = functions.uniqueID()
  39. # first time expe is launched add expe information
  40. if 'expe' not in request.session or expe_name != request.session.get('expe'):
  41. request.session['expe'] = expe_name
  42. request.session['scene'] = scene_name
  43. request.session['begin'] = True
  44. request.session['qualities'] = api.get_scene_qualities(scene_name)
  45. # update unique timestamp each time new experience is launched
  46. request.session['timestamp'] = datetime.strftime(datetime.utcnow(), "%Y-%m-%d_%Hh%Mm%Ss")
  47. else:
  48. request.session['begin'] = False
  49. # refresh if scene_name changed
  50. if 'scene' not in request.session or scene_name != request.session.get('scene'):
  51. request.session['expe'] = expe_name
  52. request.session['scene'] = scene_name
  53. request.session['begin'] = True
  54. request.session['qualities'] = api.get_scene_qualities(scene_name)
  55. # update unique timestamp each time new experience is launched
  56. request.session['timestamp'] = datetime.strftime(datetime.utcnow(), "%Y-%m-%d_%Hh%Mm%Ss")
  57. else:
  58. request.session['begin'] = False
  59. # create output folder for expe_result
  60. current_day = datetime.strftime(datetime.utcnow(), "%Y-%m-%d")
  61. results_folder = os.path.join(cfg.output_expe_folder.format(current_day))
  62. if not os.path.exists(results_folder):
  63. os.makedirs(results_folder)
  64. result_filename = expe_name + '_' + scene_name + '_' + request.session.get('id') + '_' + request.session.get('timestamp') +".csv"
  65. results_filepath = os.path.join(results_folder, result_filename)
  66. if not os.path.exists(results_filepath):
  67. output_file = open(results_filepath, 'w')
  68. functions.write_header_expe(output_file, expe_name)
  69. else:
  70. output_file = open(results_filepath, 'a')
  71. # create `quest` object if not exists
  72. models_folder = os.path.join(cfg.model_expe_folder.format(current_day))
  73. if not os.path.exists(models_folder):
  74. os.makedirs(models_folder)
  75. model_filename = result_filename.replace('.csv', '.obj')
  76. model_filepath = os.path.join(models_folder, model_filename)
  77. # run `quest` expe
  78. img_merge = run_quest_one_image(request, model_filepath, output_file)
  79. if img_merge is not None:
  80. # create output folder for tmp files if necessary
  81. tmp_folder = os.path.join(settings.MEDIA_ROOT, cfg.output_tmp_folder)
  82. if not os.path.exists(tmp_folder):
  83. os.makedirs(tmp_folder)
  84. # generate tmp merged image (pass as BytesIO was complicated..)
  85. # TODO : add crontab task to erase generated img
  86. filepath_img = os.path.join(tmp_folder, request.session.get('id') + '_' + scene_name + '' + expe_name + '.png')
  87. img_merge.save(filepath_img)
  88. # expe parameters
  89. data = {
  90. 'expe_name': expe_name,
  91. 'img_merged_path': filepath_img,
  92. 'question': cfg.expe_questions[expe_name]['question'],
  93. 'indication': cfg.expe_questions[expe_name]['indication']
  94. }
  95. return render(request, 'expe/expe.html', data)
  96. def refresh_data(request, expe_name, scene_name):
  97. request.session['expe'] = expe_name
  98. request.session['scene'] = scene_name
  99. request.session['begin'] = True
  100. request.session['qualities'] = api.get_scene_qualities(scene_name)
  101. # update unique timestamp each time new experience is launched
  102. request.session['timestamp'] = datetime.strftime(datetime.utcnow(), "%Y-%m-%d_%Hh%Mm%Ss")
  103. # TODO : add in cache ref_image
  104. # get reference image
  105. #ref_image = api.get_image(scene_name, 'max')
  106. # save ref image as list (can't save python object)
  107. #request.session['ref_img'] = np.array(ref_image).tolist()
  108. def run_quest_one_image(request, model_filepath, output_file):
  109. # get parameters
  110. qualities = request.session.get('qualities')
  111. scene_name = request.session.get('scene')
  112. # by default
  113. iteration = 0
  114. # first time only init `quest`
  115. # if experience is started we can save data
  116. if request.session.get('begin'):
  117. answer = int(request.GET.get('answer'))
  118. iteration = int(request.GET.get('iteration'))
  119. answer_time = time.time() - request.session['answer_time']
  120. previous_percentage = request.session.get('expe_percentage')
  121. previous_orientation = request.session.get('expe_orientation')
  122. previous_position = request.session.get('expe_percentage')
  123. previous_entropy = request.session.get('expe_entropy')
  124. # default params
  125. max_iteration = 10
  126. thresholds = np.arange(50, 10000, 50)
  127. stim_space=np.asarray(qualities)
  128. slopes = np.arange(0.0001, 0.001, 0.00003)
  129. # check if necessary to construct `quest` object
  130. if not os.path.exists(model_filepath):
  131. qp = QuestPlus(stim_space, [thresholds, slopes], function=psychometric_fun)
  132. else:
  133. filehandler = open(model_filepath, 'rb')
  134. qp = pickle.load(filehandler)
  135. # construct image and update `quest` only if necessary
  136. if iteration < max_iteration:
  137. # process `quest`
  138. next_stim = qp.next_contrast()
  139. print(next_stim)
  140. # construct new image
  141. noisy_image = api.get_image(scene_name, next_stim)
  142. # reconstruct reference image from list stored into session
  143. ref_image = api.get_image(scene_name, 'max')
  144. img_merge, percentage, orientation, position = crop_images(noisy_image, ref_image)
  145. else:
  146. return None
  147. # if experience is started we can save data
  148. if request.session.get('begin'):
  149. # TODO : check `i` variable
  150. # update of `quest`
  151. # qp.update(qualities[i], answer)
  152. qp.update(str(qualities[iteration]), answer)
  153. entropy = qp.get_entropy()
  154. line = str(next_stim)
  155. line += ";" + scene_name
  156. line += ";" + str(previous_percentage)
  157. line += ";" + str(previous_orientation)
  158. line += ";" + str(previous_orientation)
  159. line += ";" + str(answer)
  160. line += ";" + str(answer_time)
  161. line += ";" + str(entropy)
  162. line += '\n'
  163. # TODO : add answer time from javascript
  164. output_file.write(line)
  165. output_file.flush()
  166. # save `quest` model
  167. file_pi = open(model_filepath, 'wb')
  168. pickle.dump(qp, file_pi)
  169. # set current step data
  170. request.session['expe_percentage'] = percentage
  171. request.session['expe_orientation'] = orientation
  172. request.session['expe_position'] = position
  173. request.session['answer_time'] = time.time()
  174. return img_merge