<jupyter_start><jupyter_text>Ant Path DetectionThe purpose of this tool is to extract the path that a single ant takes in navigating its way across a surface. This program takes in a vido and generates a position file for use in MATLAB. For the path extraction to be successful, there are several important actions that must be taken. 1. The video must first be cropped appropriately so that the ant's path does not intersect any object that moved in the video, including people. 2. Next, once the extracted path image is generated, the user must erase any other dark content in the image. This may be somewhat difficult and require trial and error. The edited image will be uploaded, and then the points will be generated. 3. If there are points away from the ant path, this means that photo must be edited again (to remove the area with the points) and reuploaded. The points are an approximation of the ant path.   Video InstructionsHere are the instructions for uploading the video. Note that to upload a file you look at the four vertical icons on the left, click the bottom one several times, and then, from of the three horizontal icons that appear, click the leftmost one with the arrow.1. See where movement intersects the full ant path.2. Cut out up until there is no interfering movement.3. Cut out everything after the ant leaves the board.4. Create a zip file with the video and upload it.  Execution InstructionsClick each of the black circles with play buttons in them. There are some where you will have to wait for it to complete.<jupyter_code># install components not present in Colab by default
!apt-get update
!apt install imagemagick
!apt install ffmpeg
!pip3 install scikit-image
# import Python packages 
import subprocess
import os
import glob
import math 
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from sklearn.cluster import mean_shift
import cv2

from google.colab import files
frame_rate = "25" #@param ["10","15","20", "25"]
frame_rate = int(frame_rate)
# the cropped + zipped video file you uploaded
video_file = glob.glob('*.zip')

# get the video's name and extension
video_name = video_file[0].split('/')[-1].split('.')[0]
ext = video_file[0].split('/')[-1].split('.')[1]

# unzip the upload zip file
subprocess.run(['unzip', video_file[0]])

# produce 15 frame image data from the video
subprocess.run(['ffmpeg', '-i', video_name+'.'+ext, '-r', f'{frame_rate}', '-q:v', '2', '-f', 'image2', f'./{video_name}_%d.jpeg'])

# create img directory again
if os.path.isdir(f'new_vi') == True:
  subprocess.run(['rm','-rf','new_vi'])
subprocess.run(['mkdir','new_vi'])

# renumber the images produced
imgs = glob.glob(f'*.jpeg')
largest_img = max([len(img.split('.')[0].split('_')[1]) for img in imgs])
for img in imgs:
  img_num = img.split('.')[0].split('_')[1]
  zeros = largest_img - len(img_num)
  new_num = ''.join(['0']*zeros)+img_num
  new_img = img.split('.')[0].split('_')[0]+'_'+str(new_num)+'.jpeg'
  subprocess.run(['mv', img, f'./new_vi/{new_img}'])

# foresground setup
c1 = ['convert', '-density','300']
imgs = sorted(glob.glob('./new_vi/*.jpeg'))
if len(imgs) % 2 != 0: # make file count even
  imgs = imgs[:-1]

# create img directory again
if os.path.isdir(f'r_imgs') == True:
  %rm -rf r_imgs
%mkdir r_imgs

# step through 2 files at a time, generate the difference
for index in range(0, len(imgs), 2):
  c2 = ['-compose','difference','-composite','-colorspace','Gray']
  name_1st = './r_imgs/'+'result'+imgs[index].split('/')[-1].split('.')[0].split('_')[1]+'.jpeg'
  name_2nd = './r_imgs/'+'result'+imgs[index+1].split('/')[-1].split('.')[0].split('_')[1]+'.jpeg'
  c2.append(name_1st)
  c2.append(name_2nd)
  try:
    command = c1 + [imgs[index], imgs[index+1]] + c2
  except IndexError:
    pass
  subprocess.run(command)

imgs = list(filter(lambda elt: 'result' in elt, sorted(glob.glob('./r_imgs/*.jpeg'))))
command_final = ['convert', '-compose','lighten', imgs[0]]
remaining_imgs = []
file_name = video_name+'.jpeg'
for img in imgs[1:]:
  remaining_imgs.append(img)
  remaining_imgs.append('-composite')
remaining_imgs.append(file_name)
command = command_final + remaining_imgs
subprocess.run(command)

# remove lesser image differences
img = cv2.imread(file_name)
T, threshInv = cv2.threshold(img, 55, 255, cv2.THRESH_BINARY)
invIMG = file_name.split('.')[0]+'_inv.jpeg'
cv2.imwrite(invIMG, threshInv)

# download file
files.download(invIMG)<jupyter_output><empty_output><jupyter_text>Next StepSo, the generated file has just been downloaded. Now is it time to remove the other white regions which are not part of the ant path using your photo edit tool of choice. Do this and reupload the file with the SAME name. Remove the shadows from the ant path. For this next part, you will choose a number of points to approximate the ant path. Once you run the code chunk, **observe the outputted image** and see if there are any points flowing in space. If there are such points, go back and edit the photo to remove these, and then reupload the photo, again with the same name.<jupyter_code>#subprocess.run(['convert',f'{invIMG}', '-resize', '75%',  f'{invIMG}'])
img = Image.open(invIMG)

arr = np.array(img.convert('L')).T[:,::-1]
# get indices where there line is the pixel values is dark, ie <100
indices = np.argwhere(arr > 200)
# you only need to run this once
print('INDEX : NUM OF POINTS')
for x in np.arange(25,1,-2):
    print('{:.2f}: '.format(x), end='')
    print(len(mean_shift(indices, bandwidth=x)[0]))<jupyter_output><empty_output><jupyter_text>Play around with editing the points below and seeing how accurate it is or whether there are any defects<jupyter_code>index_value = 7 #@param {type:"slider", min:1, max:40, step:1}

points, labels = mean_shift(indices, bandwidth=index_value)

from matplotlib import image
data = image.imread(invIMG)

# the points will be mirrored, but this is okay
plt.imshow(data, origin='lower')
plt.scatter(points[:,0], points[:,1])
# create csv file
max_size = max([max(points[:,0]), max(points[:,1])])
print(max_size)
name = file_name.split('.')[0]
spaces = ' '*(len(str(round(max_size)))+1)
with open(f'{name}.pos', 'w') as f:
  f.write('Object\n')
  f.write(f'X{spaces}Y\n')
  for (x,y) in zip(points[:,0], points[:,1]):
    f.write(f'{round(x)}  {round(y)}\n')
files.downloadf'{name}.pos')<jupyter_output>2438.711111111111<jupyter_text>Final StepIf you are done with everything and want to upload a new video, click the last play button. Also, you will not need to re-run the first two play buttons of this program when you restart the process.<jupyter_code>%rm -r *<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13678178253657064, 'fraction_numerical': 0.018096817976172522, 'mean_word_length': 5.034576888080073, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '650008', 'license': 'MIT', 'n_tokens_mistral': 2235, 'n_tokens_neox': 2159, 'n_words': 781, 'path': 'ants.ipynb', 'repo_name': 'tmartin2/ant-tracking-kamhilab', 'size': '6631'}