Bläddra i källkod

first refactoring of the main loop

asobolev 4 år sedan
förälder
incheckning
92de262175
2 ändrade filer med 79 tillägg och 113 borttagningar
  1. 1 0
      .gitignore
  2. 78 113
      Jupyter Notebook - One Target Island - openCV 4-0-1.ipynb

+ 1 - 0
.gitignore

@@ -4,6 +4,7 @@
 *parameters.json
 *.xlsx
 *.avi
+sessions*
 
 # ipython temp files
 .ipynb_checkpoints

+ 78 - 113
Jupyter Notebook - One Target Island - openCV 4-0-1.ipynb

@@ -26,7 +26,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 1,
    "metadata": {},
    "outputs": [
     {
@@ -95,7 +95,7 @@
       "    \"arena_x\": 400,\n",
       "    \"arena_y\": 300,\n",
       "    \"arena_radius\": 300,\n",
-      "    \"experiment_date\": \"2020-06-07_18-26-44\"\n",
+      "    \"experiment_date\": \"2020-06-09_22-13-54\"\n",
       "}\n"
      ]
     }
@@ -129,31 +129,7 @@
    "metadata": {
     "scrolled": true
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "EXPERIMENT ID: 003901_aSIT_2020-06-07_18-26-44\n",
-      "Trials per session: 50\n",
-      "Session duration [s]: 3600\n",
-      "Trial duration [s]: 60\n",
-      "Radius of the starting platform [pixels]: 67\n",
-      "X-position of the starting platform [pixels]: 195\n",
-      "Y-position of the starting platform [pixels]: 195\n",
-      "Radius of the target platform [pixels]: 80\n",
-      "Target duration [s]: 5\n",
-      "Subject: 003901\n",
-      "Experiment type: aSIT\n",
-      "Subject is darker than background [T = True; F = False]: T\n",
-      "Initialisation Duration [s]: 0.2\n",
-      "Arena X coordinate [pixels]: 400\n",
-      "Arena Y coordinate [pixels]: 300\n",
-      "Arena radius [pixels]: 300\n",
-      "Experiment date: 2020-06-07_18-26-44\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "def show_entry_fields():\n",
     "    print(\"EXPERIMENT ID: %s\" % experiment_id)\n",
@@ -435,7 +411,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 9,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -469,21 +445,9 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 10,
    "metadata": {},
-   "outputs": [
-    {
-     "ename": "NameError",
-     "evalue": "name 'arenaX' is not defined",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[0;32m<ipython-input-11-ad6c592f385a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;31m# Mask the space outside the arena\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0mmask\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mshape\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mimg\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshape\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"uint8\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0mcv2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcircle\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmask\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0marenaX\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0marenaY\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0marenaRadius\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m255\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m255\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m255\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m \u001b[0;31m# Experiment starts in phase 0 with 0 trials\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
-      "\u001b[0;31mNameError\u001b[0m: name 'arenaX' is not defined"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# Define video capture device for live-stream (0 = webcam1) and tracking\n",
     "cap = cv2.VideoCapture(0)\n",
@@ -537,7 +501,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 11,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -586,7 +550,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 12,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -621,16 +585,46 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 13,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "ename": "NameError",
+     "evalue": "name 'workbook' is not defined",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-13-e251fc351d5c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m    395\u001b[0m \u001b[0mstream\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    396\u001b[0m \u001b[0mcv2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdestroyAllWindows\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 397\u001b[0;31m \u001b[0mworkbook\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    398\u001b[0m \u001b[0mboard\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    399\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mNameError\u001b[0m: name 'workbook' is not defined"
+     ]
+    }
+   ],
    "source": [
-    "def render_frame():\n",
+    "# Define and start the experiment timer\n",
+    "expTime = time.time()\n",
+    "\n",
+    "# Start the audio stream\n",
+    "stream.start()\n",
+    "\n",
+    "# Conditions to be met for the experiment to start and continue\n",
+    "while(cap.isOpened() and trialCounter < cfg['trial_number'] and (time.time()-expTime)<=cfg['session_duration']):\n",
+    "    \n",
+    "    # Here you can choose different modes of amplitude modulation by commenting/uncommenting \n",
+    "    ampMod = (random.randrange(2396,2962,1)/100)**e/10000 # Unbiased Voltage Ratio -5dB\n",
+    "    ### ampMod = random.randrange(5623,10001,1)/10000 # Voltage Ratio -5dB\n",
+    "    ### ampMod = random.randrange(3162,10001,1)/10000 # Power Ratio -5dB\n",
+    "    ### ampMod = 1 # No modulation\n",
+    "    \n",
+    "    ret, frame = cap.read()\n",
+    "    if not ret == True:\n",
+    "        break\n",
+    "        \n",
     "    maskedFrame = cv2.bitwise_and(src1=frame, src2=mask)\n",
     "\n",
     "    ## Animal tracking\n",
     "    # Substracts background from current frame\n",
-    "    subject = cv2.subtract(img, maskedFrame) if backgroundColor == 'T' else cv2.subtract(maskedFrame, img)\n",
+    "    subject = cv2.subtract(img, maskedFrame) if cfg['background_color'] == 'T' else cv2.subtract(maskedFrame, img)\n",
     "\n",
     "    # Converts subject to grey scale\n",
     "    subjectGray = cv2.cvtColor(subject, cv2.COLOR_BGR2GRAY)\n",
@@ -659,8 +653,8 @@
     "        contour = contours[np.argmax(list(map(cv2.contourArea, contours)))]\n",
     "        M = cv2.moments(contour)\n",
     "        if ((M['m00']) == 0):\n",
-    "            x = 780\n",
-    "            y = 580\n",
+    "            x = 20 if expPhase < 3 else 780\n",
+    "            y = 40 if expPhase < 3 else 580\n",
     "            subjectHullCentroid = np.zeros(frame.shape,np.uint8)\n",
     "            subjectHullCentroid = cv2.circle(subjectHullCentroid, (x,y), 3, BGR_COLOR['yellow'], -1)\n",
     "        else:\n",
@@ -669,16 +663,16 @@
     "            hull = cv2.convexHull(contour)\n",
     "            subjectHullCentroid = maskedFrame\n",
     "\n",
-    "    # Draws contour and centroid of the subject\n",
-    "    cv2.drawContours(subjectHullCentroid, [contour], 0, BGR_COLOR['green'], 1, cv2.LINE_AA)\n",
-    "    subjectHullCentroid = cv2.circle(subjectHullCentroid, (x,y), 3, BGR_COLOR['yellow'], -1)\n",
+    "        # Draws contour and centroid of the subject\n",
+    "        cv2.drawContours(subjectHullCentroid, [contour], 0, BGR_COLOR['green'], 1, cv2.LINE_AA)\n",
+    "        subjectHullCentroid = cv2.circle(subjectHullCentroid, (x,y), 3, BGR_COLOR['yellow'], -1)\n",
     "\n",
-    "    # Draws the arena contour, the attractor target, the distractor target, and a green dot, \n",
-    "    # signalling that the subject is inside the attractor target area\n",
+    "    # Draws the arena contour, the attractor target, the distractor target, and a red / green dot, \n",
+    "    # signalling that the subject is outside / inside the attractor target area\n",
     "    colors = {0: 'red', 1: 'green', 2: 'blue', 3: 'green'}\n",
     "    arena_start_color = (0, 255, 0) if expPhase == 2 else (255, 0, 255)\n",
-    "    subjectHullCentroidArena = cv2.circle(subjectHullCentroid,(arenaX,arenaY), arenaRadius, (0,0,255), 2)\n",
-    "    subjectHullCentroidArenaStart = cv2.circle(subjectHullCentroidArena,(targetX,targetY), targetRadius, arena_start_color, 2)\n",
+    "    subjectHullCentroidArena = cv2.circle(subjectHullCentroid, (cfg['arena_x'],cfg['arena_y']), cfg['arena_radius'], (0,0,255), 2)\n",
+    "    subjectHullCentroidArenaStart = cv2.circle(subjectHullCentroidArena,(targetX,targetY), cfg['target_radius'], arena_start_color, 2)\n",
     "    subjectHullCentroidArenaStartIn = cv2.circle(subjectHullCentroidArena,(20,20), 10, BGR_COLOR[colors[expPhase]], -6)\n",
     "\n",
     "    # Adds a stopwatch for the experiment duration to the video\n",
@@ -689,13 +683,13 @@
     "    # Adds a trial duration countdown to the video\n",
     "    if expPhase > 0:\n",
     "        subjectHullCentroidArenaStartInText=cv2.putText(subjectHullCentroidArenaStartInText,\n",
-    "        '' + str('Trial: %.2f' % ((trialDuration-trialCountdown))),\n",
+    "        '' + str('Trial: %.2f' % ((cfg['trial_duration']-trialCountdown))),\n",
     "        (670,590), cv2.FONT_HERSHEY_DUPLEX, .5, BGR_COLOR['red'] if expPhase == 2 else BGR_COLOR['green'])\n",
     "\n",
     "    # Adds a target duration countdown to the video\n",
     "    if expPhase == 3:\n",
     "        subjectHullCentroidArenaStartInText=cv2.putText(subjectHullCentroidArenaStartInText,\n",
-    "        '' + str('Target: %.2f' % ((targetDuration-targetCountdown))),\n",
+    "        '' + str('Target: %.2f' % ((cfg['target_duration']-targetCountdown))),\n",
     "        (670,570), cv2.FONT_HERSHEY_DUPLEX, .5, BGR_COLOR['green'])\n",
     "\n",
     "    # Adds the current trial number to the video\n",
@@ -713,37 +707,15 @@
     "    cv2.imshow('Press (q)-to end the experiment',subjectHullCentroidArenaStartInText)\n",
     "\n",
     "    # Frame ID\n",
-    "    frameCounter = frameCounter+1\n",
+    "    frameCounter += 1\n",
     "\n",
     "    # Calculates the percentage of successful/rewarded trials\n",
     "    if (rewardCounter==0):\n",
     "        percentCorrect = 0\n",
     "    else:\n",
     "        percentCorrect = 100/trialCounter*rewardCounter\n",
-    "\n",
-    "\n",
-    "\n",
-    "\n",
-    "# Define and start the experiment timer\n",
-    "expTime = time.time()\n",
-    "\n",
-    "# Start the audio stream\n",
-    "stream.start()\n",
-    "\n",
-    "# Conditions to be met for the experiment to start and continue\n",
-    "while(cap.isOpened() and trialCounter<trialNumber and (time.time()-expTime)<=sessionDuration):\n",
-    "    \n",
-    "    # Here you can choose different modes of amplitude modulation by commenting/uncommenting \n",
-    "    ampMod = (random.randrange(2396,2962,1)/100)**e/10000 # Unbiased Voltage Ratio -5dB\n",
-    "    ### ampMod = random.randrange(5623,10001,1)/10000 # Voltage Ratio -5dB\n",
-    "    ### ampMod = random.randrange(3162,10001,1)/10000 # Power Ratio -5dB\n",
-    "    ### ampMod = 1 # No modulation\n",
-    "    \n",
-    "    ret, frame = cap.read()\n",
-    "    if not ret == True:\n",
-    "        break\n",
     "        \n",
-    "    render_frame()\n",
+    "        \n",
     "    \n",
     "    # Phase 0 = Animal just entered the arena or finished a trial\n",
     "    if expPhase == 0:\n",
@@ -754,17 +726,10 @@
     "        # Feede an empty wave to the audio stream\n",
     "        stream.write(silenceSound)\n",
     "        soundPlayed = 'false'\n",
-    "\n",
-    "        # Writes a new row to the protocol\n",
-    "        log_frame_data([frameCounter, (time.time()-expTime), expPhase, \n",
-    "                        x, y, startX, startY, startRadius, targetX, targetY, \n",
-    "                        targetRadius, trialCounter, percentCorrect, soundPlayed, \n",
-    "                        commonCycle, target2X, target2Y, target3X, target3Y, \n",
-    "                        target4X, target4Y, target5X, target5Y])\n",
     "        \n",
     "        # Checks, if the subject is in the starting/initialization area\n",
     "        # If so, the protocol proceeds to phase 1 and a timer is started\n",
-    "        if (((x-startX)*(x-startX))+((y-startY)*(y-startY))) <= (startRadius*startRadius):\n",
+    "        if (x-cfg['start_x'])**2 + (y-cfg['start_y'])**2 <= cfg['start_radius']**2:\n",
     "            expPhase = 1\n",
     "            startInZone = time.time()\n",
     "\n",
@@ -775,12 +740,13 @@
     "    # Phase 1 = Animal is in the starting area\n",
     "    elif expPhase == 1:\n",
     "        ## Checks, if the subject is still in the starting/initialization area \n",
-    "        if (((x-startX)*(x-startX))+((y-startY)*(y-startY))) <= (startRadius*startRadius):\n",
+    "        if (x-cfg['start_x'])**2 + (y-cfg['start_y'])**2 <= cfg['start_radius']**2:\n",
     "            stopInZone = time.time()\n",
+    "\n",
     "            # Checks, if the time spent in the starting/initialization area exceeds the initiation duration\n",
     "            # If so, the protocol proceeds to phase 2, the trial timer is started, the designated distractor (trial)\n",
     "            # sound is played every \"delayLength\" cycles, and the target areas for the current trial are generated\n",
-    "            if (stopInZone-startInZone) >= initDuration:\n",
+    "            if (stopInZone-startInZone) >= cfg['init_duration']:\n",
     "                expPhase = 2\n",
     "                startTrial = time.time()\n",
     "                if (commonCycle == 1):\n",
@@ -797,16 +763,16 @@
     "                    soundPlayed = 'false'\n",
     "\n",
     "                # Generates the first target (attractor), which cannot overlap with the starting area\n",
-    "                while ((((randomX-arenaX)*(randomX-arenaX))+((randomY-arenaY)*(randomY-arenaY))) >= (arenaRadius*arenaRadius) or               \n",
-    "                           math.sqrt(((startX-randomX)*(startX-randomX))+((startY-randomY)*(startY-randomY))) <= (startRadius+targetRadius)):  \n",
+    "                while ( (randomX-cfg['arena_x'])**2 + (randomY-cfg['arena_y'])**2 >= cfg['arena_radius']**2 or               \n",
+    "                           math.sqrt((startX-randomX)**2 + (startY-randomY)**2) <= cfg['start_radius'] + cfg['target_radius'] ):\n",
     "\n",
     "                        # random angle\n",
     "                        alpha = 2 * math.pi * random.random()   \n",
     "                        # random radius\n",
-    "                        r = (arenaRadius-20-targetRadius) * math.sqrt(random.random())  \n",
+    "                        r = (cfg['arena_radius'] - 20 - cfg['target_radius']) * math.sqrt(random.random())  \n",
     "                        # calculating coordinates\n",
-    "                        randomX = int(r * math.cos(alpha) + arenaX)  \n",
-    "                        randomY = int(r * math.sin(alpha) + arenaY)  \n",
+    "                        randomX = int(r * math.cos(alpha) + cfg['arena_x'])  \n",
+    "                        randomY = int(r * math.sin(alpha) + cfg['arena_y'])  \n",
     "                        targetX = randomX                            \n",
     "                        targetY = randomY                      \n",
     "\n",
@@ -834,19 +800,19 @@
     "        stopTrial = time.time()\n",
     "\n",
     "        # If the maximum trial duration is reached, the trial is terminated and the protocol goes back to phase 0\n",
-    "        if (stopTrial-startTrial) >= trialDuration:\n",
+    "        if (stopTrial-startTrial) >= cfg['trial_duration']:\n",
     "            expPhase=0\n",
     "            trialCounter = trialCounter+1\n",
     "            randomX = 9000\n",
     "            randomY = 9000            \n",
-    "            random2X = 9000\n",
-    "            random2Y = 9000                \n",
-    "            random3X = 9000\n",
-    "            random3Y = 9000\n",
-    "            random4X = 9000\n",
-    "            random4Y = 9000\n",
-    "            random5X = 9000\n",
-    "            random5Y = 9000        \n",
+    "            # random2X = 9000\n",
+    "            # random2Y = 9000                \n",
+    "            # random3X = 9000\n",
+    "            # random3Y = 9000\n",
+    "            # random4X = 9000\n",
+    "            # random4Y = 9000\n",
+    "            # random5X = 9000\n",
+    "            # random5Y = 9000        \n",
     "            trialCountdown = 0\n",
     "\n",
     "        else:\n",
@@ -857,7 +823,7 @@
     "            # Checks, if the animal is in the attractor target area\n",
     "            # If so, acoustic stimulation switches to the designated attractor stimulus and the protocol \n",
     "            # proceeds to phase 3\n",
-    "            if (((x-targetX)*(x-targetX))+((y-targetY)*(y-targetY))) <= (targetRadius*targetRadius):\n",
+    "            if (x-targetX)**2 + (y-targetY)**2 <= cfg['target_radius']**2:\n",
     "                startInTarget = time.time()\n",
     "                if (commonCycle == 1):\n",
     "                    stream.write((attractorSoundTarget1*ampMod)) \n",
@@ -906,7 +872,7 @@
     "        # Checks, if the animal is still in the attractor target area\n",
     "        # If so, acoustic stimulation continues with the designated attractor stimulus and the protocol \n",
     "        # remains in phase 3          \n",
-    "        if (((x-targetX)*(x-targetX))+((y-targetY)*(y-targetY))) <= (targetRadius*targetRadius):\n",
+    "        if (x-targetX)**2 + (y-targetY)**2 <= cfg['target_radius']**2:\n",
     "\n",
     "            if (commonCycle == 1):\n",
     "                stream.write((attractorSoundTarget1*ampMod)) \n",
@@ -930,7 +896,7 @@
     "            # Checks, if the desired target duration is reached   \n",
     "            # If so, the subject is rewarded, the trial and reward counters are increased by 1,\n",
     "            # the target countdown stops, and the protocol goes back to phase 1\n",
-    "            if (stopInTarget-startInTarget) >= targetDuration:\n",
+    "            if (stopInTarget-startInTarget) >= cfg['target_duration']:\n",
     "                trialCounter = trialCounter+1\n",
     "                randomX = 9000\n",
     "                randomY = 9000\n",
@@ -1016,8 +982,8 @@
     "    # Writes a new row to the protocol\n",
     "    log_frame_data([\n",
     "        frameCounter, (time.time()-expTime), expPhase, \n",
-    "        x, y, startX, startY, startRadius, targetX, targetY, \n",
-    "        targetRadius, trialCounter, percentCorrect, soundPlayed, \n",
+    "        x, y, cfg['start_x'], cfg['start_y'], cfg['start_radius'], targetX, targetY, \n",
+    "        cfg['target_radius'], trialCounter, percentCorrect, soundPlayed, \n",
     "        commonCycle, target2X, target2Y, target3X, target3Y, \n",
     "        target4X, target4Y, target5X, target5Y\n",
     "    ])\n",
@@ -1031,7 +997,6 @@
     "out.release()\n",
     "stream.stop()\n",
     "cv2.destroyAllWindows()\n",
-    "workbook.close()\n",
     "board.exit()                              \n",
     "\n"
    ]