In [17]:
from PIL import Image
import numpy as np
import pandas as pd

import sklearn as sk
from sklearn import cluster
from sklearn import linear_model
from scipy.optimize import minimize

from sklearn.cluster import KMeans

import itertools
import os
from itertools import cycle

import scipy.stats as stats
from scipy.misc import factorial

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab

import time
import pylab as pl
from IPython import display

import seaborn as sns

import cv2

%matplotlib inline

sns.set_style('whitegrid')
sns.set_context('poster')

Initial boilerplate to extract the data from the .mov files in connected worlds


In [2]:
y_max = 1080 - 864
x_max = 384

def load_image( infilename ) :
    img = Image.open(infilename)
    img.load()
    data = np.asarray( img, dtype="int32" )
    return data

def save_image( npdata, outfilename ) :
    img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
    img.save( outfilename )

In [3]:
def extract_boundary(original,hsv_image, lower, upper, flag):
    # need end points of the boundary too
    mask = cv2.inRange(hsv_image, lower, upper)
    # Bitwise-AND mask and original image
    res = cv2.bitwise_and(original,original,mask= mask)
    #boundaries in gray scale
    gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
    # Otsu's thresholding and gaussian filtering  to make the logs white and the background black for better detection
    ret2,th2 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    # Otsu's thresholding after Gaussian filtering
    blur = cv2.GaussianBlur(gray,(5,5),0)
    #logs will be white in th3
    ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    if(flag==1):
        black, extLeft, extRight, cx,cy = find_contour(th3,original)
        return black,extLeft,extRight,cx,cy
    return th3   

#just identify water flow path for drawing graphs   
def detect_water(min_video_frame):
    hsv = cv2.cvtColor(min_video_frame, cv2.COLOR_BGR2HSV)
    # define range of green/yellow color in HSV
    lower_green = np.array([29,86,6])
    upper_green = np.array([64,255,255])
    th3 = extract_boundary(min_video_frame,hsv,lower_green, upper_green,0)    
    store = th3
    # morphing to get the skeletal structure/ medial line of the water flow    
    size = np.size(th3)    
    skel = np.zeros(th3.shape,np.uint8)    
    element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
    done = False
 
    while(not done):
        eroded = cv2.erode(th3,element)
        temp = cv2.dilate(eroded,element)
        temp = cv2.subtract(th3,temp)
        skel = cv2.bitwise_or(skel,temp)
        th3 = eroded.copy()
 
        zeros = size - cv2.countNonZero(th3)
        if zeros==size:
            done = True
    return store,skel

def detect_logs(min_video_frame):
    hsv = cv2.cvtColor(min_video_frame, cv2.COLOR_BGR2HSV)
    # define range of blue color in HSV
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])  
    
    th3 = extract_boundary(min_video_frame,hsv,lower_blue, upper_blue,0)    

    #smooth the logs (current version very fat lines)
    image ,contours, heirarchy = cv2.findContours(th3,1,2)#cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    
#     print(contours)
    
    #Draw log contour + bonding rects
    colored = cv2.cvtColor(image,cv2.COLOR_GRAY2BGR) 
    count =0    
    black = np.zeros(colored.shape)
    centers=[]
    for contour in contours:
        coord_points = np.array([[p[0][0],p[0][1]] for p in contour])
        
        if len(coord_points) < 10:
            continue
            
        # TODO: if contour is really long we need to split it up
        
        mu = np.mean(coord_points, axis=0)
        cov_var = np.cov(coord_points.T)
        
        angle = np.arctan(np.linalg.eig(cov_var)[0][1]/np.linalg.eig(cov_var)[0][0])

        r, theta = convert_rec_to_polar(mu[0],y_max-mu[1])
#         image = cv2.circle(black,(cx,cy),2,(0,255,0),4)
        centers.append([r,theta,angle])

    return image,centers

In [4]:
def convert_rec_to_polar(x,y):
    assert x != 0
    theta = np.tan(y/x)
    r = np.sqrt(x**2 + y**2)
    return r, np.arctan(y/x)

def update_centers(new_sample, mu, cov):
    if mu == None:
        return np.mean(new_sample, axis=0)
    
    n = len(new_sample)
    mu_new = np.mean(new_sample, axis=0)
    sigma0_inv = np.cov(new_sample.T)
    sigma_inv = np.linalg.pinv(cov)
    
    mu_update = np.linalg.pinv(sigma_inv + n*sigma0_inv).dot(
                    sigma_inv.dot(mu) + n*sigma0_inv.dot(mu_new) )
    sigma_update = np.linalg.pinv(sigma_inv + n*sigma0_inv)
    
    return (mu_update, sigma_update)

In [5]:
cap = cv2.VideoCapture('./2017-09-07T10_39_18-0.mov')
count = 0
log_centers = []
mu, cov = None, None
while cap.isOpened():
    ret,frame = cap.read()

    if ret==True:
        store, skel = detect_water(frame[864:1080,0:384])
        logs,centers = detect_logs(frame[864:1080,0:384])   
        cv2.imwrite("frames/frame_log%04d.jpg" % count, logs)
        count = count + 1
        log_centers.append(centers)
    else:
        # The next frame is not ready, so we try to read it again
        cap.set(1, count-1)
        print("something not working")
        # It is better to wait for a while for the next frame to be ready
        cv2.waitKey(1000)

    if cv2.waitKey(10) == 27:
        break
    if cap.get(1) == cap.get(7):
        # If the number of captured frames is equal to the total number of frames,
        # we stop
        break
    if count >= 20:
        break
        
cap.release()

In [6]:
def line_centroid(r, theta1):
    x = r * np.cos(theta1)
    y = r * np.sin(theta1)
    return (x,y)

def log_points(r, theta1, theta2, length=np.arange(-5,5,0.5)):
        (x,y) = line_centroid(r, theta1)
        points = np.array([[l * np.cos(theta2) + x, l * np.sin(theta2) + y] for l in length])
        return points

In [7]:
points = [log_points(p[0],p[1],p[2]) for p in log_centers[3]]

fig = plt.figure(figsize=(8,3))
for p in points:
    plt.plot(p[:,0], p[:,1])
plt.xlim([0,x_max])
plt.ylim([0,y_max])
plt.show()


K-Means clustering to detect logs

Here I use K-means to cluster the log data to try and get a reasonably noise free representation of the $(r, \theta_1, \theta_2)$ coordinates of the log's positions.


In [11]:
ret,frame = cap.read()

def detect_logs(frame):
    min_video_frame = frame[864:1080,0:384]
    hsv = cv2.cvtColor(min_video_frame, cv2.COLOR_BGR2HSV)
    
    # define range of blue color in HSV
    lower_blue = np.array([110,50,50])
    upper_blue = np.array([130,255,255])  
    
    th3 = extract_boundary(min_video_frame,hsv,lower_blue, upper_blue,0)    

    #smooth the logs (current version very fat lines)
    image ,contours, heirarchy = cv2.findContours(th3,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    
    colored = cv2.cvtColor(image,cv2.COLOR_GRAY2BGR)
    return colored

In [12]:
# cap = cv2.VideoCapture('/Volumes/Seagate Backup Plus Drive/connected_worlds_water/water_level_4/2017-09-19T15_16_53-0.mov')

In [13]:
import copy
ret,frame = cap.read()

cap = cv2.VideoCapture('./2017-09-19T10_01_14-0.mov')

kmeans=KMeans(n_clusters=7)
main_mu = []
k = 0
log_p_filters = []
cluster_means = []
mu_old = []

while cap.isOpened():
    ret,frame = cap.read()
    logs = detect_logs(frame)

    _2d = []
    for i,row in enumerate(logs):
        for j, col in enumerate(row):
            if np.sum(col) > 0:
                _2d.append([i,j])

    _2d = np.array(_2d)
    
    # some images are coming through blank
    if len(_2d) < 20:
        continue
        
    kmeans.fit(X=_2d)

    clusters=kmeans.fit_predict(X=_2d)
    new_mus = []
    
    ordered_mus = [None]*7
    for i in range(7):
        samples = _2d[clusters == i]
        mu = samples.mean(axis=0)
        
        if len(mu_old) > 0:
            movement = np.argmin(np.linalg.norm(np.subtract(np.array(mu_old), mu), axis=1))
            mu = (np.array(mu) + np.array(mu_old[movement]))/2
#             mu = mu_old[movement]
            mu_old[movement] = [np.inf, np.inf]
    
#             ordered_mus[movement] = mu
        
        new_mus.append(mu)
#         pl.scatter(mu[0], mu[1], c='r', s=100, zorder=100)
    new_mus = np.array(new_mus)
    if k == 0:
        ordered_mus = copy.deepcopy(new_mus)
    else:
        best_order = copy.deepcopy(new_mus)
        min_cost = np.inf
        for perm in itertools.permutations(range(7), 7):
            c = np.sum([(x1-x2)**2+(y1-y2)**2 for ((x1,y1),(x2,y2)) in zip(main_mu[k-1], new_mus[np.array(perm)])])
            if c < min_cost:
                min_cost = c
                best_order = copy.deepcopy(new_mus[np.array(perm)])

        ordered_mus = best_order
        
    main_mu.append(ordered_mus)
    
    k+=1
    if k % 50 == 0:
        print(k)
#         break


50
100
150
200
250
300
350
400
450
500
550
600
650
700
750
800
850
900
950
1000
1050
1100
1150
1200
1250
1300
1350
1400
---------------------------------------------------
TypeError         Traceback (most recent call last)
<ipython-input-13-13540ba920c2> in <module>()
     11 while cap.isOpened():
     12     ret,frame = cap.read()
---> 13     logs = detect_logs(frame)
     14 
     15     _2d = []

<ipython-input-11-73b0cab38c8a> in detect_logs(frame)
      2 
      3 def detect_logs(frame):
----> 4     min_video_frame = frame[864:1080,0:384]
      5     hsv = cv2.cvtColor(min_video_frame, cv2.COLOR_BGR2HSV)
      6 

TypeError: 'NoneType' object is not subscriptable

In [14]:
main_mu = np.array(main_mu)
len(main_mu[:,0,0])


Out[14]:
1425

In [18]:
## construct dataframe from logs
df = pd.DataFrame()
for i in range(7):
    df['x_%i'%i] = main_mu[:,i,0]
    df['y_%i'%i] = main_mu[:,i,1]
df.head(50)


Out[18]:
x_0 y_0 x_1 y_1 x_2 y_2 x_3 y_3 x_4 y_4 x_5 y_5 x_6 y_6
0 94.028037 284.289720 180.862903 65.016129 172.195876 156.773196 102.091743 77.458716 125.934959 225.861789 105.155340 263.990291 116.091743 244.825688
1 94.056075 284.149533 180.862903 65.016129 172.195876 156.773196 102.091743 77.458716 126.000000 225.702479 105.346154 263.721154 116.284404 244.477064
2 94.056075 284.149533 180.862903 65.016129 172.195876 156.773196 102.091743 77.458716 125.934959 225.861789 105.291262 263.815534 116.129630 244.731481
3 94.056075 284.149533 180.862903 65.016129 172.195876 156.773196 102.091743 77.458716 125.934959 225.861789 105.291262 263.815534 116.129630 244.731481
4 93.990476 284.361905 180.862903 65.016129 172.195876 156.773196 102.091743 77.458716 125.903226 225.943548 104.891089 264.346535 115.909910 245.180180
5 93.732484 285.114650 181.807339 64.000000 172.307692 155.723077 102.092025 77.564417 126.608392 223.902098 106.315315 261.396396 116.442478 242.752212
6 93.950920 285.343558 182.598214 63.526786 172.273504 155.726496 102.131579 77.526316 125.972028 224.944056 104.484375 264.398438 115.318182 244.645455
7 94.081761 284.628931 182.494118 63.470588 172.282828 155.575758 101.894309 77.869919 125.788462 224.288462 105.166667 263.800000 115.728070 244.745614
8 93.933775 284.496689 181.690722 64.000000 172.281818 155.790909 102.097222 77.625000 125.925000 224.206250 105.815789 262.885965 116.070796 244.398230
9 93.993590 284.192308 181.483871 63.978495 171.603175 156.769841 102.041667 77.694444 126.066667 224.293333 106.822034 261.432203 116.475728 243.533981
10 93.744966 284.966443 181.693878 63.938776 171.772059 155.772059 102.133333 77.586667 126.482993 224.074830 106.252101 262.361345 116.151261 244.151261
11 93.835526 284.769737 181.757576 63.919192 172.068182 155.446970 102.133333 77.586667 126.435374 224.809524 106.096774 262.459677 116.416667 243.850000
12 93.846154 284.621795 181.589474 64.031579 171.354167 156.784722 102.041667 77.694444 126.617021 224.595745 106.299145 262.230769 116.330435 243.991304
13 93.697987 285.228188 181.688172 64.010753 171.666667 157.113636 102.041667 77.694444 126.397260 225.102740 105.571429 263.126050 115.939130 244.843478
14 93.773333 284.893333 181.732673 64.009901 172.299145 155.786325 102.133333 77.586667 126.310345 224.937931 105.959016 262.688525 116.210084 244.310924
15 93.688406 285.942029 181.766990 63.980583 172.454545 155.520661 102.133333 77.586667 126.143791 225.228758 103.000000 266.225000 114.948148 246.555556
16 93.935065 284.616883 181.607843 64.254902 172.243697 155.823529 102.041667 77.694444 126.420690 224.937931 105.801653 262.925620 115.964912 244.754386
17 93.673333 285.140000 181.598039 64.303922 171.800000 156.768000 102.041667 77.694444 126.402778 225.111111 105.975207 262.710744 116.126050 244.403361
18 93.823129 284.700680 181.247423 64.628866 171.428571 156.736842 102.028777 77.683453 126.333333 225.462585 105.524272 263.067961 115.844828 244.974138
19 94.012739 284.554140 181.464646 64.060606 171.875912 156.394161 102.041667 77.694444 126.510490 224.804196 105.631148 263.122951 116.156522 244.391304
20 93.818792 284.939597 181.821053 63.947368 172.559055 155.708661 102.041667 77.694444 126.300000 225.346667 105.207207 263.783784 115.423729 245.652542
21 93.750000 285.125000 181.614583 64.052083 172.437500 156.320312 102.041667 77.694444 126.434483 225.055172 105.516949 263.279661 115.983333 244.841667
22 93.673759 285.602837 181.702970 63.980198 172.409449 156.039370 102.133333 77.586667 126.755245 224.349650 103.549020 265.901961 117.339623 242.537736
23 93.323529 288.823529 181.483871 63.978495 172.234234 155.837838 102.041667 77.694444 126.984496 223.488372 98.750000 271.718750 119.705882 240.957983
24 94.344828 285.117241 181.557692 64.375000 172.085470 156.162393 102.041667 77.694444 126.229008 224.580153 107.907216 261.154639 126.116883 247.701299
25 95.363057 284.617834 181.852941 63.931373 172.239669 156.330579 102.041667 77.694444 125.724138 225.331034 109.097561 262.048780 125.622222 247.988889
26 93.516393 288.204918 182.293103 63.801724 172.274809 155.969466 102.109091 77.727273 126.193548 224.729032 106.849057 277.490566 126.103175 246.857143
27 93.421488 288.198347 181.740741 64.037037 172.301587 155.722222 102.006135 77.809816 126.335570 224.395973 107.626866 276.194030 124.630631 245.243243
28 93.505376 289.634409 181.715686 63.911765 172.360000 155.376000 101.783133 78.018072 126.944444 223.500000 111.104000 271.104000 121.825806 249.406452
29 93.506329 282.354430 181.788462 63.884615 172.305344 155.541985 102.350877 77.713450 132.847368 228.957895 109.723404 273.829787 118.737705 253.926230
30 91.838926 272.416107 181.679612 63.990291 172.210084 155.747899 102.270115 77.977011 135.459016 220.491803 110.451923 271.846154 122.485030 248.814371
31 96.492611 274.024631 182.000000 64.000000 172.176991 155.840708 102.588235 77.670588 137.738462 220.661538 117.403670 257.009174 127.851240 241.429752
32 100.867257 276.955752 182.614035 63.684211 172.285714 155.750000 102.059172 78.402367 137.555556 221.523810 116.664122 259.038168 128.287879 241.636364
33 87.195122 276.601626 182.289474 63.938596 172.296610 155.737288 102.209877 77.895062 135.128205 228.083333 109.623762 274.217822 118.873134 253.626866
34 86.750000 276.629310 181.460000 64.180000 172.234234 155.837838 102.313253 77.939759 135.784615 226.353846 106.728571 276.385714 127.101449 243.188406
35 85.960784 276.578431 181.204082 64.255102 172.456000 155.280000 102.384181 77.745763 135.326923 227.384615 102.855856 276.045045 121.366197 249.464789
36 85.029412 277.098039 181.340000 64.220000 172.274809 155.503817 102.372881 77.717514 136.040323 223.258065 99.510417 275.395833 123.580952 247.209524
37 84.172414 276.643678 181.669903 64.087379 172.250000 155.725000 102.186667 77.446667 130.677419 223.677419 98.813187 275.648352 121.341040 250.179191
38 91.163636 276.260606 181.087912 64.461538 172.234234 155.837838 102.041958 77.811189 122.806122 221.755102 113.678571 266.328571 122.902256 248.413534
39 88.724490 276.459184 181.492754 64.159420 172.160920 155.977011 101.843478 78.008696 121.384615 221.807692 120.155172 266.724138 124.321839 246.494253
40 88.875969 276.457364 181.628205 64.179487 172.692308 155.529915 101.952000 77.792000 103.979695 217.888325 119.152542 267.977401 124.421569 246.509804
41 91.115854 275.304878 181.291667 64.375000 172.245763 155.838983 102.231788 77.417219 100.047368 215.584211 118.335052 268.402062 124.517857 246.071429
42 91.443787 275.130178 181.614583 64.093750 172.234234 155.837838 102.000000 78.044586 91.233503 207.477157 117.220000 268.820000 126.507246 243.550725
43 90.343066 275.335766 181.418367 64.336735 172.243697 155.789916 102.285714 77.761905 87.329412 205.111765 114.386667 269.660000 124.408451 246.845070
44 89.098361 276.000000 181.610000 63.920000 172.291667 155.641667 101.846154 78.402367 74.808383 196.035928 115.911565 269.346939 120.993671 241.544304
45 88.959016 275.934426 181.742857 64.019048 172.228346 155.496063 102.018405 77.748466 73.568345 191.489209 115.375000 269.513889 120.500000 237.500000
46 92.824561 275.017544 181.798165 64.183486 172.211382 155.756098 101.792899 78.171598 74.148148 191.437037 119.029268 268.151220 118.403101 229.255814
47 93.005650 275.067797 181.629630 64.194444 171.907692 156.192308 102.196078 77.594771 74.353383 191.390977 119.767677 267.681818 118.391304 228.195652
48 92.982249 275.153846 182.401709 63.786325 172.301587 155.619048 102.078313 77.783133 74.261194 191.373134 118.596939 268.020408 118.060150 228.774436
49 88.330508 277.550847 181.809091 64.145455 172.213115 155.696721 102.259036 77.638554 72.064286 190.821429 119.161905 268.109524 119.520661 225.512397

In [23]:
df.diff()


Out[23]:
x_0 y_0 x_1 y_1 x_2 y_2 x_3 y_3 x_4 y_4 x_5 y_5 x_6 y_6
0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0.028037 -0.140187 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.065041 -0.159309 0.190814 -0.269137 0.192661 -0.348624
2 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.065041 0.159309 -0.054892 0.094380 -0.154774 0.254417
3 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
4 -0.065599 0.212372 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -0.031734 0.081760 -0.400173 0.531001 -0.219720 0.448699
5 -0.257992 0.752745 0.944436 -1.016129 0.111816 -1.050119 0.000281 0.105702 0.705166 -2.041450 1.424226 -2.950138 0.532568 -2.427968
6 0.218436 0.228909 0.790875 -0.473214 -0.034188 0.003419 0.039554 -0.038101 -0.636364 1.041958 -1.830940 3.002041 -1.124296 1.893242
7 0.130841 -0.714627 -0.104097 -0.056197 0.009324 -0.150738 -0.237270 0.343603 -0.183566 -0.655594 0.682292 -0.598437 0.409888 0.100159
8 -0.147986 -0.132242 -0.803396 0.529412 -0.001010 0.215152 0.202913 -0.244919 0.136538 -0.082212 0.649123 -0.914035 0.342726 -0.347384
9 0.059815 -0.304381 -0.206851 -0.021505 -0.678644 0.978932 -0.055556 0.069444 0.141667 0.087083 1.006244 -1.453762 0.404932 -0.864250
10 -0.248623 0.774135 0.210007 -0.039719 0.168884 -0.997782 0.091667 -0.107778 0.416327 -0.218503 -0.569933 0.929141 -0.324468 0.617280
11 0.090560 -0.196706 0.063698 -0.019584 0.296123 -0.325089 0.000000 0.000000 -0.047619 0.734694 -0.155327 0.098333 0.265406 -0.301261
12 0.010628 -0.147942 -0.168102 0.112387 -0.714015 1.337753 -0.091667 0.107778 0.181647 -0.213779 0.202371 -0.228908 -0.086232 0.141304
13 -0.148167 0.606393 0.098698 -0.020826 0.312500 0.328914 0.000000 0.000000 -0.219761 0.506995 -0.727717 0.895281 -0.391304 0.852174
14 0.075347 -0.334855 0.044501 -0.000852 0.632479 -1.327312 0.091667 -0.107778 -0.086915 -0.164809 0.387588 -0.437526 0.270954 -0.532554
15 -0.084928 1.048696 0.034317 -0.029318 0.155400 -0.265664 0.000000 0.000000 -0.166554 0.290827 -2.959016 3.536475 -1.261936 2.244631
16 0.246659 -1.325146 -0.159147 0.274319 -0.210848 0.302868 -0.091667 0.107778 0.276899 -0.290827 2.801653 -3.299380 1.016764 -1.801170
17 -0.261732 0.523117 -0.009804 0.049020 -0.443697 0.944471 0.000000 0.000000 -0.017912 0.173180 0.173554 -0.214876 0.161138 -0.351025
18 0.149796 -0.439320 -0.350617 0.324944 -0.371429 -0.031158 -0.012890 -0.010991 -0.069444 0.351474 -0.450935 0.357217 -0.281223 0.570777
19 0.189610 -0.146540 0.217224 -0.568260 0.447341 -0.342682 0.012890 0.010991 0.177156 -0.658389 0.106876 0.054990 0.311694 -0.582834
20 -0.193947 0.385457 0.356406 -0.113238 0.683143 -0.685499 0.000000 0.000000 -0.210490 0.542471 -0.423940 0.660833 -0.732793 1.261238
21 -0.068792 0.185403 -0.206469 0.104715 -0.121555 0.611651 0.000000 0.000000 0.134483 -0.291494 0.309742 -0.504123 0.559605 -0.810876
22 -0.076241 0.477837 0.088387 -0.071885 -0.028051 -0.280942 0.091667 -0.107778 0.320762 -0.705522 -1.967930 2.622300 1.356289 -2.303931
23 -0.350229 3.220693 -0.219099 -0.001703 -0.175215 -0.201532 -0.091667 0.107778 0.229251 -0.861278 -4.799020 5.816789 2.366260 -1.579753
24 1.021298 -3.706288 0.073821 0.396505 -0.148764 0.324555 0.000000 0.000000 -0.755488 1.091781 9.157216 -10.564111 6.411001 6.743316
25 1.018230 -0.499407 0.295249 -0.443627 0.154199 0.168185 0.000000 0.000000 -0.504870 0.750882 1.190344 0.894141 -0.494661 0.287590
26 -1.846664 3.587084 0.440162 -0.129648 0.035140 -0.361113 0.067424 0.032828 0.469410 -0.602002 -2.248504 15.441786 0.480952 -1.131746
27 -0.094906 -0.006571 -0.552363 0.235313 0.026778 -0.247243 -0.102956 0.082543 0.142022 -0.333059 0.777809 -1.296536 -1.472544 -1.613900
28 0.083889 1.436061 -0.025054 -0.125272 0.058413 -0.346222 -0.223002 0.208256 0.608874 -0.895973 3.477134 -5.090030 -2.804824 4.163208
29 0.000953 -7.279978 0.072775 -0.027149 -0.054656 0.165985 0.567745 -0.304622 5.902924 5.457895 -1.380596 2.725787 -3.088102 4.519778
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1395 -0.511737 0.360751 0.842493 -1.860420 0.550992 0.063874 -0.095981 0.079091 0.153363 -0.108500 0.041814 -0.297307 -0.126966 0.010956
1396 -0.308776 0.191044 -0.696519 1.538457 -0.291419 -0.047453 -0.346980 -0.278563 0.176515 0.314394 -0.941176 1.441176 -0.052741 0.027270
1397 0.429208 -0.045708 -0.357571 0.369989 -0.462710 -0.177902 0.400908 0.213364 -0.284563 -0.138388 1.148302 -1.571665 0.065194 0.041878
1398 -0.275362 0.064460 0.565527 -0.953134 0.522129 0.105355 0.183593 0.251481 0.501230 0.021721 -0.195712 -0.032373 0.092198 -0.051706
1399 -0.044776 0.149254 -0.424270 0.704383 -0.362195 -0.307681 -0.327423 -0.393608 -0.320614 -0.149561 0.481456 -0.622343 -0.320258 0.081185
1400 0.982276 -0.326259 -0.143628 0.386233 0.122724 0.280772 0.539770 0.491724 -0.250386 -0.031439 1.599567 -0.461760 0.180723 -0.118976
1401 -0.623214 -0.104018 0.562556 -1.150444 0.344373 0.173616 -0.076049 -0.202887 0.734938 0.086088 -1.414286 0.915873 0.250000 0.090909
1402 0.497308 -0.131263 -0.333333 0.222222 -1.228090 -0.528019 -0.012587 -0.039559 -0.995036 -0.173178 0.140476 -0.340476 -0.186416 0.028311
1403 1.060201 -0.285953 0.227205 0.067642 0.988155 0.364667 -0.415090 -0.155432 0.434064 0.104106 0.778986 -0.518116 0.052023 0.052023
1404 -0.538462 0.057692 -0.262336 0.502619 -0.364870 -0.057566 0.310623 0.257265 -0.204282 -0.038210 -0.555867 0.698223 0.028071 -0.074978
1405 -0.317460 0.099206 -0.191721 0.911220 -0.006098 0.060625 0.722344 0.336142 -0.766788 -0.131428 -0.106452 0.840726 -0.067208 -0.083029
1406 -0.359157 0.078654 0.768316 -1.556705 0.547521 -0.013323 -1.227106 -0.604396 1.115137 0.305231 0.055556 -0.548611 -0.029133 -0.047999
1407 -2.050333 1.121785 46.838058 79.989306 10.388526 2.032770 0.506752 -0.142857 4.122411 0.953390 -12.299673 27.111111 -0.107218 0.123835
1408 -1.945226 1.497187 -1.173927 -0.554537 -0.822410 -0.180497 -0.466459 0.021978 -0.541847 -0.159091 -0.163575 -0.338462 -0.218908 0.187443
1409 5.970422 -3.713499 -46.552817 -77.826979 -10.065391 -2.173644 -0.101167 -0.125071 -3.470973 -0.860140 15.828904 -30.676690 0.036364 -0.151515
1410 -4.048246 2.642857 -0.804217 1.915559 0.361418 0.513121 0.059839 0.287875 -0.235546 -0.191554 -6.571212 8.565152 0.623927 -0.161850
1411 1.416667 -1.130952 0.127134 -0.142570 -0.451699 -0.525619 0.167702 -0.011313 -0.235209 0.021654 1.685294 -2.902941 -0.305032 0.050085
1412 -2.459459 1.839447 -0.435417 1.479167 0.079914 0.545991 -0.294425 -0.197860 -0.050613 0.033148 -6.521008 12.803491 -0.076471 -0.013235
1413 -1.002805 0.444246 0.183488 -0.571759 0.393224 -0.010976 -2.001793 -0.902080 -0.141349 0.107664 0.026891 0.290627 0.058480 0.142544
1414 0.803728 -0.454134 -0.424884 1.246272 -0.358522 -0.215075 0.970211 0.452112 0.252460 -0.090570 -0.395938 0.985014 0.028226 -0.023324
1415 0.171811 -0.220519 -0.108604 -0.224513 0.024194 0.016129 1.622436 0.749359 0.153236 0.214286 -0.424784 0.694264 0.131686 -0.074679
1416 -0.470171 -0.020369 0.246208 -0.829916 -0.046774 -0.302595 -0.513660 -0.295619 0.206753 -0.096583 0.303230 -1.315191 -0.286187 0.193454
1417 0.215825 0.080973 -0.209384 1.229578 0.480992 0.316924 0.715743 0.385202 0.016949 0.076271 -0.426387 1.435277 -0.001169 -0.101500
1418 -0.138558 0.198082 0.010970 -0.620986 -0.288684 0.128226 -0.169019 0.001008 -0.134669 -0.286903 0.036036 0.030888 0.086717 0.006257
1419 -0.358075 0.093048 0.327497 -0.727223 0.252137 0.109117 0.753840 0.253456 0.610277 0.277470 0.508439 -2.153707 -0.041561 -0.047513
1420 0.805502 -0.419005 0.075305 0.269380 -0.283507 -0.225463 -1.354371 -0.756034 -0.675500 0.077364 0.624520 -0.013227 0.017927 -0.087885
1421 -0.158273 0.070137 0.071429 -0.333333 0.320312 0.265625 -0.913632 -0.289843 -0.500215 -0.246890 0.092531 -0.204494 0.110534 0.047880
1422 -0.236797 0.136797 -0.074230 0.250000 -0.289514 -0.442794 1.000284 0.333806 0.519751 0.019173 -0.256354 0.269136 0.005239 0.146691
1423 1.732536 -1.064115 -0.222136 0.486842 0.101288 0.255173 -0.012479 0.263755 0.154051 0.254701 -0.589969 1.718364 -0.183061 -0.101313
1424 -0.361785 0.125973 -0.163843 0.869322 0.169272 0.091054 1.048512 0.180917 -0.264857 -0.114286 0.293673 -0.101080 0.042868 -0.084701

1425 rows × 14 columns


In [43]:
diff_series = (df.diff().abs() > 5).sum(axis=1) > 2
# print(np.sum(diff_series)/len(diff_series))
diff_series.to_pickle(path='diff_series.pkl')
# diff_series.plot()
# diff_series.plot()
fig, ax = plt.subplots(1,1,figsize=(15,5))

for ix,v in diff_series.iteritems():
    if v:
        ax.axvline(ix, color='r', linestyle='-', lw=0.1)

ax.set_title('Action Events')
ax.yaxis.set_visible(False)
ax.set_xlabel('time (S)')
ax.grid(False)
plt.show()



In [41]:
fig,ax = plt.subplots(4,3,figsize=(15,15))
ax = ax.flatten()

cap = cv2.VideoCapture('./2017-09-19T10_01_14-0.mov')
k = 0
j = 0

while cap.isOpened():
    ret,frame = cap.read()
    logs = detect_logs(frame)
    if diff_series.ix[k]:
        ax[j].set_title('Timestep {}'.format(k))
        ax[j].imshow(frame[864:1080,0:384])
        ax[j].grid(False)
        ax[j].xaxis.set_visible(False)
        ax[j].yaxis.set_visible(False)
        j+=1
    if j >= 12:
        break
    k+=1


Using the Log Detection Module

The log detection module ../utils/log_detection.py is a class that will wrap all of the code that is used to detect the specific coordinates of the logs.


In [4]:
import os
import sys
import numpy as np
import pandas as pd
module_path = os.path.abspath(os.path.join('../utils/'))
if module_path not in sys.path:
    sys.path.append(module_path)
from log_detection import LogPosition

In [1]:
data_path = '/Volumes/Seagate Backup Plus Drive/connected_worlds_water/'
# interesting_file_path = 'water_level_3/2017-09-19T10_01_14-0.mov'
interesting_file_path = 'water_level_4/2017-09-19T15_16_53-0.csv'

# log_detector = LogPosition()
# log_detector.load_mov_file(data_path + interesting_file_path)
# log_detector.infer_log_positions_over_time()
# # log_detector.get_log_positions_DF()

In [2]:
# log_detector.get_actions()

In [165]:
x_sigma = 20
y_sigma = 4

def rotate(matrix, theta):
    rotation_transformation = np.array([[np.cos(theta), -np.sin(theta)],[np.sin(theta), np.cos(theta)]])
    return np.dot(matrix, rotation_transformation).real

class LogParticleFilter:
    
    def __init__(self, mu, cov_var):
        
        self.mu = mu
        self.cov_var = cov_var
        self.num_logs = 7
        
    def transition_model(self):
        
        angle = np.arctan(np.linalg.eig(self.cov_var)[0][1]/np.linalg.eig(self.cov_var)[0][0])
        gaussian = np.array([[x_sigma, 0],[0, y_sigma]])
        gaussian = rotate(gaussian, angle)
        self.cov_var = gaussian
        return True
    
    def filter_with_new_sample(self, new_sample):
        
        n = len(new_sample)
        try:
            probabilities = np.array([stats.multivariate_normal.pdf(s, mean=self.mu, cov=self.cov_var) for s in new_sample])
        except:
            probabilities = np.array([stats.multivariate_normal.pdf(s, mean=self.mu, cov=np.array([[x_sigma, 0],[0, y_sigma]])) for s in new_sample])

        high_probabs_args = np.argsort(probabilities)[n-n//self.num_logs:]
        
        self.mu = np.mean(new_sample[high_probabs_args], axis=0)
        self.cov_var = np.cov(new_sample[high_probabs_args].T)

In [45]:
cap = cv2.VideoCapture('./2017-09-19T10_01_14-0.mov')

ret,frame = cap.read()

fig, ax = plt.subplots(1,1,figsize=(8,6))
ax.imshow(frame[864:1080,0:384])
ax.grid(False)
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)


Human time stamped data

Here I have manually time stamped the actions in the system and plotted the resulting log configurations such that we can visualise the events as a change in log positions.


In [48]:
lap_times = [29,4,10,7,9,7,12,13,6,9,11,14,9,19,4,83]
lap_times = np.cumsum(lap_times)

In [51]:
fig, ax = plt.subplots(1,1,figsize=(15,5))
for i in lap_times:
    ax.axvline(i, color='r', linestyle='-', lw=1)

ax.set_title('Action Events')
ax.yaxis.set_visible(False)
ax.set_xlabel('time (S)')
ax.grid(False)
plt.show()



In [60]:
fig,ax = plt.subplots(4,4,figsize=(20,10))
ax = ax.flatten()

cap = cv2.VideoCapture('./2017-09-19T10_01_14-0.mov')
k = 0
j = 0

while cap.isOpened():
    ret,frame = cap.read()
    logs = detect_logs(frame)
    if k in lap_times:
        ax[j].set_title('Timestep {}'.format(k))
        ax[j].imshow(frame[864:1080,0:384])
        ax[j].grid(False)
        ax[j].xaxis.set_visible(False)
        ax[j].yaxis.set_visible(False)
        j+=1
    if j >= 16:
        break
    k+=1
    
ax[-1].grid(False)
ax[-1].xaxis.set_visible(False)
ax[-1].yaxis.set_visible(False)



In [125]:
data = pd.read_csv('./log-0-Free_Play_Session.csv')
data.columns = data.columns.str.strip()
data = data.ix[0:300]

fig, ax = plt.subplots(1,1,figsize=(10,4))

water_subset = data[data.columns[data.columns.str.contains('Water') & (~data.columns.str.contains('Bins|Waterfall|Floor|Mountain|Reservoir'))]]
water_subset[water_subset.columns[~water_subset.columns.isin(['Total_Water'])]].plot(ax=ax, color=['g','b','r','m'])

# plains water
ax.axvline(74,color='b', lw=1,alpha=0.8)
ax.axvline(105,color='b', lw=1,alpha=0.8)
ax.axvline(270,color='b', lw=1,alpha=0.8)

# desert water
ax.axvline(62,color='g', lw=1,alpha=0.8)
ax.axvline(102,color='g', lw=1,alpha=0.8)
ax.axvline(150,color='g', lw=1,alpha=0.8)

# jungle water
ax.axvline(48,color='r', lw=1,alpha=0.8)

# wetlands water
ax.axvline(15,color='m', lw=1,alpha=0.8)
ax.axvline(30,color='m', lw=1,alpha=0.8)

ax.legend(loc='upper center', bbox_to_anchor=(1.2, 0.75))

plt.grid(False)
plt.xlabel('time (s)')
ax.yaxis.set_visible(False)
plt.title('Biome Water Levels with Associated Important Changes Highlighted')
plt.show()



In [114]:
fig, ax = plt.subplots(4,1,figsize=(10,10))

plant_subset = data[data.columns[data.columns.str.contains('lv1|lv2|lv3|lv4') & (~data.columns.str.contains('Bins|Waterfall|Floor|Mountain|Reservoir|Dead'))]]
biomes = ['Desert','Plains','Jungle','Wetlands']
for i in range(4):
    
    plant_subset[plant_subset.columns[plant_subset.columns.str.contains(biomes[i])]].plot(ax=ax[i])
    ax[i].yaxis.set_visible(False)
    ax[i].grid(False)
    if i < 3: ax[i].xaxis.set_visible(False)
    
# plains plants
ax[1].axvline(168,color='black', lw=1,alpha=0.8)

# jungle water
ax[2].axvline(173,color='black', lw=1,alpha=0.8)

ax[i].set_xlabel('time (s)')
# plt.title('Biome Water Levels with Associated Important Changes Highlighted')
plt.show()



In [117]:
fig, ax = plt.subplots(4,1,figsize=(10,10))

plant_subset = data[data.columns[data.columns.str.contains('Creatures') & (~data.columns.str.contains('Bins|Waterfall|Floor|Mountain|Reservoir|Dead'))]]
biomes = ['Desert','Plains','Jungle','Wetlands']

for i in range(4):
    
    plant_subset[plant_subset.columns[plant_subset.columns.str.contains(biomes[i])]].plot(ax=ax[i])
    ax[i].yaxis.set_visible(False)
    ax[i].grid(False)
    if i < 3: ax[i].xaxis.set_visible(False)

ax[i].set_xlabel('time (s)')
# plt.title('Biome Water Levels with Associated Important Changes Highlighted')
plt.show()