main.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # 基于图像识别和文字识别用 Python 提取视频字幕
  2. import cv2
  3. from PIL import Image
  4. import numpy as np
  5. import os
  6. import datetime
  7. import re
  8. def format_time(second):
  9. hours = second // 3600
  10. minutes = (second - hours * 3600) // 60
  11. second = second - hours * 3600 - minutes * 60
  12. t = datetime.time(hour=hours, minute=minutes, second=second)
  13. return datetime.time.isoformat(t)
  14. def cal_stderr(img, imgo=None):
  15. '''
  16. 计算方差
  17. :param img:
  18. :param imgo:
  19. :return:
  20. '''
  21. if imgo is None:
  22. return (img ** 2).sum() / img.size * 100
  23. else:
  24. return ((img - imgo) ** 2).sum() / img.size * 100
  25. def save_image(ex_folder, img: Image, starts: int, ends: int):
  26. # 保存字幕图片到文件夹
  27. start_time = format_time(starts)
  28. end_time = format_time(ends)
  29. timeline = '-'.join([start_time, end_time])
  30. timeline = timeline.replace(":", "_") + ".png"
  31. try:
  32. imgname = os.path.join(ex_folder, timeline)
  33. img.save(imgname)
  34. print('export subtitle at %s' % timeline)
  35. except Exception:
  36. print('export subtitle at %s error' % timeline)
  37. def export_subtitle(video_filename, skip_frames):
  38. '''
  39. 导出字幕
  40. :param video_filename: 视频文件
  41. :return: 字幕图片截图
  42. '''
  43. ex_folder = os.path.splitext(video_filename)[0]
  44. if not os.path.exists(ex_folder):
  45. os.mkdir(ex_folder)
  46. videoCap = cv2.VideoCapture(video_filename)
  47. for i in range(skip_frames):
  48. videoCap.read()
  49. start_frame = skip_frames
  50. curr_frame = skip_frames
  51. fps = videoCap.get(cv2.CAP_PROP_FPS) # 30
  52. success = True
  53. subtitle_img = None
  54. last_img = None
  55. img_count = 0
  56. while success:
  57. for j in range(9):
  58. videoCap.read()
  59. curr_frame += 1
  60. success, frame = videoCap.read()
  61. curr_frame += 1
  62. if frame is None:
  63. print('video: %s finish at %d frame.' % (video_filename, curr_frame))
  64. break
  65. img = frame[:, :, 0]
  66. img = img[320:640, :]
  67. _, img = cv2.threshold(img, 150, 255, cv2.THRESH_BINARY)
  68. if cal_stderr(img) < 1: # 两帧字幕相同
  69. continue
  70. if img_count == 0:
  71. subtitle_img = img
  72. print('video: %s add subtitle at %d frame.' % (video_filename, curr_frame))
  73. last_img = img
  74. img_count += 1
  75. elif img_count > 10:
  76. img_count = 0
  77. subtitle_img = Image.fromarray(subtitle_img)
  78. save_image(ex_folder, subtitle_img, int(start_frame / fps), int(curr_frame / fps))
  79. start_frame = curr_frame # 开始时间往后移
  80. else:
  81. if cal_stderr(img, last_img) > 1:
  82. subtitle_img = np.vstack((subtitle_img, img))
  83. last_img = img
  84. img_count += 1
  85. print('video: %s add subtitle at %d frame.' % (video_filename, curr_frame))
  86. if img_count > 0:
  87. subtitle_img = Image.fromarray(subtitle_img)
  88. save_image(ex_folder, subtitle_img, int(start_frame / fps), int(curr_frame / fps))
  89. print('video: %s export subtitle finish!' % video_filename)
  90. if __name__ == '__main__':
  91. video_filename = r'videos/大象解说《血战钢锯岭》.mp4'
  92. skip_frames = 2818
  93. export_subtitle(video_filename, skip_frames)