{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Image를 hash값으로 변환해서 비교해보기"},{"metadata":{},"cell_type":"markdown","source":"해쉬(Hash)란 임의의 크기를 가진 데이터를 고정된 크기의 데이터로 변환하는 것을 말합니다. 데이터의 값(value)를 이용해서 고유한 인덱스(Index)를 만드는 과정이라고도 볼 수 있습니다. 자세한 설명은 [해시(Hash)란 무엇인가?](https://siyoon210.tistory.com/85)를 참고하시면 좋습니다.\n\n컴피티션에서 주어진 데이터를 해시값을 바꿔서 살펴보니 같은 이미지에 다른 클래스가 부여된 경우가 몇가지 있는 것 같습니다.\n\n코드는 [Whale Recognition Model with score 0.78563](https://www.kaggle.com/martinpiotte/whale-recognition-model-with-score-0-78563)의 일부를 사용하였습니다."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport os\nfrom os.path import isfile\nimport pickle\nfrom tqdm import tqdm_notebook\nprint(os.listdir(\"../input\"))\n\nfrom PIL import Image as pil_image\nimport matplotlib.pyplot as plt\n\nfrom imagehash import phash #img의 P-hash 값을 구하는 라이브러리\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/2019-3rd-ml-month-with-kakr/train.csv')\ntest_df = pd.read_csv('../input/2019-3rd-ml-month-with-kakr/test.csv')\nsample_df = pd.read_csv('../input/2019-3rd-ml-month-with-kakr/sample_submission.csv')\n\nbasic_path = '../input/2019-3rd-ml-month-with-kakr/'\nsave_path = '../input/hashdataset/'","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"tagged = dict([(p,w) for _, p,w in train_df[['img_file', 'class']].to_records()]) # img_file : class_num, dict\nsubmit = [p for _, p in sample_df[['img_file']].to_records()] #img_file, dict\njoin = list(tagged.keys()) + submit #img_file list tagged and submit","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#img_file을 불러오는 함수\ndef expand_path(p):    \n    if 'train' in p:\n        p = basic_path +'train/'+ p\n    else:\n        p = basic_path + 'test/'+ p\n    return p","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def match(h1, h2):\n    for p1 in h2ps[h1]:\n        for p2 in h2ps[h2]:\n            i1 = pil_image.open(expand_path(p))\n            i2 = pil_image.open(expand_path(p))\n            \n            if i1.mode != i2.mode or i1.size != i2.size: #mode is RGB or grayscale\n                return False\n            \n            a1 = np.array(i1)\n            a1 = a1-a1.mean()\n            a1 = a1/sqrt((a1**2).mean())\n            \n            a2 = np.array(i2)\n            a2 = a2-a2.mean()\n            a2 = a2/sqrt((a2**2).mean())\n            \n            a = ((a1-a2)**2).mean()\n            if a > 0.1:\n                return False\n    return True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''#이미지의 해시 값이 특정 조건을 만족하면, 같은 해시값으로 처리\nh2h = {}\n\nfor i, h1 in enumerate(tqdm_notebook(hs)):\n    for h2 in hs[:i]:\n        if h1-h2 <= 6 and match(h1,h2):\n            s1 = str(h1)\n            s2 = str(h2)\n            if s1 < s2:\n                s1,s2 = s2,s1\n            h2h[s1] = s2\n            \nwith open('h2h.pickle', 'wb') as handle:\n    pickle.dump(h2h, handle, protocol=pickle.HIGHEST_PROTOCOL)'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(save_path + 'p2h.pickle', 'rb') as f:\n    p2h = pickle.load(f)\n    \nwith open(save_path + 'h2h.pickle', 'rb') as f:\n    h2h = pickle.load(f)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#phash 값이 같은 이미지 찾기\nh2ps = {}\n\nfor p,h in p2h.items():\n    if h not in h2ps:\n        h2ps[h] = []\n    if p not in h2ps[h]:\n        h2ps[h].append(p)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#h2h에서 같은 값으로 처리한 이미지의 hash값을 같도록 변경.\nfor p,h in p2h.items():\n    h = str(h)\n    if h in h2h:\n        h = h2h[h]\n    p2h[p] = h","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#총 45개가 차이 발생\nprint(len(h2ps), len(p2h))\n\ncc = 0\nfor h, ps in h2ps.items():\n    if len(ps) >= 2:\n        cc +=1\n        \nprint(cc)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"c = 0\nfor h, ps in h2ps.items():\n    if len(ps) >= 2:\n        c+=1\n        print('Images : ', ps)\n        g = []\n        for p in ps:\n            if 'test' in p:\n                g.append(' ')\n                continue\n            g.append(tagged[p])\n        print('Class : ', g)\n        \nprint(\"Total : \", c)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_car(imgs, per_row=2):\n    n = len(imgs)\n    rows = (n + per_row - 1)//per_row\n    cols = min(per_row, n)\n    fig, axes = plt.subplots(rows,cols, figsize=(24//per_row*cols,24//per_row*rows))\n    for ax in axes.flatten(): ax.axis('off')\n    for i,(img,ax) in enumerate(zip(imgs, axes.flatten())): \n        ax.imshow(img.convert('RGB'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for h, ps in h2ps.items():\n    if len(ps) >= 2:\n        #print('Images:', ps)\n        imgs = [pil_image.open(expand_path(p)) for p in ps]\n        show_car(imgs, per_row=len(ps))","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}