|
a |
|
b/mpg2png.py |
|
|
1 |
import os, datetime, glob, re |
|
|
2 |
import cv2 |
|
|
3 |
import numpy as np |
|
|
4 |
import pandas as pd |
|
|
5 |
import csv |
|
|
6 |
import sys |
|
|
7 |
|
|
|
8 |
#RAPIDから保存した小腸カプセル内視鏡動画(mpg)を画像(png)にして保存 |
|
|
9 |
# ※simplemain()を実行するとできる |
|
|
10 |
|
|
|
11 |
def matching(x, y, image, num): |
|
|
12 |
''' |
|
|
13 |
パターンマッチングの実行 |
|
|
14 |
''' |
|
|
15 |
w = 17 |
|
|
16 |
h = 24 |
|
|
17 |
_time = 0 |
|
|
18 |
try: |
|
|
19 |
for i in range(10, -1, -9): |
|
|
20 |
img = image[y:y+h, x:x+w] |
|
|
21 |
mat = [] |
|
|
22 |
for n in num: |
|
|
23 |
match_result = cv2.matchTemplate(img, n, cv2.TM_CCOEFF_NORMED) |
|
|
24 |
mat.append(match_result.max()) |
|
|
25 |
t = np.argmax(mat) |
|
|
26 |
_time += t*i |
|
|
27 |
x += 17 |
|
|
28 |
except Exception as e: |
|
|
29 |
print(f'numbers/0~9.pngが見つかりません。CE画像の時間読み取り用の0~9.pngをnumbersフォルダに入れて適切に配置してください。\nエラー内容:{e}') |
|
|
30 |
sys.exit() |
|
|
31 |
return _time |
|
|
32 |
|
|
|
33 |
def readtime(img): |
|
|
34 |
''' |
|
|
35 |
パターンマッチングによりCE画像の時刻を読み取る |
|
|
36 |
''' |
|
|
37 |
_time = [] |
|
|
38 |
x = 5 |
|
|
39 |
y = 7 |
|
|
40 |
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
|
|
41 |
numpath = glob.glob('./numbers/*.png') |
|
|
42 |
num = [] |
|
|
43 |
for path in numpath: |
|
|
44 |
n = cv2.imread(path) |
|
|
45 |
n = cv2.cvtColor(n, cv2.COLOR_BGR2GRAY) |
|
|
46 |
num.append(n) |
|
|
47 |
|
|
|
48 |
for i in range(3): |
|
|
49 |
t = matching(x, y, img, num) |
|
|
50 |
_time.append(t) |
|
|
51 |
x += 44 |
|
|
52 |
|
|
|
53 |
return _time[0], _time[1], _time[2] |
|
|
54 |
|
|
|
55 |
def fiximg(img, mask): |
|
|
56 |
''' |
|
|
57 |
画像を512×512にして淵の白文字を黒くする |
|
|
58 |
''' |
|
|
59 |
return img[32:-32, 32:-32, :]*mask |
|
|
60 |
|
|
|
61 |
def mpg2png(movpath, folder, img_save, inp_save, imgpath=None, inppath=None): |
|
|
62 |
''' |
|
|
63 |
動画を画像にして保存 |
|
|
64 |
(画像名:CE画像の時間で保存、時間が重複している場合は、名前の最後が"_00""_01"などになる) |
|
|
65 |
''' |
|
|
66 |
if inp_save: |
|
|
67 |
try: |
|
|
68 |
mask = cv2.imread('./mask.png') |
|
|
69 |
mask = np.where(mask < 100, 0, 1) |
|
|
70 |
except Exception as e: |
|
|
71 |
print(f'mask.pngが見つかりません。CE画像の名前や時間を黒塗りするためのmask.pngが読み込めませんでした。パスを確認してください。\nエラー内容:{e}') |
|
|
72 |
sys.exit() |
|
|
73 |
hours = [] |
|
|
74 |
minute = [] |
|
|
75 |
second = [] |
|
|
76 |
total_second = [] |
|
|
77 |
i = 0 |
|
|
78 |
tmp = None |
|
|
79 |
tmps = 0 |
|
|
80 |
cap = cv2.VideoCapture(movpath) |
|
|
81 |
if(cap.isOpened()): |
|
|
82 |
ret, frame = cap.read() |
|
|
83 |
while(ret):#画像枚数分ループ |
|
|
84 |
if(i%5 == 0):#CE動画は5枚連続で同じ画像のため5回に一回保存 |
|
|
85 |
h, m, s = readtime(frame) |
|
|
86 |
hours.append(h) |
|
|
87 |
minute.append(m) |
|
|
88 |
second.append(s) |
|
|
89 |
ts = h*3600 + m*60 + s |
|
|
90 |
total_second.append(ts) |
|
|
91 |
|
|
|
92 |
if (ts < tmps): |
|
|
93 |
print(f'failed pattern matching.CE画像から時刻の読み取りに失敗しました。') |
|
|
94 |
sys.exit() |
|
|
95 |
|
|
|
96 |
ce_time = '{0:02}{1:02}{2:02}'.format(h, m, s) |
|
|
97 |
if(ce_time == tmp): |
|
|
98 |
n += 1 |
|
|
99 |
else: |
|
|
100 |
n = 0 |
|
|
101 |
if img_save: |
|
|
102 |
cv2.imwrite(os.path.join(imgpath, ce_time + '_{:02}.png'.format(n)), frame) |
|
|
103 |
if inp_save: |
|
|
104 |
frame = fiximg(frame, mask) |
|
|
105 |
cv2.imwrite(os.path.join(inppath, ce_time + '_{:02}.png'.format(n)), frame) |
|
|
106 |
tmp = ce_time |
|
|
107 |
tmps = ts |
|
|
108 |
i += 1 |
|
|
109 |
ret, frame = cap.read() |
|
|
110 |
cap.release() |
|
|
111 |
cv2.destroyAllWindows() |
|
|
112 |
|
|
|
113 |
if img_save or inp_save: |
|
|
114 |
#各画像に書かれている内視鏡の時間をcsvに保存 |
|
|
115 |
df = pd.DataFrame({'Hours': hours, 'Minute': minute, 'Second': second, 'Total_Second': total_second}) |
|
|
116 |
df.to_csv(os.path.join(folder, 'time.csv')) |
|
|
117 |
|
|
|
118 |
def simplemain(mpg_paths='./mpg', out_path='./output', img_save=True, inp_save=True): |
|
|
119 |
''' |
|
|
120 |
PillCamSB3動画(COLON2非対応)を画像に変換(mpg2pngの実行)と保存するフォルダを生成 |
|
|
121 |
(元画像保存先:out_path/現在の時刻/動画の名前/image/*.png) |
|
|
122 |
(トリミング後画像保存先:out_path/現在の時刻/動画の名前/input_image/*.png) |
|
|
123 |
※time.csvに各画像の時間を書き込む |
|
|
124 |
args |
|
|
125 |
mpg_paths:動画を含むフォルダ |
|
|
126 |
out_path:動画を画像変換後の保存先 |
|
|
127 |
img_save:動画を画像変換後に保存するか |
|
|
128 |
inp_save:動画を画像変換後にトリミングと白塗りして保存するか |
|
|
129 |
''' |
|
|
130 |
mpgpaths = glob.glob(f'{mpg_paths}/*') |
|
|
131 |
mpgpaths = sorted([p for p in mpgpaths if re.search('/*\.(avi|mp4|mov|mpg|wmv|flv)', str(p))]) |
|
|
132 |
if len(mpgpaths)==0: |
|
|
133 |
print(f'読み込んだ動画{len(mpgpaths)}本。動画が読み込まれていません。パスの確認やフォルダ名とファイル名に日本語を含まないようにしてください。') |
|
|
134 |
sys.exit() |
|
|
135 |
print(f'確認(動画数{len(mpgpaths)}。{mpgpaths}\n以上の動画を画像にして保存します。') |
|
|
136 |
outpath = os.path.join(out_path, datetime.datetime.now().strftime('%Y%m%d_%H%M%S')) |
|
|
137 |
imgpath, inppath = None, None |
|
|
138 |
for mpgpath in mpgpaths: |
|
|
139 |
mpgname = os.path.splitext(os.path.basename(mpgpath))[0] |
|
|
140 |
path = os.path.join(outpath, mpgname) |
|
|
141 |
if img_save: |
|
|
142 |
imgpath = os.path.join(outpath, mpgname, 'image') |
|
|
143 |
os.makedirs(imgpath, exist_ok=True) |
|
|
144 |
if inp_save: |
|
|
145 |
inppath = os.path.join(outpath, mpgname, 'input_image') |
|
|
146 |
os.makedirs(inppath, exist_ok=True) |
|
|
147 |
|
|
|
148 |
mpg2png(mpgpath, path, img_save, inp_save, imgpath=imgpath, inppath=inppath) |
|
|
149 |
|
|
|
150 |
if __name__ == '__main__': |
|
|
151 |
simplemain(mpg_paths='./mpg', out_path='./output', img_save=True, inp_save=True) |
|
|
152 |
#※mask/pngとnumbers/0から9まで.pngを適切に配置する |
|
|
153 |
#引数 |
|
|
154 |
#mpg_paths:動画を含むフォルダ |
|
|
155 |
#out_path:動画を画像変換後の保存先 |
|
|
156 |
#img_save:動画を画像変換後に保存するか |
|
|
157 |
#inp_save:動画を画像変換後にトリミングと白塗りして保存するか |