forked from freder/cinemetrics
-
Notifications
You must be signed in to change notification settings - Fork 0
/
02_1_shot-detection.py
172 lines (137 loc) · 4.81 KB
/
02_1_shot-detection.py
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
# -*- coding: utf-8 -*-
import sys
import cv
import time
import winsound
import win32api, win32con
import os.path
import xml.etree.ElementTree as et
DEBUG = False
#DEBUG = True
DEBUG_INTERACTIVE = False
OUTPUT_DIR_NAME = "shot_snapshots"
soundfile = "ton.wav"
def main():
BLACK_AND_WHITE = False
THRESHOLD = 0.48
BW_THRESHOLD = 0.4
os.chdir(sys.argv[1])
try:
os.mkdir(OUTPUT_DIR_NAME)
except:
pass
if len(sys.argv) > 2:
if sys.argv[2] == "bw":
BLACK_AND_WHITE = True
THRESHOLD = BW_THRESHOLD
print "##########"
print " B/W MODE"
print "##########"
tree = et.parse("project.xml")
movie = tree.getroot()
file_path = movie.attrib["path"]
cap = cv.CreateFileCapture(file_path)
if DEBUG:
cv.NamedWindow("win", cv.CV_WINDOW_AUTOSIZE)
cv.MoveWindow("win", 200, 200)
hist = None
prev_hist = None
prev_img = None
pixel_count = None
frame_counter = 0
last_frame_black = False
black_frame_start = -1
t = time.time()
while 1:
img_orig = cv.QueryFrame(cap)
if not img_orig: # eof
cv.SaveImage(OUTPUT_DIR_NAME + "\\%06d.png" % (frame_counter-1), prev_img)
"""movie.set("frames", str(frame_counter))
tree.write("project.xml")"""
break
img = cv.CreateImage((int(img_orig.width/4), int(img_orig.height/4)), cv.IPL_DEPTH_8U, 3)
cv.Resize(img_orig, img, cv.CV_INTER_AREA)
if frame_counter == 0: # erster frame
cv.SaveImage(OUTPUT_DIR_NAME + "\\%06d.png" % (0), img)
pixel_count = img.width * img.height
prev_img = cv.CreateImage(cv.GetSize(img), cv.IPL_DEPTH_8U, 3)
cv.Zero(prev_img)
if DEBUG and frame_counter % 2 == 1:
cv.ShowImage("win", img)
img_hsv = cv.CreateImage(cv.GetSize(img), cv.IPL_DEPTH_8U, 3)
cv.CvtColor(img, img_hsv, cv.CV_BGR2HSV)
# #####################
# METHOD #1: find the number of pixels that have (significantly) changed since the last frame
diff = cv.CreateImage(cv.GetSize(img), cv.IPL_DEPTH_8U, 3)
cv.AbsDiff(img_hsv, prev_img, diff)
cv.Threshold(diff, diff, 10, 255, cv.CV_THRESH_BINARY)
d_color = 0
for i in range(1, 4):
cv.SetImageCOI(diff, i)
d_color += float(cv.CountNonZero(diff)) / float(pixel_count)
if not BLACK_AND_WHITE:
d_color = float(d_color/3.0) # 0..1
# #####################
# METHOD #2: calculate the amount of change in the histograms
h_plane = cv.CreateMat(img.height, img.width, cv.CV_8UC1)
s_plane = cv.CreateMat(img.height, img.width, cv.CV_8UC1)
v_plane = cv.CreateMat(img.height, img.width, cv.CV_8UC1)
cv.Split(img_hsv, h_plane, s_plane, v_plane, None)
planes = [h_plane, s_plane, v_plane]
hist_size = [50, 50, 50]
hist_range = [[0, 360], [0, 255], [0, 255]]
if not hist:
hist = cv.CreateHist(hist_size, cv.CV_HIST_ARRAY, hist_range, 1)
cv.CalcHist([cv.GetImage(i) for i in planes], hist)
cv.NormalizeHist(hist, 1.0)
if not prev_hist:
prev_hist = cv.CreateHist(hist_size, cv.CV_HIST_ARRAY, hist_range, 1)
# wieso gibt es kein cv.CopyHist()?!
cv.CalcHist([cv.GetImage(i) for i in planes], prev_hist)
cv.NormalizeHist(prev_hist, 1.0)
continue
d_hist = cv.CompareHist(prev_hist, hist, cv.CV_COMP_INTERSECT)
# combine both methods to make a decision
if ((0.4*d_color + 0.6*(1-d_hist))) >= THRESHOLD:
if DEBUG:
if frame_counter % 2 == 0:
cv.ShowImage("win", img)
winsound.PlaySound(soundfile, winsound.SND_FILENAME|winsound.SND_ASYNC)
print "%.3f" % ((0.4*d_color + 0.6*(1-d_hist))), "%.3f" % (d_color), "%.3f" % (1-d_hist), frame_counter
if DEBUG and DEBUG_INTERACTIVE:
if win32api.MessageBox(0, "cut?", "", win32con.MB_YESNO) == 6: #yes
cv.SaveImage(OUTPUT_DIR_NAME + "\\%06d.png" % (frame_counter), img)
else:
cv.SaveImage(OUTPUT_DIR_NAME + "\\%06d.png" % (frame_counter), img)
cv.CalcHist([cv.GetImage(i) for i in planes], prev_hist)
cv.NormalizeHist(prev_hist, 1.0)
# #####################
# METHOD #3: detect series of (almost) black frames as an indicator for "fade to black"
average = cv.Avg(v_plane)[0]
if average <= 0.6:
if not last_frame_black: # possible the start
print "start", frame_counter
black_frame_start = frame_counter
last_frame_black = True
else:
if last_frame_black: # end of a series of black frames
cut_at = black_frame_start + int( (frame_counter - black_frame_start) / 2 )
print "end", frame_counter, "cut at", cut_at
img_black = cv.CreateImage((img_orig.width/4, img_orig.height/4), cv.IPL_DEPTH_8U, 3)
cv.Set(img_black, cv.RGB(0, 255, 0))
cv.SaveImage(OUTPUT_DIR_NAME + "\\%06d.png" % (cut_at), img_black)
last_frame_black = False
cv.Copy(img_hsv, prev_img)
frame_counter += 1
if DEBUG:
if cv.WaitKey(1) == 27:
break
if DEBUG:
cv.DestroyWindow("win");
print "%.2f min" % ((time.time()-t) / 60)
#raw_input("- done -")
return
# #########################
if __name__ == "__main__":
main()
# #########################