Parcourir la source

Added new experiment (areSameImages)

rigwild il y a 4 ans
Parent
commit
105d4fa7bc

+ 9 - 0
experimentConfig.default/Experiments/AreSameImages.js

@@ -0,0 +1,9 @@
+import { buildConfig } from '@/functions'
+
+// This will apply to all the scenes
+export const defaultConfig = {}
+
+// This will overwrite the config for the given scene
+export const scenesConfig = {}
+
+export default buildConfig(defaultConfig, scenesConfig)

+ 8 - 2
experimentConfig.default/mixins/ExperimentBase.js

@@ -1,9 +1,15 @@
 import { buildConfig } from '@/functions'
 
 // This will apply to all the scenes
-export const defaultConfig = {}
+export const defaultConfig = {
+  // lockConfig: true
+}
 
 // This will overwrite the config for the given scene
-export const scenesConfig = {}
+export const scenesConfig = {
+  // bathroom: {
+  //   lockConfig: true
+  // }
+}
 
 export default buildConfig(defaultConfig, scenesConfig)

+ 15 - 0
experimentConfig.default/mixins/ExperimentBaseAreSameImages.js

@@ -0,0 +1,15 @@
+import { buildConfig } from '@/functions'
+
+// This will apply to all the scenes
+export const defaultConfig = {
+  // maxTestCount: 5
+}
+
+// This will overwrite the config for the given scene
+export const scenesConfig = {
+  // bathroom: {
+  //   maxTestCount: 5
+  // }
+}
+
+export default buildConfig(defaultConfig, scenesConfig)

+ 2 - 4
experimentConfig.default/mixins/ExperimentBaseExtracts.js

@@ -6,8 +6,7 @@ export const defaultConfig = {
   // extractConfig: {
   //   x: 4,
   //   y: 6
-  // },
-  // lockConfig: true
+  // }
 }
 
 // This will overwrite the config for the given scene
@@ -17,8 +16,7 @@ export const scenesConfig = {
   //   extractConfig: {
   //     x: 4,
   //     y: 10
-  //   },
-  //   lockConfig: false
+  //   }
   // }
 }
 

+ 4 - 1
src/functions.js

@@ -23,7 +23,7 @@ export const API_ROUTES = {
 export const delay = ms => new Promise(res => setTimeout(res, ms))
 
 export const buildURI = (ssl, host, port, route = '') => `${ssl ? 'https' : 'http'}://${host}:${port}${route}`
-export const buildWsURI = (ssl, host, port, uuid = '') => `${ssl ? 'wss' : 'ws'}://${host}:${port}?uuid=${uuid}`
+export const buildWsURI = (ssl, host, port) => `${ssl ? 'wss' : 'ws'}://${host}:${port}`
 
 export const sortIntArray = intArray => intArray ? intArray.sort((a, b) => a - b) : null
 
@@ -72,3 +72,6 @@ export const buildConfig = (defaultConfig = {}, scenesConfig = {}) =>
 
 // Serialize non-serializable objects (like window.screen)
 export const serialize = obj => Object.keys(Object.getPrototypeOf(obj)).reduce((acc, x) => ((acc[x] = obj[x]), acc), {})
+
+// Get a random int between two values (inclusive)
+export const rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min

+ 23 - 1
src/mixins/ExperimentBase/index.vue

@@ -34,7 +34,13 @@ export default {
 
   mounted() {
     if (!this.getExperimentProgress({ experimentName: this.experimentName, sceneName: this.sceneName }).experimentName)
-      this.sendMessage({ msgId: experimentMsgId.STARTED, experimentName: this.experimentName, sceneName: this.sceneName })
+      this.sendMessage({
+        msgId: experimentMsgId.STARTED,
+        msg: {
+          experimentName: this.experimentName,
+          sceneName: this.sceneName
+        }
+      })
 
     // Check if the experiment is already finished
     if (this.experimentName && this.sceneName && this.isExperimentDone({ experimentName: this.experimentName, sceneName: this.sceneName })) {
@@ -91,6 +97,22 @@ export default {
       const { data } = await fetch(URI).then(res => res.json())
       this.qualities = data
       this.saveProgress()
+    },
+
+
+    // Load an image from the API
+    async getImage(quality) {
+      const URI = `${this.getHostURI}${API_ROUTES.getImage(this.sceneName, quality)}`
+      const { data } = await fetch(URI)
+        .then(async res => {
+          res.json = await res.json()
+          return res
+        })
+        .then(res => {
+          if (!res.ok) throw new Error(res.json.message + res.json.data ? `\n${res.json.data}` : '')
+          return res.json
+        })
+      return data
     }
   }
 }

+ 39 - 0
src/mixins/ExperimentBaseAreSameImages/config.js

@@ -0,0 +1,39 @@
+import deepmerge from 'deepmerge'
+import { buildConfig } from '@/functions'
+
+const getMixinConfig = () => import('@/mixins/ExperimentBase/config')
+const getGlobalConfig = () => import('@/../experimentConfig/mixins/ExperimentBaseAreSameImages')
+
+// This will apply to all the scenes
+export const defaultConfig = async () => {
+  // Import parent mixin config
+  const mixinConfig = await getMixinConfig().then(({ defaultConfig: fn }) => fn())
+
+  // Import global config
+  const globalConfig = (await getGlobalConfig()).defaultConfig
+
+  return deepmerge.all([
+    mixinConfig,
+    {
+      maxTestCount: 5
+    },
+    globalConfig
+  ])
+}
+
+// This will overwrite the config for the given scene
+export const scenesConfig = async () => {
+  // Import parent mixin config
+  const mixinConfig = await getMixinConfig().then(({ scenesConfig: fn }) => fn())
+
+  // Import global config
+  const globalConfig = (await getGlobalConfig()).scenesConfig
+
+  return deepmerge.all([
+    mixinConfig,
+    {},
+    globalConfig
+  ])
+}
+
+export default async () => buildConfig(await defaultConfig(), await scenesConfig())

+ 92 - 0
src/mixins/ExperimentBaseAreSameImages/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <div>
+    <slot></slot>
+  </div>
+</template>
+
+<script>
+import './style.css'
+import ExperimentBase from '@/mixins/ExperimentBase'
+
+import { mapGetters } from 'vuex'
+import { rand } from '@/functions'
+import { EXPERIMENT as experimentMsgId } from '@/../config.messagesId'
+
+export default {
+  name: 'ExperimentBaseAreSameImages',
+  mixins: [ExperimentBase],
+  data() {
+    return {
+      maxTestCount: null,
+      testCount: 1,
+
+      leftImage: { link: null, quality: null },
+      rightImage: { link: null, quality: null }
+    }
+  },
+  computed: {
+    ...mapGetters(['getHostURI'])
+  },
+  methods: {
+    async getTest(leftQuality, rightQuality) {
+      const left = this.qualities[leftQuality]
+      const right = this.qualities[rightQuality]
+      const res = await Promise.all([this.getImage(left), this.getImage(right)])
+      const [leftImage, rightImage] = res.map(x => {
+        x.link = `${this.getHostURI}${x.link}`
+        return x
+      })
+      return { leftImage, rightImage }
+    },
+
+    getRandomTest() {
+      return this.getTest(rand(0, this.qualities.length - 1), rand(0, this.qualities.length - 1))
+    },
+
+    // An action was triggered, load extracts and save progression
+    async areTheSameActionRandom(areTheSame) {
+      this.loadingMessage = 'Loading new test...'
+      this.loadingErrorMessage = null
+      try {
+        this.testCount++
+
+        const obj = {
+          leftImage: this.leftImage,
+          rightImage: this.rightImage,
+          areTheSame,
+          experimentName: this.experimentName,
+          sceneName: this.sceneName
+        }
+        this.sendMessage({ msgId: experimentMsgId.DATA, msg: obj })
+
+        const { leftImage, rightImage } = await this.getRandomTest()
+        this.leftImage = leftImage
+        this.rightImage = rightImage
+
+        // Experiment end
+        if (this.testCount >= this.maxTestCount) this.finishExperiment()
+      }
+      catch (err) {
+        console.error('Failed to load new test', err)
+        this.loadingErrorMessage = 'Failed to load new test. ' + err.message
+      }
+      finally {
+        this.loadingMessage = null
+        this.saveProgress()
+      }
+    },
+
+    // Finish an experiment, sending full data to the server
+    // Don't forget to surcharge this function when using this mixin to add more data
+    finishExperiment() {
+      const obj = {
+        experimentName: this.experimentName,
+        sceneName: this.sceneName
+      }
+      this.sendMessage({ msgId: experimentMsgId.VALIDATED, msg: obj })
+      this.setExperimentDone({ experimentName: this.experimentName, sceneName: this.sceneName, done: true })
+      this.$router.push(`/experiments/${this.experimentName}`)
+    }
+  }
+}
+</script>

+ 0 - 0
src/mixins/ExperimentBaseAreSameImages/style.css


+ 7 - 7
src/router/experiments.js

@@ -1,16 +1,16 @@
 export default [
-  {
-    path: '/experiments/ExperimentNoReference/:sceneName',
-    name: 'ExperimentNoReference',
-    fullName: 'No reference image',
-    component: () => import('@/views/Experiments/NoReference'),
-    props: true
-  },
   {
     path: '/experiments/ExperimentWithReference/:sceneName',
     name: 'ExperimentWithReference',
     fullName: 'With reference image',
     component: () => import('@/views/Experiments/WithReference'),
     props: true
+  },
+  {
+    path: '/experiments/ExperimentAreSameImages/:sceneName',
+    name: 'ExperimentAreSameImages',
+    fullName: 'Are images the same',
+    component: () => import('@/views/Experiments/AreSameImages'),
+    props: true
   }
 ]

+ 1 - 1
src/store/getters.js

@@ -18,7 +18,7 @@ export default {
   getHostWsURI(state, getters) {
     if (!state) return
     if (getters.isHostConfigured)
-      return buildWsURI(state.hostConfig.ssl, state.hostConfig.host, state.hostConfig.port, state.uuid)
+      return buildWsURI(state.hostConfig.ssl, state.hostConfig.host, state.hostConfig.port)
   },
 
   areScenesLoaded(state) {

+ 37 - 0
src/views/Experiments/AreSameImages/config.js

@@ -0,0 +1,37 @@
+import deepmerge from 'deepmerge'
+import { buildConfig } from '@/functions'
+
+const getMixinConfig = () => import('@/mixins/ExperimentBaseAreSameImages/config')
+const getGlobalConfig = () => import('@/../experimentConfig/Experiments/AreSameImages')
+
+// This will apply to all the scenes
+export const defaultConfig = async () => {
+  // Import parent mixin config
+  const mixinConfig = await getMixinConfig().then(({ defaultConfig: fn }) => fn())
+
+  // Import global config
+  const globalConfig = (await getGlobalConfig()).defaultConfig
+
+  return deepmerge.all([
+    mixinConfig,
+    {},
+    globalConfig
+  ])
+}
+
+// This will overwrite the config for the given scene
+export const scenesConfig = async () => {
+  // Import parent mixin config
+  const mixinConfig = await getMixinConfig().then(({ scenesConfig: fn }) => fn())
+
+  // Import global config
+  const globalConfig = (await getGlobalConfig()).scenesConfig
+
+  return deepmerge.all([
+    mixinConfig,
+    {},
+    globalConfig
+  ])
+}
+
+export default async () => buildConfig(await defaultConfig(), await scenesConfig())

+ 108 - 0
src/views/Experiments/AreSameImages/index.vue

@@ -0,0 +1,108 @@
+<template>
+  <div>
+    <v-container grid-list-md text-xs-center fluid>
+      <v-layout row wrap>
+        <v-flex xs12>
+          <v-layout justify-start>
+            <v-btn flat exact :to="`/experiments/${experimentName}`">
+              <v-icon left>arrow_back</v-icon>
+              Back to scene selection
+            </v-btn>
+          </v-layout>
+
+          <h1>Experiment Are the images the same - {{ sceneName }}</h1>
+        </v-flex>
+        <!-- Loading screen -->
+        <loader v-if="loadingMessage" :message="loadingMessage" />
+        <!--/ Loading screen -->
+
+        <!-- Experiment -->
+        <template v-else-if="!loadingErrorMessage">
+          <v-flex xs12 sm6>
+            <v-card dark color="primary">
+              <v-card-text class="px-0">Image 1</v-card-text>
+
+              <v-img v-if="leftImage && leftImage.link" :src="leftImage.link">
+                <template v-slot:placeholder>
+                  <v-layout fill-height align-center justify-center ma-0>
+                    <v-progress-circular indeterminate color="grey lighten-5" />
+                  </v-layout>
+                </template>
+              </v-img>
+            </v-card>
+          </v-flex>
+          <v-flex sm6 xs12>
+            <v-card dark color="primary">
+              <v-card-text>Image 2</v-card-text>
+
+              <v-img v-if="rightImage && rightImage.link" :src="rightImage.link">
+                <template v-slot:placeholder>
+                  <v-layout fill-height align-center justify-center ma-0>
+                    <v-progress-circular indeterminate color="grey lighten-5" />
+                  </v-layout>
+                </template>
+              </v-img>
+            </v-card>
+          </v-flex>
+
+
+          <!-- Experiment validation button -->
+
+          <v-layout justify-center align-content-center>
+            <div>
+              <h2>Test {{ testCount }} / {{ maxTestCount }}</h2>
+              <v-layout justify-center align-content-center>
+                <v-btn @click="areTheSameActionRandom(false)" color="error" large>Images are NOT the same</v-btn>
+                <v-btn @click="areTheSameActionRandom(true)" color="success" large>Images are the same</v-btn>
+              </v-layout>
+            </div>
+          </v-layout>
+          <!--/ Experiment validation button -->
+        </template>
+        <!--/ Experiment -->
+      </v-layout>
+    </v-container>
+  </div>
+</template>
+
+<script>
+import ExperimentBaseAreTheSame from '@/mixins/ExperimentBaseAreSameImages'
+import Loader from '@/components/Loader.vue'
+import experimentConfig from './config'
+
+export default {
+  name: 'ExperimentAreTheSame',
+  components: {
+    Loader
+  },
+  mixins: [ExperimentBaseAreTheSame],
+
+  data() {
+    return {
+      experimentName: 'ExperimentAreSameImages'
+    }
+  },
+
+  async mounted() {
+    // Load config for this scene to local state
+    await this.loadConfig(experimentConfig)
+
+    // Load progress from store into local state
+    this.loadProgress()
+
+    // Load scene data from the API
+    await this.getQualitiesList()
+
+    // Load a test if not already one loaded
+    if (!this.leftImage || !this.leftImage.link || !this.rightImage || !this.rightImage.link) {
+      const { leftImage, rightImage } = await this.getRandomTest()
+      this.leftImage = leftImage
+      this.rightImage = rightImage
+    }
+
+    this.saveProgress()
+  },
+
+  methods: {}
+}
+</script>

+ 0 - 9
src/views/Experiments/NoReference/index.vue

@@ -1,9 +0,0 @@
-<template>
-  <div></div>
-</template>
-
-<script>
-export default {
-  name: 'ExperimentNoReference'
-}
-</script>

+ 6 - 13
src/views/Experiments/WithReference/index.vue

@@ -89,7 +89,6 @@
 
 <script>
 import ExperimentBaseExtracts from '@/mixins/ExperimentBaseExtracts'
-import { API_ROUTES } from '@/functions'
 import Loader from '@/components/Loader.vue'
 import ExtractConfiguration from '@/components/ExperimentsComponents/ExtractConfiguration.vue'
 import experimentConfig from './config'
@@ -118,7 +117,11 @@ export default {
 
     // Load scene data from the API
     await Promise.all([
-      this.getReferenceImage(),
+      this.getImage('max')
+        .then(res => {
+          this.referenceImage = this.getHostURI + res.link
+          this.saveProgress()
+        }),
       this.getQualitiesList()
     ])
 
@@ -131,16 +134,6 @@ export default {
     this.saveProgress()
   },
 
-  methods: {
-    // Load the reference image from the API
-    async getReferenceImage() {
-      if (this.referenceImage) return
-
-      const URI = `${this.getHostURI}${API_ROUTES.getImage(this.sceneName, 'max')}`
-      const { data } = await fetch(URI).then(res => res.json())
-      this.referenceImage = this.getHostURI + data.link
-      this.saveProgress()
-    }
-  }
+  methods: {}
 }
 </script>