黑邊是指視訊中存在的黑色或白色邊框,這類邊框存在于很多視訊中,由于黑邊的存在,哈希值的提取收到了它的幹擾,尤其對于dhash來說,影響非常大,容易造成誤判。在v1.0排重算法中,采用的黑邊去除方法是opencv自帶的函數,該函數對于包含logo的黑邊處理效果很差,而絕大部分黑邊中都包含視訊logo,是以仍然存在大部分黑邊未被去除的情況,是以手工重寫黑邊去除算法。
部分黑邊情況如下圖所示:
算法流程:
->
->
->
計算圖像顔色直方圖,求得顔色直方圖的标準差,若标準差小于1024,則直接認定為不包含邊框。(因為标準差越小說明顔色分布越均勻,越不可能出現純色邊框)
将圖像轉換為二值圖像,這裡利用OTSU算法确定分割門檻值,OTSU算法能夠好的分割前景色與背景色。
在二值圖像的基礎上,利用sobel算子計算出垂直與水準方向的邊緣。
對計算得到的邊緣圖像統計分别統計橫縱方向的邊緣長度占比以及區域内的像素均值。
以中線折疊,取邊緣最長的邊,若其長度大于某一門檻值,顔色均值不極端分布于黑色或白色,則認定該邊緣為邊框邊緣。
取一個視訊内所有邊緣,做NMS,取得統一的邊框邊緣,利用該邊緣切割所有該視訊的截圖,得到最終結果。
import os
import cv2
import numpy as np
from io import BytesIO
from PIL import Image
import base64
class BorderRm():
def nms(self,boxes,overlap=0.8):
boxes = [[i[0],i[2],i[1],i[3],s] for i,s in boxes.items()]
boxes = sorted(boxes,key=lambda N:N[4])
if not boxes:
pick = []
else:
trial = np.zeros((len(boxes),5),dtype=np.float32)
trial[:] = boxes[:]
x1 = trial[:,0]
y1 = trial[:,1]
x2 = trial[:,2]
y2 = trial[:,3]
score = trial[:,4]
area = (x2-x1+1)*(y2-y1+1)
I = np.argsort(score)
pick = []
while (I.size!=0):
last = I.size
i = I[last-1]
pick.append(i)
suppress = [last-1]
for pos in range(last):
j = I[pos]
xx1 = max(x1[i],x1[j])
yy1 = max(y1[i],y1[j])
xx2 = min(x2[i],x2[j])
yy2 = min(y2[i],y2[j])
w = xx2-xx1+1
h = yy2-yy1+1
if (w>0 and h>0):
o = w*h/max(area[i],area[j])
if (o >overlap):
if pos != i:
boxes[i][4] += boxes[pos][4]
suppress.append(pos)
I = np.delete(I,suppress)
newBox = []
for i in pick:
newBox.append(boxes[i])
newBox = sorted(newBox,key=lambda N:N[4],reverse=True)
return newBox[0][:4]
def remove_border_imgs(self,imgs):
borders = {}
for img in imgs:
img = Image.open(BytesIO(base64.b64decode(img))).convert("RGB")
img = img.convert('RGB')
im = cv2.cvtColor(np.asarray(img),cv2.COLOR_RGB2BGR)
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
(x1,x2),(y1,y2) = self.sobel(im)
if (x1,x2,y1,y2) not in borders:
borders[(x1,x2,y1,y2)] = 1
else:
borders[(x1,x2,y1,y2)] += 1
x1,y1,x2,y2 = self.nms(borders)
return x1,y1,x2,y2
def detectBorder(self,im,ori,width,length,side):
border = {}
if side == 'X':
im = im.T
ori = ori.T
for i,ix in enumerate(im):
border[i] = (np.sum(ix)*0.003921568627451,np.sum(ori[i])*0.003921568627451)
border = self.checkborder(border,width,length,side)
return border
def checkborder(self,border,width,length,side):
border = [(k,border[k]) for k in sorted(border.keys())]
Nborder = []
colorSum = 0
for i in range(int(length*0.375)):
colorSum += border[i][1][1]+border[length-i-1][1][1]
Nborder.append((i,border[i][1][0]+border[length-i-1][1][0],colorSum))
res = sorted(Nborder,key=lambda N:N[1],reverse=True)[0]
cw = res[0]
Bvalue = res[1]*0.5
Cvalue = res[2]*0.5/(cw+1)
if side == 'Y':
B = 0.30
C = 0.40
else:
B = 0.40
C = 0.40
if Bvaluewidth*C and Cvalue