케모노 프렌즈의 한 장면에서 이야기 수와 어느 근처를 추측한다

동기 부여



가방짱 모에



뭐야? 너무 귀여워. 무엇이 귀엽다고 전부야 너.
Twitter에서 2차 그림을 보고 기절하는 나날을 보내고 있습니다.

여기에서 본제



고치우사치 진짜로 굉장히, 고속이고, 정확하고 이 소프트를 리스펙트로, 케모노 프렌즈판을 자작해 보았다. 알고리즘이라든지는 참고로 했지만, 가능한 한 잔치의 소스 프로그램은 공부를 겸해 보지 않고 작성했다. 본가는 C#이지만, 이번은 Python3으로 만든다. 사용한 라이브러리 등의 설치에 대해서는 여기에서는 해설하지 않는다. OpenCV와 imagehash, mysql connector를 사용한다.

데이터베이스 작성



OpenCV에서 동영상에서 1프레임씩 꺼내 이미지를 64bit까지 dHash을 사용하여 압축한다. 그것을 DB에 등록한다. 여기 PHPMyAdmin. 1 레코드는 "dHash 값, 프레임 수, 화 수"입니다.

(2018년 3월 7일 추가)
첫 번째 게시물에서는 numpy.ndarray와 PIL.JpegImagePlugin.JpegImageFile 간의 변환 방법을 모르고 cv2.imwrite로 buffer.jpg에 내보낸 다음 Image.open에서 읽는 너무 바보 같은 코드였습니다. 알았으므로 그쪽의 방법으로 재기록하고 있습니다.

KemonoFriendsDBgenerator.py
#.mp4から1フレームずつ取り出しdHash計算後、指定されたDBに登録
#2017/12/28
#2018/03/07

import cv2
import numpy as np
from PIL import Image
import imagehash
import mysql.connector

conn = mysql.connector.connect(user='root', password='', host='localhost', database='kemonofriends')
cur = conn.cursor()

cap=cv2.VideoCapture("KemonoFriends1.mp4")
i=1
while(cap.isOpened()):
    ret,frame=cap.read()
    pilImg = Image.fromarray(np.uint8(frame))
    hash=imagehash.dhash(pilImg)

    print("dHash="+str(hash)+",Frame="+str(i))
    cur.execute("insert into main values ('"+str(hash)+"',"+str(i)+",1);")
    conn.commit()
    i+=1
    if cv2.waitKey(1) & 0xFF==ord('q'):
        break

cur.close
conn.close
cap.release()
cv2.destroyAllWindows()

dHash, 프레임수, 화수 순으로 오름차순으로 나란히 완성된 DB를 csv로 내보냈다. 50만 행 정도가 됐다. 메모리에 전개해 15MB 정도.

KemonoFriendsDB.csv (일부 발췌)
5979a89c9eeeae2a,34080,12
5979a89c9eeeae6a,34078,12
5979a89c9eeeae6a,34079,12
5979bb9b9999b973,27207,7
5979bb9b9999b973,27208,7
5979bb9b9999b973,27209,7
5979bb9b9999b9b3,27210,7
5979bb9b9999b9b3,27211,7
5979f0b2c666636e,31367,9
597c789898b6766c,26162,7
597c789898b6766c,26163,7
597c789898b6766c,26164,7
597c789898b6766c,26165,7
597c789898b6766c,26166,7
597c7c9898b6766c,26161,7
597c7c989c96766c,26139,7
597c7c989c96766c,26140,7
597c7c989c96766c,26141,7
5982c6ddc2aacae8,2660,1
5988c162a2e1e5e3,21076,2
5988c162a2e1e5e3,21077,2
598d8e8d8d189868,40668,1
598d8e8d8d189868,40669,1
5991858785ebc9cb,13397,10

메인 프로그램 만들기



원하는 이미지를 입력하면 dHash를 계산하여 csv에서 가장 가까운 dHash 값을 찾아 프레임 수에서 몇 분 동안 몇 초당 장면을 맞 춥니 다. 선형 탐색으로 찾습니다. 다른 탐색 알고리즘보다 느리기 때문에, 가능한 한 빨리 되도록 죄송 정도로 해밍 거리의 계산 부분은 비트 연산으로 하고 있다.

KemonoFriendsSearch.py
#画像を読みこみdHash計算後、それに最も近い値をcsvから探索
#2017/12/30
#2018/01/15

from PIL import Image
import imagehash
import csv

#ハミング距離
def getHammingDistance(n,m):
    data=n ^ m
    data=(data & 0x5555555555555555)+((data & 0xAAAAAAAAAAAAAAAA)>> 1)
    data=(data & 0x3333333333333333)+((data & 0xCCCCCCCCCCCCCCCC)>> 2)
    data=(data & 0x0F0F0F0F0F0F0F0F)+((data & 0xF0F0F0F0F0F0F0F0)>> 4)
    data=(data & 0x00FF00FF00FF00FF)+((data & 0xFF00FF00FF00FF00)>> 8)
    data=(data & 0x0000FFFF0000FFFF)+((data & 0xFFFF0000FFFF0000)>>16)
    data=(data & 0x00000000FFFFFFFF)+((data & 0xFFFFFFFF00000000)>>32)
    return data

#探索する画像のdHash計算
hash=imagehash.dhash(Image.open("buffer.png"))
hash_str=str(hash)
hash_int=int(hash_str,16)

#csv読み込み
f = open("KemonoFriendsDB.csv", "r")
csv_data = csv.reader(f)
db = [ e for e in csv_data]
f.close()

result="近い画像が見つかりました"

ans=-1          #答えとなるレコード
min=65          #答えとなるハッシュ値とのハミング距離
max=len(db)-1   #DBのレコード数
Hamming_limit=5 #同じ画像を発見できなかった時、許容できるハミング距離の上限

#線形探索
for i in range(len(db)-1):
    diff=getHammingDistance(int(db[i][0],16),hash_int)

    #print("lines="+str(i)+","+hash_str+","+db[i][0]+",diff="+str(diff)+",min="+str(min))

    #同じ画像があった
    if(diff==0):
        min=diff
        ans=i
        result="この画像と同じ画像がdbに存在する"
        break

    #近い画像があった
    if(diff<min):
        min=diff
        ans=i

print("\n結果:")
print("探してた画像のdHash="+hash_str)
print("dbから検索結果dHash="+db[ans][0])
print("ハミング距離="+str(min))

if(min>Hamming_limit):
    result="検索失敗 この画像はdbに存在しない"
    print(result)
else:
    seconds=    int(int(db[ans][1])/30)%60
    minutes=int(int(int(db[ans][1])/30)/60)
    print(result)
    print("フレーム="+db[ans][1])
    print(db[ans][2]+"話"+str(minutes)+"分"+str(seconds)+"秒あたり")

실행 결과



입력 이미지 1



아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아아


결과 1



「5화 9분 35초당」이라고...

확인해 본다.

OHHHHHHHHHHHHHHHHHHHHHH!!!!!!YEEEEEEEEEEEEEEEEES!!!!!!!!!!!!!!

입력 이미지 2



일단 한 장 더 해보시겠습니까 ...


결과 2






프레임수를 캐스트해 「분, 초」를 산출하고 있기 때문에 약간의 오차는 나오네요.
이제 소중한 영상을 빠르게 찾을 수 있습니다!

입력 이미지 3



친구와 놀았을 때의 기념 촬영을 입력해 본다.


결과 3



정밀도 좋다.


참고문헌



배열을 1 차원으로 변환하는 NumPy의 flatten 함수 사용법

좋은 웹페이지 즐겨찾기