-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmodel.py
More file actions
252 lines (232 loc) · 11.1 KB
/
model.py
File metadata and controls
252 lines (232 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
'''
Contains 2 primary
analyze: Performs Linear Regression Analysis the cropped portion of all the frames and outputs the
centre of mass(COM) data for and a plot of COM for furthur use
compute: Calculates frequency, change in angle per frame, total clockwise/counter-clockwise time
interval and no of frames and all else necessary outputs. Also outputs the finally analyzed
data in the form of CSV files and graphs
'''
import cv2
import numpy
import imgpros
from sklearn import linear_model
import math
import matplotlib.pyplot as plt
import csv
import utilities
#defining variables
slopes = []
tracedia =[]
lens = []
xcomlist2 = []
ycomlist2 = []
xcomlist = []
ycomlist = []
angles = []
def analyze():
'''
Calculates the slope of the regression line of the cropped region for each frame after thresholding
which is used by the compute function to calculate the change in angle per frame and the angular frequency.
Also calculates the diameter of the least fitting circle of the trace of the rotating cell which gives
us the length of the cell Other calculations include xcom and ycom of the the thresholded cell for each frame
'''
count = 0
#importing required variables from previous corresponding files
meta = utilities.meta
filename = utilities.filename
folder_path = utilities.folder_path
num_frames = utilities.num_frames
delay = utilities.delay
refPt = imgpros.refPt
trace = imgpros.trace
out_folder = utilities.out_folder
global slopes,lens,tracedia,xcomlist2,ycomlist2,xcomlist,ycomlist #defining global variales
prev_a = 0
addr = folder_path + '/img_000000'
ad = '_Default_000.tif'
while (count<num_frames): #looping over all frames
if meta == 0: #when metadata is not availbale
frame = cv2.imread(folder_path + filename.replace("00000",str("%05d" % count)))
else: #when metadata is available
frame = cv2.imread(addr+ str("%03d" % count)+ad)
frame = imgpros.threshold(frame)
orgimg= frame.copy()
cv2.rectangle(orgimg, refPt[0], refPt[1], (0, 255, 0), 2) #using rectangle function of cv2 library
frame = frame[refPt[0][1]:refPt[1][1], refPt[0][0]:refPt[1][0]] #definfing final frame coordinates
points = numpy.where(frame==0)
revP=[] #initializing variable revP
for i in range(len(points[0])):
revP.append([points[1][i],points[0][i]])
points=numpy.array(revP) #storing data in numpy array for easier analysis
xcom = numpy.mean(points[:,0]) #caluclting xcom by finding average
ycom = numpy.mean(points[:,1]) #caluclting ycom by finding average
xcomlist.append(xcom) #appending to xcomlist
ycomlist.append(ycom) #appending to ycom list
stDevX = numpy.std(points[:,0]) #calculating standard deviation using std function of numpy library
stDevY = numpy.std(points[:,1])
verticality = stDevY/stDevX # handle div by 0 cases
slope=0 #initializing slope to 0
regr = linear_model.LinearRegression() #calculating linear regression to find best fit line
if verticality<1: #in case the slope of line does not tend to 90 degrees
regr.fit(numpy.reshape([points[:,0]], (points.shape[0],1)), points[:,1])
m =math.atan(-regr.coef_) #since slope is not close to 90, taninv will work
slope =regr.coef_
c= regr.intercept_
else: #in case slope of line is close to 90 degrees
regr.fit(numpy.reshape([points[:,1]], (points.shape[0],1)), points[:,0])
slope = 1/regr.coef_
m =1.57 - math.atan(-regr.coef_) #since slope is close to 90 degrees, calculate cotinv instead of taninv
c= -regr.intercept_/regr.coef_
count+=1 #increases counter
slopes.append(m)
y1 = ycom-slope[0]*xcom
y2=slope[0]*(frame.shape[0]-xcom)
point2 = [frame.shape[0],y2+ycom]
point1 = [0,y1]
contours, heirarchy = cv2.findContours(frame, 1, 2) #calling findContours function of cv2 library
cnt = contours[0]
(xxx, yyy), radi = cv2.minEnclosingCircle(cnt)
center = (int(xxx), int(yyy)) #initializing variable for coordinates of centre
radi = int(radi) #initializing variable for radius
nframe = frame.copy()
lens.append(radi*2)
cv2.namedWindow('image',cv2.WINDOW_NORMAL) #calling namesWindow function of cv2 library
cv2.resizeWindow('image', 600,600) #calling resizeWindow function of cv2 library
frame[frame == 0] = 1
frame[frame == 255] = 0
frame[frame == 1] = 255
trace = numpy.maximum(frame,trace) #setting maximum coordinates as frame size
frame[frame == 0] = 1
frame[frame == 255] = 0
frame[frame == 1] = 255
contours, heirarchy = cv2.findContours(trace, 1, 2) #calling findContours function of cv2 library
cnt = contours[0]
(xx, yy), rad = cv2.minEnclosingCircle(cnt) #calling minEnclosingCircle function of cv2 library
center = (int(xx), int(yy))
rad = int(rad)
tracedia.append(rad*2)
if( (abs(y1)<1000) or (abs(y2)<1000) ):
cv2.line(frame,(int(point1[0]),int(point1[1])),(int(point2[0]),int(point2[1])),(0,255,0),1)
frame = cv2.resize(frame, (300, 300)) #calling resize function of cv2 library
printtrace = trace.copy()
printtrace = cv2.resize(printtrace,(300,300))
frame = numpy.concatenate((frame, printtrace), axis=0) #concatenating arrays using numpys inbuilt function
orgimg = cv2.resize(orgimg, (600, 600))
frame = numpy.concatenate((frame, orgimg), axis=1) #Resize image
cv2.imshow('image',frame)
cv2.waitKey(delay)
plt.scatter(xcomlist,ycomlist) #computing scatter plot using pyplot library
plt.title(utilities.cell_name) #defining title of plot
plt.xlabel('x com') #defining x coordinate of plot
plt.ylabel('y com') #defining y coordinate of plot
plt.savefig(out_folder + '/'+utilities.cell_name +'xcom_ycom.png')
plt.show()
xcommean = numpy.mean(xcomlist) #calculating mean by calling numpys function
ycommean = numpy.mean(ycomlist)
for i in xcomlist:
xcomlist2.append(i-xcommean)
for j in ycomlist:
ycomlist2.append(j-ycommean)
def compute():
'''
Calculates frequency, change in angle per frame, total clockwise/counter-clockwise time
interval and no of frames and all else necessary outputs. Also outputs the finally analyzed
data in the form of CSV files and graphs
'''
#defines variables for furthur use
time = utilities.time
out_folder = utilities.out_folder
a=0
prev_a =0
total_angle = 0.0 #change in total angle
num_clock = 0 #number of frames with clockwise rotation
num_anti = 0 #number of frames with anti clockwise rotation
num_switch1 = 0 #number of switches from clockwise to counter
num_switch2 = 0 #number of switches from counter to clockwise
curr_block = 0 #number of consecutive same directions
pos_total = 0 #total number of frames with positive direction
neg_total = 0 #total number of frames with negative direction
global slopes,lens,tracedia,angles #define global variable
slopes = numpy.array(slopes) #covert slopes array to numpy array
prevang = (math.atan(0))
count=0
blocks=[]
negfreqavg =0
posfreqavg =0
negcount=0
poscount =0
for i in slopes: #for each slope in list (each frame's slope)
currang = i #defining current angle
diff = currang-prevang #calculating difference
abs_diff= min(abs(diff),abs(diff-3.14),(abs(diff+3.14))) #calculating absolute difference
if abs_diff!=0: #if cell has rotated from previous frame
if ((diff/abs_diff==1)|((diff-3.14)/abs_diff==1)|((diff+3.14)/abs_diff==1)):
a=1
else:
a=-1
else: #if cell has not rotated
a=prev_a
if count == 0:
total_angle = currang
else:
total_angle += abs_diff*a
curr_block += 1
if a == 1:
num_clock += 1 #clockwise rotation
else:
num_anti += 1 #anticlockwise rotation
if prev_a == 1 and a == -1:
pos_total += curr_block
if curr_block>5:
blocks.append(curr_block)
num_switch1 += 1 #switch from clockwise to counter-clockwise
curr_block = 1
if prev_a == -1 and a == 1:
neg_total += curr_block #switch from anti-clockwise to clockwise
if curr_block>5:
blocks.append(-curr_block)
num_switch2 += 1
curr_block = 1
prev_a = a
angles.append([count,currang,diff,abs_diff,a,abs_diff*a,((abs_diff*1000)/time), total_angle, lens[count], tracedia[count],(1000*abs_diff*a)/(time*6.28)])
if((abs_diff*a)/(time*6.28)>0):
posfreqavg = posfreqavg + (abs_diff*a)/(time*6.28)
poscount= poscount +1 #increasing postive count
else:
negfreqavg = negfreqavg + (abs_diff*a)/(time*6.28)
negcount = negcount +1 #increasing negative count
count+=1
prevang=i
angles = numpy.array(angles[1:]) #triuncating numpy array
stDev = numpy.std(angles[:,6]) #calculating standard deviation
mean = numpy.mean(angles[:,6]) #calculating mean
lastent = 0
if(len(blocks) == 0): #blocks to calcuate number of changes b/w clockwise and counter clockwise rotations
lastent = 0
else:
lastent = blocks[len(blocks)-1]
if(angles[len(angles)-1][4] == 1):
blocks.append(curr_block) #if rotation direction has changed
else:
blocks.append(-(curr_block)) #if rotation direction has not changed
blocks = numpy.array(blocks)
pos_total =0
neg_total =0
for dist in blocks:
if dist>0:
pos_total+=dist #counts number of clockwise rotations
else:
neg_total-=dist #counts numebr of counter-clockwise rotations
with open(out_folder + 'file_details.csv', 'w') as f: #saving output in file named file_details.csv
writer = csv.writer(f)
writer.writerow(['Frame Distribution', 'CW rotation frames', 'CW Rotation Time', 'CCW -> CW Switches','CCW rotation frames', 'CCW Rotation Time', 'CW -> CCW Switchs', 'Avg CW rot time interval', 'Avg CCW rot time interval', 'Mean Angular Speed', 'Deviation from mean', 'Ratio of time intervals [CW/CCW]', 'Average CCW frequency', 'Avg CW frequency'])
if(num_switch1 == 0 and num_switch2 == 0 and neg_total == 0):
writer.writerow([blocks, pos_total, pos_total*time, num_switch1, neg_total, neg_total*time, num_switch2, (pos_total*time), (neg_total*time), mean, stDev, 'Nan', (posfreqavg/poscount), (negfreqavg/negcount)])
elif(num_switch1 == 0 and num_switch2 == 0 and pos_total == 0):
writer.writerow([blocks, pos_total, pos_total*time, num_switch1, neg_total, neg_total*time, num_switch2, (pos_total*time), (neg_total*time), mean, stDev, (pos_total*num_switch2)/(neg_total), (posfreqavg/poscount), (negfreqavg/negcount)])
elif(num_switch1 == 0):
writer.writerow([blocks, pos_total, pos_total*time, num_switch1, neg_total, neg_total*time, num_switch2, 0, (neg_total*time)/num_switch2, mean, stDev, (pos_total*num_switch2)/(neg_total*num_switch1), (posfreqavg/poscount), (negfreqavg/negcount)])
elif(num_switch2 == 0):
writer.writerow([blocks, pos_total, pos_total*time, num_switch1, neg_total, neg_total*time, num_switch2, (pos_total*time)/num_switch1, 0 , mean, stDev, (pos_total*num_switch2)/(neg_total*num_switch1), (posfreqavg/poscount), (negfreqavg/negcount)])
else:
writer.writerow([blocks, pos_total, pos_total*time, num_switch1, neg_total, neg_total*time, num_switch2, (pos_total*time)/num_switch1, (neg_total*time)/num_switch2, mean, stDev, (pos_total*num_switch2)/(neg_total*num_switch1), (posfreqavg/poscount), (negfreqavg/negcount)])