先のエラーを追いかけます。
$ ls -lt out_v26/bw_near_2* | head -rw-r--r--@ 1 kondoh staff 416097 4 21 13:43 out_v26/bw_near_2.mp4 -rw-r--r-- 1 kondoh staff 28439 4 21 13:43 out_v26/bw_near_200080.jpg -rw-r--r-- 1 kondoh staff 28495 4 21 13:40 out_v26/bw_near_200079.jpg -rw-r--r-- 1 kondoh staff 28084 4 21 13:37 out_v26/bw_near_200078.jpg -rw-r--r-- 1 kondoh staff 27962 4 21 13:34 out_v26/bw_near_200077.jpg -rw-r--r-- 1 kondoh staff 27857 4 21 13:31 out_v26/bw_near_200076.jpg -rw-r--r-- 1 kondoh staff 27951 4 21 13:28 out_v26/bw_near_200075.jpg -rw-r--r-- 1 kondoh staff 27738 4 21 13:25 out_v26/bw_near_200074.jpg -rw-r--r-- 1 kondoh staff 27942 4 21 13:22 out_v26/bw_near_200073.jpg -rw-r--r-- 1 kondoh staff 27636 4 21 13:19 out_v26/bw_near_200072.jpg 0,1,2,... ときて 81の処理のどこかで起きてるようなので... 10 * 81 / 300 = 2.7 これで再現するだろうか $ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v26/dbg div=2 use_srv srv_c use_img_srv init_sec=12.7 OpenCV: FFMPEG: tag 0x34363248/'H264' is not supported with codec id 28 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to use tag 0x31637661/'avc1' frm : 0/300(0.0%) : not start yet wh : 0/76800(0.0%) : not start yet Traceback (most recent call last): File "./img_sock.py", line 158, inf() File "./img_sock.py", line 137, in col col = img.col(*lst) File "/Users/kondoh/rt_wk/rt_v26/img.py", line 139, in col return videos.col(fn, sec, x, y, def_col, rep) File "/Users/kondoh/rt_wk/rt_v26/img.py", line 102, in col return img_sec(fn, sec)[y, x] TypeError: 'NoneType' object is not subscriptable 再現する
追いかけてみるとどうも
v26.patch diff -urN rt_v25/img.py rt_v26/img.py : - video = [] - while vc.isOpened(): - (ret, img) = vc.read() - if not ret: - break - video.append(img) - n = len(video) : + kd = { 'i': 1, 'w': 3, 'h': 4, 'fps': 5, 'n': 7 } + get_prop = lambda k: vc.get( kd.get(k) ) + set_prop = lambda k, v: vc.set( kd.get(k), v ) + fix_type = lambda k, v: int(v) if k != 'fps' else v + + dic = dict( map( lambda k: ( k, fix_type( k, get_prop(k) ) ), kd.keys() ) ) + + fps = dic.get('fps') + n = dic.get('n') :
ここで以前は動画ファイルに含まれるフレームの数nを、 最後までreadしみて決定してましたが、、、
今回のv26では、vc.get(7)で返る結果を使うように変更してました。
さらに、以前は最初に全フレームをreadして保持してましたが、 さすがにメモリを使い過ぎる気がして、 必要なときに vc.set(1, xxx) でseekしてreadするよう変更してました。
どうも、取得したフレーム数 n の範囲内でも、 read に失敗する現象が出てるようです。 (IMG_3999_3.mov の 171 フレームの read で失敗してます)
というか、以前は最初にまとめてreadして、 失敗した段階でそこまでのフレーム数を、動画ファイルのフレームと思っていた。
というか、というか、今回 vc.get(7) で取得するようにした値は、 動画ファイルに含まれるフレーム数として正しい値じゃなかった!?
動画ファイルを画像ファイルに展開してみて、 どこかでエラーがでるか試してみます。 $ ./img.py Usage: ./img.py img_name video_name fps=zm= cmd= fps is int value (default 30) zm is float value (default 1.0) cmd is v2i, i2v or play (default i2v) $ ./img.py out_v26/for_dbg_3 IMG_3999_3.mov cmd=v2i Traceback (most recent call last): File "./img.py", line 263, in video_to_imgs(img_name, video_name) File "./img.py", line 233, in video_to_imgs cv2.imwrite(fn, imgs[i] ) TypeError: 'map' object is not subscriptable bash-3.2$ って、これは違うエラー python3 対応もれ... とりあえず img.py : def read_video(fn): : #dic['imgs'] = lambda : map( img_idx, range(n) ) # func dic['imgs'] = lambda : ut.map_lst( img_idx, range(n) ) # func で修正して 次のパッチに入れるとして $ ./img.py out_v26/for_dbg_3 IMG_3999_3.mov cmd=v2i エラーはでませんな... ls -l out_v26/for_dbg_3* -rw-r--r-- 1 kondoh staff 79995 4 22 07:58 out_v26/for_dbg_300000.jpg -rw-r--r-- 1 kondoh staff 78942 4 22 07:58 out_v26/for_dbg_300001.jpg -rw-r--r-- 1 kondoh staff 78168 4 22 07:58 out_v26/for_dbg_300002.jpg : -rw-r--r-- 1 kondoh staff 66253 4 22 07:58 out_v26/for_dbg_300168.jpg -rw-r--r-- 1 kondoh staff 64499 4 22 07:58 out_v26/for_dbg_300169.jpg -rw-r--r-- 1 kondoh staff 67107 4 22 07:58 out_v26/for_dbg_300170.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300171.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300172.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300173.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300174.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300175.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300176.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300177.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300178.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300179.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300180.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300181.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300182.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300183.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300184.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300185.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300186.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300187.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300188.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300189.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300190.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300191.jpg ほれー! 171フレーム以降が 0 バイトになってる
さてどうしたものか
$ python Python 3.6.5 (default, Mar 30 2018, 06:41:49) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import cv2 >>> vc = cv2.VideoCapture('IMG_3999_3.mov') >>> vc.get(7) 192.0 >>> list(map( vc.get, range(8) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0] >>> list(map( vc.get, range(9) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0, 0.0] >>> list(map( vc.get, range(10) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0, 0.0, 0.0] >>> list(map( vc.get, range(11) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0, 0.0, 0.0, 0.0]
確かに192を返してて、他に171を返すようなプロパティは無さそうですね...
全部メモリに保持するのは避けるとして、 時間はかかりますが、最初に空読みしてread可能なフレーム数だけ調べる対応にしてみますかな。
img.py : def read_video(fn): vc = cv2.VideoCapture(fn) kd = { 'i': 1, 'w': 3, 'h': 4, 'fps': 5, 'n': 7 } get_prop = lambda k: vc.get( kd.get(k) ) set_prop = lambda k, v: vc.set( kd.get(k), v ) fix_type = lambda k, v: int(v) if k != 'fps' else v dic = dict( map( lambda k: ( k, fix_type( k, get_prop(k) ) ), kd.keys() ) ) fps = dic.get('fps') n = dic.get('n') # get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) : if 'img' not in dic: ( ret, dic['img'] ) = vc.read() if not ret: sys.stderr.write( 'err i/n={}/{}\n'.format( dic.get('i'), dic.get('n') ) ) return dic.get('img')
これならどうか? 解像度を落としてエラーチェック。
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 : wh : 300/300(100.0%) : fin 0.80s frm : 65/300(21.7%) : total 4m 8.20s : rest 3m 14.42s : 2018/04/22 09:52:53 wh : 0/300(0.0%) : not start yet wh : 300/300(100.0%) : fin 0.80s wh : 0/300(0.0%) : not start yet err i/n=171/178 Traceback (most recent call last): File "./img_sock.py", line 158, inf() File "./img_sock.py", line 137, in col col = img.col(*lst) File "/Users/kondoh/rt_wk/rt_v27/img.py", line 149, in col return videos.col(fn, sec, x, y, def_col, rep) File "/Users/kondoh/rt_wk/rt_v27/img.py", line 112, in col return img_sec(fn, sec)[y, x] TypeError: 'NoneType' object is not subscriptable Traceback (most recent call last):
vc.get(7)のプロパティは192が返って、 最初にまとめてread()すると177まで成功するので178フレーム分あると思ってたら、 seekしてやり読み直してると171のreadでエラー!?。
n = dic.get('n') # get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0)
seekで先頭に戻してもう一度最初からreadしてみると...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 : err i/n=171/178 :
n=178表示は1回しか出ないので、2回目の171もreadできてる様子?
# get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break for i in [171, 170, 172]: set_prop('i', i) (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 0)
さらに171にseekしてread、170にseekしてread、172にseekしてreadを試すと...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 171 ret=False 170 ret=True 172 ret=False :
連続してreadすると177までOKで、seekしてreadするときは170まではOKとかなのだろうか?
: for i in [171, 170, 172]: set_prop('i', i) (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 170) for i in range(3): i += 170 (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 0)
170read成功のあと、seekなしで連続でreadしてみると...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 171 ret=False 170 ret=True 172 ret=False 170 ret=True 171 ret=False 172 ret=False
いちどerrが出てしまうと、もうだめとか?
# get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break #for i in [171, 170, 172]: # set_prop('i', i) # (ret, _) = vc.read() # sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 170) for i in range(3): i += 170 (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 0)
いかに?
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 170 ret=True 171 ret=False 172 ret=False
seek 0のあとは178までread OKで、 seek 170すると171でNG ? 確認
$ python >>> import cv2 >>> vc = cv2.VideoCapture('IMG_3999_3.mov') >>> vc.set(1, 170) True >>> vc.read() (True, array([[[ 10, 15, 15], [ 10, 15, 15], [ 10, 15, 15], ..., [ 21, 24, 29], : >>> vc.get(1) 171.0 >>> (ret,_) = vc.read() >>> ret False >>> vc.set(1, 0) True >>> vc.get(1) 0.0 >>> for i in range(169): ... (ret, _) = vc.read() ... >>> (ret, _) = vc.read() >>> ret True >>> (ret, _) = vc.read() >>> ret True >>> (ret, _) = vc.read() >>> ret True >>> vc.get(1) 172.0
確かに、0から連続してreadしてる分には171もread OK
さてどうしたものか。
最初連続readで上限を取得しておいて、 つかってて途中でエラーでたら、 seek 0で先頭からreadしてなんとかするとか。
def err_recover(): if vc.isOpened(): vc.open(fn) if 'img' in dic: dic.pop('img') if get_prop('i') != 0: set_prop('i', 0) # get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i break err_recover() def img_idx(i): i %= n # loop if 'img' in dic and dic.get('i') != i: dic.pop('img') if dic.get('i')+1 != i: set_prop('i', i) dic['i'] = i if 'img' not in dic: ( ret, dic['img'] ) = vc.read() if not ret: err_recover() for j in range(i+1): ( ret, dic['img'] ) = vc.read() if not ret: sys.stderr.write( 'err {} {}/{}\n'.format( fn, j, dic.get('n') ) ) dic['i'] = i return dic.get('img') dic['img_idx'] = img_idx
これでトライ
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 : wh : 300/300(100.0%) : fin 0.67s frm : 300/300(100.0%) : fin 3m 38.28s
一応エラーではとまらなくなりました。
パッチを作っておいて。
それでは、前回のリベンジ。
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_2 div=2 use_srv srv_c use_img_srv init_sec=10 : wh : 76530/76800(99.6%) : total 2m 44.76s : rest 0.57s : 2018/04/23 04:08:46 wh : 76800/76800(100.0%) : fin 2m 44.74s frm : 300/300(100.0%) : fin 14h 22m 30.00s
とりあえずエラーでとまらずに10秒の動画を生成できました。 14時間半。画像サーバに切り出す前は確か11時間半。
では、いつものデータで速度比較。
まず従来方式
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2 n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 7m 45.41s 以前の v26 wh : 76800/76800(100.0%) : fin 7m 31.17s v25 wh : 76800/76800(100.0%) : fin 7m 50.96s v24 wh : 76800/76800(100.0%) : fin 7m 44.42s v23 wh : 76800/76800(100.0%) : fin 7m 48.33s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_is n=1 init_sec=5 div=2 use_img_srv : wh : 76800/76800(100.0%) : fin 8m 19.96s 以前の v26 wh : 76800/76800(100.0%) : fin 8m 12.84s
レイトレ用のサーバプロセス分離版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76800/76800(100.0%) : fin 9m 18.49s 以前の v26 wh : 76800/76800(100.0%) : fin 9m 22.96s v25 wh : 76800/76800(100.0%) : fin 9m 34.91s v24 wh : 76800/76800(100.0%) : fin 9m 38.24s v23 wh : 76800/76800(100.0%) : fin 9m 9.07s $ rm xdat
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_s_is n=1 init_sec=5 div=2 use_srv use_img_srv : wh : 76800/76800(100.0%) : fin 9m 53.40s 以前の v26 wh : 76800/76800(100.0%) : fin 9m 54.44s $ rm xdat
レイトレ用のサーバプロセスをC言語で実装版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 76800/76800(100.0%) : fin 53.66s 以前の v26 wh : 76800/76800(100.0%) : fin 53.40s v25 wh : 76800/76800(100.0%) : fin 53.95s v24 wh : 76800/76800(100.0%) : fin 54.07s v23 wh : 76800/76800(100.0%) : fin 1m 50.29s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_sc_is n=1 init_sec=5 div=2 use_srv srv_c use_img_srv : wh : 76800/76800(100.0%) : fin 1m 8.39s 以前の v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
まぁ、変わらず。