{"cells":[{"metadata":{},"cell_type":"markdown","source":"# 반드시 처음부터 끝까지 스켈레톤 코드를 살펴보고 구현하기 시작하길 바란다\n## 1. 스켈레톤 코드를 [복사 및 편집] 하여 사용한다.\n## 2. 아래의 [Empty Module 5개]를 직접 구현한다.\n## 3. main 부를 실행하면 여러분이 작성한 Empty Module 을 이용하여 코드가 동작한다."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## [라이브러리 설치] 컴퓨터 비전의 대표 라이브러리 [OpenCV](https://opencv.org/) \nOpencv는 다양한 영상/동영상 처리에 사용할 수 있는 오픈소스 라이브러리. 이미지 데이터를 처리하기 위한 다양한 함수를 제공하고 있으며, 본 프로젝트에서는 영상의 칼라 변환(RGB영상을 회색영상 변환)시, 특징량 추출(SIFT)시 사용됩니다. OpenCV는 C++로 구현되어 있으며, 파이썬 Wrapper를 제공하고 있어 파이썬에서도 사용가능합니다. JupyterNotebook 환경에서는 import cv2로 불러 와서 사용할 수 있습니다. 현재 Kaggle 노트북 개발 환경에 설치된 OpenCV 라이브러리로는 우리의 프로젝트를 원활하게 수행할 수 없으므로, 아래와 같이 기조에 설치된 OpenCV 라이브러리를 제거하고 우리에게 맞는 버전을 설치합니다."},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"# 현재 opencv 코드는 3.4.2.17 에 맞춰서 작성되어 있어 버전을 맞추는 작업이 필요하다. \n! yes | pip3 uninstall opencv-python\n! yes | pip3 uninstall opencv-contrib-python\n! yes | pip3 install opencv-python==3.4.2.17\n! yes | pip3 install opencv-contrib-python==3.4.2.17","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"import cv2\ncv2.__version__","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# OpenCV를 사용하기 위해 Import한다.\nimport cv2\n\nimport os\nimport numpy as np\nfrom sklearn.cluster import KMeans\nfrom sklearn import preprocessing\nfrom sklearn.svm import LinearSVC\nfrom sklearn.metrics import classification_report\nfrom sklearn.model_selection import GridSearchCV\nfrom sklearn import svm\nimport pandas as pd\nfrom tqdm import tqdm\nimport scipy.cluster.vq as vq","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# >> 필요한 모듈 부분 (function 부)"},{"metadata":{},"cell_type":"markdown","source":"# [Empty Module #1] 데이터 불러오기 \n\n### 목표: 지금부터 1D 데이터 형테로 변환하여 저장되어 있는 csv 파일을 읽고, 학습/테스트 데이터를 변수(메모리)에 저장하는 코드를 작성하기로 한다.\n- 1) 클래스 명을 범주형 라벨로 변환하는 작업을 진행한다. \n  - (팁) 클래스 명: 저장된 CSV파일의 상위 폴더 이름, 범주형 라벨: Label2Names.csv에 있는 매핑 표\n  - (예) \"crocodile_head\" -> 30\n  - (주의) \"BACKGROUND_Google\" 는 Label2Names.csv 안에 없므며, 배경클래스는 102로 맵핑하여 사용하라\n- 2) 특징점을 추출하기 위해서는 1D 데이터를 2D 형태인 RGB 데이터로 변환이 필요하다. 이와 같이 데이터의 형태를 변환할 때는 reshape 함수를 사용하라.\n- 3) 그리고 uint64로 제공된 데이터를 uint8로 변경하여 사용한다. 이때 np.uint8 을 사용하라.\n- 4) 특징점을 추출하는 OpenCV 함수들은 입력으로 칼라 영상이 아닌 Gray 영상을 입력으로 받으므로 영상 칼라를 변환한다. \n - 현재 제공된 영상 데이터는 칼라 포멧으로 BGR 포맷을 사용하고 있다. (일반적으로 칼라 영상은 RGB 이다.)\n - 이때 [cv2.cvtcolor() 라는 함수](https://opencv-python.readthedocs.io/en/latest/doc/08.imageProcessing/imageProcessing.html)를 사용하고, flag로 cv2.COLOR_BGR2GRAY 를 사용하라. "},{"metadata":{"trusted":true},"cell_type":"code","source":"# -------------------------------------\n# [Empty Module #1] 학습데이터, 테스트 데이터 불러오기 \n# -------------------------------------\n\n\n# -------------------------------------\n# loadtrain(dataroottrain): <= 코드를 추가하여 학습데이터를 불러오는 코드를 완성하세요\n# -------------------------------------\n# 목적: 학습데이터 불러오기\n# 입력인자: dataroottrain - 학습 데이터 경로\n# 출력인자: traindata - 학습데이터(2D img)\n#          trainlabel - 학습데이터의 라벨 \n# -------------------------------------\n\ndef loadtrain(dataroottrain):\n    trainlabel=[]\n    traindata=[]\n    for classname in tqdm(os.listdir(dataroottrain)):\n        # ------------------------------------------------------------\n        # 구현 가이드라인  (1)\n        # ------------------------------------------------------------\n        # if classname 이 \"BACKGROUND_Google\" 이라면 \n        #   trainlabel에 102가 현재 클래스의 Index\n        # else\n        #   classname 을 df_data 속에서 찾은 다음 그에 해당하는 index가 현재 클래스의 Index \n        # ------------------------------------------------------------\n        # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n        \n        for csvname in os.listdir(os.path.join(dataroottrain,classname)):\n            # ------------------------------------------------------------\n            # 구현 가이드라인 (2)\n            # ------------------------------------------------------------\n            # 1) trainlabel에 현재 클래스 index를 append\n            # 2) csvpath= dataroottrain -> classname -> csvname Tip) os.path.join을 사용해 csvpath 설정 \n            # 3) pd.read_csv를 이용해 csv 읽어온후 np.array를 사용해 numpy 변수로 변환\n            # 4) csv를 읽으면 matrix는 현재 [256*256*3,] 차원임 이를 [256,256,3] 으로 변경 Tip) np.reshape 함수 사용\n            # 5) np.uint8을 이용해 타입변경\n            # 6) cv2.cvtColor 를 사용해 영상의 차원을 변경 Tip:)cv2.COLOR_BGR2GRAY를 인자로 사용 \n            # 7) traindata에 변경된 데이터 append\n            # ------------------------------------------------------------\n            # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n\n    return traindata,trainlabel\n\n\n\n# -------------------------------------\n# loadtest(dataroottest): <= 코드를 추가하여 데스트 데이터를 불러오는 코드를 완성하세요\n# -------------------------------------\n# 목적: 테스트데이터 불러오기\n# 입력인자: dataroottest - 테스트 데이터 경로\n# 출력인자: testdata - 테스트데이터(2D img)\n#          testlabel - 테스트데이터의 파일 제목  \n# -------------------------------------\ndef loadtest(dataroottest):\n    testlabel=[]\n    testdata=[]\n    testsort=sorted(os.listdir(dataroottest))\n    \n    for csvname in tqdm(testsort):\n        # ------------------------------------------------------------\n        # 구현 가이드라인\n        # ------------------------------------------------------------\n        # 1) csvpath= dataroottest -> csvname Tip) os.path.join을 사용해 csvpath 설정 \n        # 2) pd.read_csv를 이용해 csv 읽어온후 np.array를 사용해 numpy 변수로 변환\n        # 3) csv를 읽으면 matrix는 현재 [256*256*3,] 차원임 이를 [256,256,3] 으로 변경 Tip) np.reshape 함수 사용\n        # 4) np.uint8을 이용해 타입변경\n        # 5) cv2.cvtColor 를 사용해 영상의 차원을 변경 Tip:)cv2.COLOR_BGR2GRAY를 인자로 사용 \n        # 6) testdata에 변경된 데이터 append\n        # ------------------------------------------------------------\n        # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라   \n        \n        testlabel.append(csvname)\n        \n    return testdata,testlabel\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# [Empty Module #2] 특징점 추출하기 (Dense-SIFT)\n- ```extract_sift_descriptors``` 함수를 바탕으로 ```extract_DenseSift_descriptors``` 함수 작성\n- SIFT의 detect 함수와 compute 함수를 활용한다.\n- SIFT의 detect 함수는 특징점 위치를 추출하는 함수이고, compute 함수는 특징점 위치 주변 정보를 추출하는 함수이다.\n- [참고 메뉴얼](https://docs.opencv.org/3.4/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0) 참고  \n    "},{"metadata":{"trusted":true},"cell_type":"code","source":"# -------------------------------------\n# [Empty Module #2] 특징점 추출하기 (Dense-SIFT 사용)\n# -------------------------------------\n\n\n# -------------------------------------\n# extract_sift_descriptors(img): <= 수정하지 말고 Dense-SIFT를 위해 참고하세요\n# -------------------------------------\n# 목적: SIFT 특징점 추출을 위한 함수\n# 입력인자: img - 2D 흑백 영상 [256,256]\n# 출력인자: descriptors - SIFT 기술자\n# -------------------------------------\ndef extract_sift_descriptors(img):\n    \n    # SIFT 인스턴스 생성\n    sift = cv2.xfeatures2d.SIFT_create()\n    # SIFT를 이용하여 특징점 위치 추출\n    keypoints = sift.detect(img,None)\n    # img의 type을 uint8로 변환 \n    img=np.uint8(img)\n    # SIFT를 이용하여 추출된 위치 주변 정보인 기술자 추출\n    _,descriptors = sift.compute(img,keypoints)\n    # SIFT 기술자 반환\n    return descriptors\n\n\n# -------------------------------------\n# extract_DenseSift_descriptors(img): <= 코드를 추가하여 Dense-SIFT를 추출하는 코드를 완성하세요\n# -------------------------------------\n# 목적: Dense-SIFT 특징점 추출을 위한 함수\n# 입력인자: img - 2D 흑백 영상 [256,256]\n# 출력인자: descriptors - Dense-SIFT 기술자\n# -------------------------------------\ndef extract_DenseSift_descriptors(img):\n\n    # ------------------------------------------------------------\n    # 1) SIFT 인스턴스 생성\n    # ------------------------------------------------------------\n    # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n\n    \n    \n    # SIFT 기술자를 추출하고 싶은 특징점 위치 정의하기\n    keypoints = [cv2.KeyPoint(x, y, DSIFT_STEP_SIZE)\n            for y in range(0, img.shape[0], DSIFT_STEP_SIZE)\n                for x in range(0, img.shape[1], DSIFT_STEP_SIZE)]\n    \n\n    # ------------------------------------------------------------\n    # 2) SIFT를 이용하여 Dense SIFT를 추출하시오. (단, Keypoints는 Dense-SIFT의 사전정의된 위치 정보를 담고 있음)\n    # ------------------------------------------------------------\n    # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n\n    \n    \n    \n    return descriptors\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## [Empty Module #3] Codebook 생성\n\n- 1) 추출한 Dense-SIFT의 특징량(기술자)을 이용하여 Codebook 을 생성한다\n  - (팁) sckikit-learn에 있는 Kmeans 사용할 것 [메뉴얼](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html)\n  - 1) X를 [3060 * 1024,128]로 reshape 할 것 **\n  - 2) Kmeans의 Cluster 갯수(voc_size)를 입력으로 Kmeans를 정의한 후\n  - 3) X(data) 를 fit\n  - kmeans center를 return \n  -  ***유의 사항* ** 원래 두시간 넘게 걸리는 작업이므로 이상하게 생각안해도 된다. \n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# ------------------------------------------------------------\n# [Empty Module #3] 코드북 생성하기 (KMeans 사용)\n# ------------------------------------------------------------\n\n\n\n# ------------------------------------------------------------\n# build_codebook(X, voc_size): <= 코드를 추가하여 build_codebook를 만드는 코드를 완성하세요\n# ------------------------------------------------------------\n# 목적: Visual Words (즉, codebook)을 계산하기 위한 함수\n#\n# 입력인자: X - 군집화 하려는 데이터 [3060,1024,128]\n#         voc_size - 군집화 하려는 센터(Cluster) 수, 즉 Kmeans의 K\n#\n# 출력인자:  Kmeans 내장 변수인 cluster_center를 반환\n# ------------------------------------------------------------\ndef build_codebook(X, voc_size):\n    # ------------------------------------------------------------\n    # 구현 가이드라인 \n    # ------------------------------------------------------------\n    # 1) X는 [3060*1024,128]의 형태로 reshape 한다 **\n    # 2) n_clusters를 voc_size로 주고 KMeans를 정의한다\n    # 3) KMeans의 fit 함수를 사용해 data의 cluster-center를 구한다\n    # ------------------------------------------------------------\n    # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n    \n    \n\n    \n    return xxx # xxx 는 작성자가 변경해야 함\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## [Empty Module #4] BoW: histogram vector 생성\n\n### BoW\n- 생성해둔 codebook(kmeans clustrer center) 와 Dense SIFT를 비교하여 histogram을 구하는 작업 진행\n- 1) scipy.cluster.vq를 사용해 각 Dense SIFT와 유사한 codebook의 Index를 반환 받아 사용. \n  - (팁) [메뉴얼](https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.vq.vq.html) 참고\n- 2) vq를 이용해 얻은 Index를 np.histogram 을 사용해 histogram을 구한다.\n  - (팁)np.histogram 사용시 bin=range(codebook.shape[0] + 1), normed=True 설정\n  - [메뉴얼](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) 참고\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# ------------------------------------------------------------\n# [Empty Module #4] 히스토그램 생성하기 (vq,np.histogram 사용)\n# ------------------------------------------------------------\n\n# ------------------------------------------------------------\n# BoW(descriptor, codebook): <= 코드를 추가하여 histogram을 만드는 코드를 완성하세요\n# ------------------------------------------------------------\n# 목적: Histogram (즉, 빈도수)를 계산하기 위한 함수\n#\n# 입력인자: descriptor - 한 영상의 특징점 Matrix [1024,128] \n#         codebook - 비교하기 위한 Visual word [200,128]\n#\n# 출력인자:  feature의 codebook 빈도수( 즉 histogram)을 flatten한 Matrix\n\n# ------------------------------------------------------------\ndef BoW( descriptor, codebook):\n    descriptor=descriptor.tolist()\n    # ------------------------------------------------------------\n    # 구현 가이드라인 \n    # ------------------------------------------------------------\n    # 1) scipy.cluster.vq 를 사용해 각 Dense SIFT(descriptor)와 유사한 codebook의 Index를 반환 받아 사용\n    # 2) 구한 Index들 histogram을  np.histogram 을 사용해 histogram을 구한다\n    # 2-Tip) np.histogram 사용시 bins=range(codebook.shape[0] + 1), normed=True 로 설정\n    # ------------------------------------------------------------\n    # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n\n    \n    \n    \n    \n    return xxx # xxx는 작성자가 변경해야 함\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## [Empty Module #5] SVM: classifier\n\n- svm.SVC() 를 활용해 classification 을 진행\n- GridSearchCV()를 활용해 SVC의 파라미터 튜닝을 진행 .\n  - (팁) parameters = {'kernel':('linear', 'rbf'), 'C':[0.1 ,1, 10, 100, 1000]}\n- fit()으로 train_data에 대한 머신러닝 학습\n- predict()으로 test_data에 대한 정답을 추론 하여 반환 \n\n"},{"metadata":{},"cell_type":"markdown","source":"# **Empty Module5**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# ------------------------------------------------------------\n# [Empty Module #5] SVM 학습 및 실험데이터 classification  (SVM 사용)\n# ------------------------------------------------------------\n\n# ------------------------------------------------------------\n# SVM(train_data,train_label, test_data): <= 코드를 추가하여 test_data를 classification하는 코드를 완성하세요\n# ------------------------------------------------------------\n# 목적: SVM 학습 및 test_data의 class를 분류하는 함수 \n#\n# 입력인자: train_data - 모든 학습 영상의 BoW features(histogram) [3060,200] \n#         train_label - 모든 학습 영상의 class [3060,1]\n#         test_data   - 모든 테스트 영상의 BoW features(histogram) [1712,200]\n# 출력인자: test_data을 SVM으로 분류한 결과 \n\n# ------------------------------------------------------------\ndef SVM(train_data,train_label,test_data):\n    # ------------------------------------------------------------\n    # 구현 가이드라인 \n    # ------------------------------------------------------------\n    # 1) svm.SVC() 를 사용해 SVM 정의 \n    # 2) SVM과 파라미터 {'kernel':('linear', 'rbf'), 'C':[0.1 ,1, 10, 100, 1000]} 를 사용해 GridSearchCV() 정의\n    # 3) 정의한 GridSearchCV의 함수인 fit을 사용해 train_data 학습 \n    # 4) 정의한 GridSearchCV의 predict 함수를 사용해 test_data 에 대한 정답을 추론\n    # ------------------------------------------------------------\n    # 구현 가이드라인을 참고하여 아래쪽에 코드를 추가하라\n    \n    return predict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# >> 코드 시작 부분 (main 부)"},{"metadata":{"trusted":true},"cell_type":"code","source":"#현재 경로 저장 \ndataroot=\"/kaggle/input/2020mltermprojectbovw/\"\n# Class 이름과 Index가 맵핑되어 있는 csv 경로 저장 \ncsvpath=os.path.join(dataroot,\"Label2Names.csv\")\n# 위 csv 경로로 csv 읽어오기 \ndf_data=pd.read_csv(csvpath,header=None)\n\n# 학습 데이터 와 테스트 데이터 경로 저장 \ndataroottrain=os.path.join(dataroot,\"train_csv_v2\")\ndataroottest=os.path.join(dataroot,\"test_csv_v2\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# CSV로 저장되어 있는 Img 데이터 읽어오기 (학습데이터, 테스트 데이터)\ntrain_data,train_label=loadtrain(dataroottrain)\ntest_data,test_label=loadtest(dataroottest)   \n\n# numpy 형식으로 변환 \ntrain_data=np.array(train_data)\ntrain_label=np.array(train_label)\ntest_data=np.array(test_data)\ntest_label=np.array(test_label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Dense SIFT의 Keypoint 간격 설정 \nDSIFT_STEP_SIZE = 8\n# 영상의 특징점(DenseSIFT) 검출(학습데이터, 테스트데이터)\nx_train_feature = [extract_DenseSift_descriptors(img) for img in tqdm(train_data)]\nx_test_feature = [extract_DenseSift_descriptors(img) for img in tqdm(test_data)]\n# numpy 형식으로 변환\nx_train_des = np.array(x_train_feature)\nx_test_des = np.array(x_test_feature)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# num_cluster를 200으로 설졍하여 Visual Words(codebook) 계산 \ncodebook = build_codebook(x_train_des, 200)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# BoW feature 계산 (학습 데이터, 테스트 데이터)\nx_train = [BoW(x_train_des[i],codebook) for i in range(len(train_data))]\nx_train = np.asarray(x_train)\nx_test = [BoW(x_test_des[i],codebook) for i in range(len(test_data))]\nx_test = np.asarray(x_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# SVM으로 테스트 데이터 클래스 분류\npredict=SVM(x_train,train_label,x_test) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# CSV 제출을 위한 predict shape 변환 \npredict=predict.reshape(-1,1)\n# CSV 제출을 위한 test_label(id) shape 변환 \ntest_label=np.array(test_label)\ntest_label=test_label.reshape(-1,1)\n# CSV 제출을 위한 Predict 와 label 합치기 \ntotal_result=np.hstack([test_label,predict])\n# CSV 제출을 위한 Dataframe으로 변환 \ndf = pd.DataFrame(total_result,columns=[\"Id\",\"Category\"])\n# CSV 저장 \ndf.to_csv(\"./Test_2020ML.csv\",index=False,header=True)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}