背景:
我們采集了一系列的監控視頻,視頻的左上角會實時顯示時間。通過python opencv庫,我們可以從視頻中截取視頻幀,目標是獲取每一幀的時間戳(Unix時間戳)。
基於這樣的背景,我們的解決方案逐漸進行了優化。
粗糙的方案——估算時間戳
讀取視頻第一幀的時間戳,可以觀看視頻起始幀的時間,將其轉換為unix時間戳,然后根據幀率計算接下來幀的時間戳。
舉個例子:
上面為視頻的第一幀的時間,我們將其轉為對應的時間戳(轉換方式可以自行搜索)為1615889100。之后,我們可以根據幀率來估計每隔多少幀,時間戳會+1,給對應幀標上對應的時間戳。
例如我們的視頻幀率為30fps,那么每隔30幀,時間上加1秒,時間戳+1即可。
精細的方案——tessoract進行數字識別(python接口)
上面粗糙的方案會出現問題,我們的視頻中間可能由丟幀的情況,通過計算得到的視頻幀時間戳難免出現偏差,並且這樣偏差會隨着視頻的長度累計,導致后面的時間戳計算出現更大的誤差。所以對該方案進行優化:
我們的優化方案為:截取視頻幀左上角的時間,通過OCR技術將其轉為時間字符串,再把時間換算為時間戳。
對於OCR工具,我們選擇了開源的tesseract,因為比較熟悉python,就使用了python封裝后的tesseract接口。
-
關於如何安裝python OCR模塊:tesserocr可以參考github:https://github.com/sirfz/tesserocr
-
而關於python 的兩種OCR模塊:tesserocr和pytesserator的區別,可以參考:https://stackoverflow.com/questions/54761638/what-is-the-difference-between-pytesseract-and-tesserocr
筆者最后選擇了tesserocr作為工具,進行識別,但是對於上面的圖片,我們直接進行識別,卻無法得到想要的結果,甚至識別不出內容。進行相應問題的搜索,有人在stackoverflow上提出了類似的問題:https://stackoverflow.com/questions/55994807/why-does-pytesseract-fail-to-recognise-digits-from-image-with-darker-background(無法從背景較暗的圖形中識別出數字)
按照鏈接中的方法,進行了灰度轉換,以及圖像二值化,最后得到的圖像結果類似下面的效果:
理論上來說,這樣的圖像已經很清晰了,識別應該相當准確才對,但實際上,還是出現了數字識別錯誤的問題,並且還比較頻繁。之后繼續進行檢索,在https://www.pythonf.cn/read/84263博客中看到,tesseract做圖像識別時需要白底黑字,所以我們得到的黑底白字圖像,要做最后的像素轉換:最終得到的效果為:
再拿去做識別,得到的結果就相當准確了!
最后附上進行ocr識別以及時間戳轉換的代碼,讀者可以參考里面的函數進行自己的實現:
from PIL import Image
import cv2
import tesserocr
import time
def binarization_file(time_img_file,black_font=False):
'''
description:將指定的圖像二值化
param {time_img_file:輸入的圖像,圖像文件xxx.jpg;black_font:把黑底白字轉為白底黑字}
return {time_bin_img:二值化后的圖像,Image對象}
'''
# cv2進行讀取
img = cv2.imread(time_img_file)
# If your image is not already grayscale :
# img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 進行二值化
threshold = 180 # to be determined
_, img_binarized = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY)
# 對二值圖像進行像素反轉
if(black_font):
img_binarized = 255-img_binarized
# 轉為Image類型
time_bin_img = Image.fromarray(img_binarized)
return time_bin_img
def ocr(time_bin_img):
'''
description:對二值圖像進行OCR識別
param {time_bin_img:二值化后的圖像,Image對象}
return {text:識別出的字符串,取[:-1]是為了去掉換行符,replace函數用於刪除其中的空格}
'''
text = tesserocr.image_to_text(time_bin_img)
return text[:-1].replace(" ","")
def time2timestamp(time_str):
'''
description:將時間格式的字符串轉為時間戳
param {time_text:時間格式的字符串,格式為:'2019-06-03 21:19:03'}
return {time_stamp:時間戳,整數類型}
'''
time_array = time.strptime(time_str,"%Y-%m-%d %H:%M:%S")
time_stamp = int(time.mktime(time_array))
return time_stamp
if __name__=="__main__":
pic = "test.jpg"
bin_pic = binarization_file(pic,black_font=True)
time_text = ocr(bin_pic)
timestamp = time2timestamp(time_text)
print(timestamp)
本文主要記錄了筆者的一些踩坑經歷,正文部分附的鏈接在解決該問題上都給予了極大的幫助,建議閱讀本文時仔細閱讀參考,也歡迎與筆者交流!