{"cells":[{"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/) \n\nOpencv는 다양한 영상/동영상 처리에 사용할 수 있는 오픈소스 라이브러리. \n이미지 데이터를 처리하기 위한 다양한 함수를 제공하고 있음, BoW 에서는 영상을 색깔 영상에서 회색 영상으로 변환할때, SIFT를 할때 등 사용됩니다. \npython 에서는 import cv2로 불러 와서 사용할수 있습니다. \n"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import cv2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\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":{"trusted":true},"cell_type":"code","source":"dataroot=\"/kaggle/input/2020mltermprojectbow/\"\ncsvpath=os.path.join(dataroot,\"Label2Names.csv\")\ndf_data=pd.read_csv(csvpath,header=None)\ndataroottrain=os.path.join(dataroot,\"train_csv_v2\")\ndataroottest=os.path.join(dataroot,\"test_csv_v2\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **데이터 불러오기** \n\n- 1D vector 변환되어 저장되어 있는 Train,Test Data를 불러오는 코드 작성\n\n- Train_label을 Text 형식에서 맵핑된 Index로 변환 작업 필요. Tip) Class : 저장된 Csv 상위 폴더 이름 , Label2Names.csv : Text -> Index 맵핑 표 \n  - ex) \"crocodile_head\" -> 30\n  - **\"BACKGROUND_Google\" 는 Label2Names.csv 안에 없다. 이 클래스는 102로 맵핑 필요**\n  \n- 2D 영상으로 변환 작업 필요\n  - 2D 영상을 1D 벡터로 변환시킨 Vector를 제공된 상태\n  - 제공된 1D 벽터를 다시 2D로 reshape 해줘야 함  \n  - 기존 2D영상의 형태: (256,256,3)\n- 2D 영상의 Type을 Uint8로 변환 작업 필요\n  - 기존 uint8인 데이터를 uint64로 변환되 제공된 상태\n  - 제공된 데이터를 다시 uint8로 변환 해줘야함 Tip) np.uint8 사용\n- 2D 영상 채널 변경 필요\n  - 현재 제공된 영상은 BGR 즉 색을 갖고 있는 영상이다. 하지만 SIFT는 Gray영상으로 진행되기 때문에 변환이 필요.\n  - 채널을 변경하는 방법은 cv2.cvtColor() 를 사용하면 된다. Tip) cv2.COLOR_BGR2GRAY 를 flag로 사용하길 바람."},{"metadata":{"trusted":true},"cell_type":"code","source":"##############Load Data##############\ndef loadtrain(dataroottrain):\n    trainlabel=[]\n    traindata=[]\n    for classname in tqdm(os.listdir(dataroottrain)):\n        ###########################################\n        #만약 classname 이 \"BACKGROUND_Google\" 이라면 \n        #  trainlabel에 102가 현재 클래스의 Index\n        #else\n        #  classname 을 df_data 속에서 찾은 다음 그에 해당하는 index가 현재 클래스의 Index\n        ###########################################\n        for csvname in os.listdir(classpath):\n            ###########################################\n            # trainlabel에 현재 클래스 index를 append\n            # csvpath= dataroottrain -> classname -> csvname Tip) os.path.join을 사용해 csvpath 설정 \n            # pd.read_csv를 이용해 csv 읽어온후 np.array를 사용해 numpy 변수로 변환\n            # csv를 읽으면 matrix는 현재 [256*256*3,] 차원임 이를 [256,256,3] 으로 변경 Tip) np.reshape 함수 사용\n            # np.uint8을 이용해 타입변경\n            # cv2.cvtColor 를 사용해 영상의 차원을 변경\n            # traindata에 변경된 데이터 append\n            ###########################################\n    return traindata,trainlabel\n\ndef loadtest(dataroottest):\n    testlabel=[]\n    testdata=[]\n    testsort=sorted(os.listdir(dataroottest))\n    for csvname in tqdm(testsort):\n            ###########################################\n            # train과 유사한 과정 진행 바람\n            ###########################################\n        testlabel.append(csvname)\n    return testdata,testlabel\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Dense SIFT 작성\n\n- ```extract_sift_descriptors``` 함수를 바탕으로 ```extract_DenseSift_descriptors``` 함수 작성\n    - 기본 SIFT의 경우 keypoint detect 와 Descriptor compute를 동시에 하는 함수를 사용했지만, Dense SIFT는 미리 생성해둔 Keypoint를 기반으로 Descriptor를 compute 해야함 , Tip) [메뉴얼](https://docs.opencv.org/3.4/d0/d13/classcv_1_1Feature2D.html#ab3cce8d56f4fc5e1d530b5931e1e8dc0) 참고\n    \n-  img.shape==[256,256,3]\n    "},{"metadata":{"trusted":true},"cell_type":"code","source":"##############Extract Local Descriptors##############\ndef extract_sift_descriptors(img):\n\n\n    sift = cv2.xfeatures2d.SIFT_create()\n    keypoints, descriptors = sift.detectAndCompute(gray, None)\n    return descriptors\n      \ndef extract_DenseSift_descriptors(img):\n\n    ###########################################\n    # 기본 SIFT 와 동일하게 sift 정의 \n    ###########################################\n    \n    # 미리 이미지 전체에 keypoint를 정의\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    # 기본 SIFT 에서는 detectAndCompute를 사용했지만 \n    # Dense SIFT는 위에서 생성한 keypoint를 사용해 compute 만을 진행 \n    ###########################################\n\n    return descriptors\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Codebook 생성\n\n- 생성한 DenseSIFT를 기반으로 Codebook 찾기. Tip) [메뉴얼](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html) 참고\n    -  X를 [3060*128]로 reshape\n    - Kmeans의 Cluster 갯수(voc_size)를 입력으로 Kmeans를 정의한 후\n    - X(data) 를 fit\n    - kmeans center를 return \n    - X=모든 영상의 특징점을 모은 Matrix\n    - X.shape ==[3060, 1024, 128]==[ 영상 갯수, 키포인트 갯수,SIFT descriptor길이]\n    - voc_size==cluster갯수"},{"metadata":{"trusted":true},"cell_type":"code","source":"##############Build Codebook##############\ndef build_codebook(X, voc_size):\n\n    ###########################################\n    # X를 [3060*128]로 reshape\n    # num_cluster를 voc_size로 주고 Kmeans를 정의\n    # Kmeans 의 fit 함수를 사용해 data의 cluster center 찾기\n    ###########################################        \n    return # Kmeans 내장 변수인 cluster_center를 반환\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## BoW: histogram vector 생성\n\n### input_vector_encoder\n- 생성해둔 codebook(kmeans clustrer center) 와 Dense SIFT를 비교하여 histogram을 구하는 작업 진행\n- scipy.cluster.vq를 사용해 각 Dense SIFT와 유사한 codebook의 Index를 반환 받아 사용. Tip) [메뉴얼](https://docs.scipy.org/doc/scipy/reference/generated/scipy.cluster.vq.vq.html) 참고\n- vq를 이용해 얻은 Index를 np.histogram 을 사용해 histogram을 구한다. Tip) np.histogram 사용시 bin=range(codebook.shape[0] + 1), normed=True 설정, [메뉴얼](https://numpy.org/doc/stable/reference/generated/numpy.histogram.html) \n\n### BoW\n- input_vector_encoder를 통해 받은 code를 flatten함수를 사용해 vector를 편 후 반환  \n- descriptor= 영상하나의 특징점 Matrix\n- descriptor.shape==[1024,128]\n- codebook= Kmeans를 통해 검출한 Cluster centers\n- codebook.shape==[num_cluster,1024,128]"},{"metadata":{"trusted":true},"cell_type":"code","source":"##############Compute Codebook##############\ndef input_vector_encoder(feature, codebook):\n\n    ###########################################\n    # scipy.cluster.vq 를 사용해 각 Dense SIFT와 유사한 codebook의 Index를 반환 받아 사용\n    # 구한 Index들 histogram을  np.histogram 을 사용해 histogram을 구한다\n    # np.histogram 사용시 bin=range(codebook.shape[0] + 1), normed=True 로 설정\n    ###########################################  \n    return word_hist\n\ndef BoW( descriptor, codebook):\n    code = input_vector_encoder(descriptor.tolist(), codebook) \n    return  # code를 flatten 하여 반환 \n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## SVM: classifier\n\n- svm.SVC() 를 활용해 classification 을 진행\n- GridSearchCV()를 활용해 SVC의 파라미터 튜닝을 진행 . Tip) parameters = {'kernel':('linear', 'rbf'), 'C':[0.1 ,1, 10, 100, 1000]}\n- fit()으로 train_data에 대한 머신러닝 학습\n- predict()으로 test_data에 대한 정답을 추론 하여 반환 \n\n- train_data=모든 학습 영상의 BoW Matrix\n- train_data.shape==[3060,200]\n- train_label=모든 학습 영상의 라벨\n- train_label.shape==[3060,]\n- test_data=모든 시험 영상의 BoW Matrix\n- test_data.shape==[1712,200]\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"##############SVM##############\ndef SVM(train_data,train_label,test_data):\n    ###########################################\n    # svm.SVC() 를 사용해 SVM 정의 \n    # SVM과 파라미터 {'kernel':('linear', 'rbf'), 'C':[0.1 ,1, 10, 100, 1000]} 를 사용해 GridSearchCV() 정의\n    # 정의한 GridSearchCV의 함수인 fit을 사용해 train_data 학습 \n    # 정의한 GridSearchCV의 predict 함수를 사용해 test_data 에 대한 정답을 추론\n    ###########################################  \n    return predict","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data,train_label=loadtrain(dataroottrain)\ntest_data,test_label=loadtest(dataroottest)   \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":"DSIFT_STEP_SIZE = 8\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)]\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":"codebook = build_codebook(x_train_des, 200)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"x_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)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predict=SVM(x_train,train_label,x_test) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predict=predict.reshape(-1,1)\ntest_label=np.array(test_label)\ntest_label=test_label.reshape(-1,1)\ntotal_result=np.hstack([test_label,predict])\ndf = pd.DataFrame(total_result,columns=[\"Id\",\"Category\"])\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}