{
  "id": 196067,
  "title": "Bag of Visual Words(BoVW) Manual",
  "url": "/competitions/2020mltermprojectbow/discussion/196067",
  "author_name": "Dae Chan Han",
  "post_date": "2020-11-09T06:07:25.375000",
  "votes": 0,
  "comment_count": 2,
  "views": 0,
  "content": "<h1>BoVW</h1>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F309d819c6b29f7149c8a66e09e0f7da6%2FBow.png?generation=1604901070523914&amp;alt=media\" alt=\"\"><br>\n[그림 1] BoVW의 흐름도 <br>\nBoVW는 원래 Bag of Words(BoW)로 문서를 분류하기 위한 방법론으로 사용됐다. 문서 속 단어의 분포를 통해서 문서의 라벨을 추측하는 방법론이다. 이러한 방법론을 영상분류에 적용하기 위해서, 문서 속 단어의 분포를 영상의 특징점의 분포로 바꾼 것이 BoVW이다. <br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F287379c7e001b9c910af74a4d2c889a2%2FBoW_all.png?generation=1604905204813436&amp;alt=media\" alt=\"\"><br>\n[그림 2] BoVW 설명도 0<br>\nBoVW 의 전체적인 이해를 위해 그림 2번을 보면 아래와 같은 순서로 진행 된다. </p>\n<ul>\n<li>1. 각 클래스 사진들의 <strong>특징점</strong>을 검출한 후 사진 하단 부처럼 모은다. </li>\n<li>2. 모은 모든 특징점을 분석하여, 사진 중단부 그래프 속 x축 즉 모든 영상을 대표할 특징점들(codebook)을 선정한다. </li>\n<li>3. 사진 중단부 그래프와 같이 선정한 codebook 이 각 영상에 포함된 빈도 (histogram)를 모든 영상에 대해 구한다. 이 <strong>Histogram</strong> 이 2D 영상을 표현하는 1D vector 가 된다. </li>\n<li>4. 3번 과정을 통해 구한 1D vector를 feature vector로 생각하여 SVM을 학습하여 최종적으로 classification을 진행한다. </li>\n</ul>\n<h2>1. 영상 특징점(SIFT) 검출</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F47ee45e50d86f04bf4df3fc250bf8cb0%2FBow_1.png?generation=1604903376894286&amp;alt=media\" alt=\"\">  <br>\n[그림 3] BoVW 설명도 1, 영상 특징점 검출(words 검출)<br>\n기존 BoW가 단어의 분포를 보고 문서의 라벨을 추측했다면, BoVW는 영상의 특징점 분포를 보고 라벨을 추측한다. 설명을 위해 그림 3를 보면 , 사람 영상 속에서 특징이라 할 수 있는 특징점(눈,코,입, 턱 등) 을 특징점(\"words\") 라고 지칭하여 저장한다. <strong>예시를 위해서 특징점을 (눈,코,입 등) 으로 표현했지만 사실은 밝기값의 차이 등을 활용한 SIFT라는 영상의 특징점 검출하는 알고리즘을 사용한다.</strong><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F08d89223aa2fbe3c2677a1c05a33c4ec%2FSIFT.png?generation=1604904329992771&amp;alt=media\" alt=\"\"><br>\n[그림 4]  SIFT 표현<br>\nSIFT를 사용해 영상의 특징점을 추출하여, 추출된 곳은 표현하면 그림 4 과 같이 표현 할 수 있다. SIFT에 관한 자세한 설명은 참고 자료들을 보길 바란다. </p>\n<h3>DenseSIFT</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2Fe6decfdd3c78d611a87c8d5e6071ff85%2FSIFT.png?generation=1605022203856596&amp;alt=media\" alt=\"\"><br>\n[그림 SIFT] DenseSIFT와 SIFT 비교 <br>\nSIFT는 영상 전체를 분석하여 특징점을 추출한다. 이렇게 영상을 분석을 하면 특징점이 영상 전체에 고르게 분포되지 않고 특정 위치에 몰려있거나 아예 특징점이 검출되지 않을 수도있다. 따라서 영상의 모든 부분의 특징을 사용하기 위해서 DenseSIFT가 사용된다. DenseSIFT는 keypoint 즉 특징점의 위치를 미리 선정해두고 그 위치에서 특징점을 검출한다. SIFT와 DenseSIFT의 차이는 그림 SIFT를 통해 확인 할 수 있다. </p>\n<h3>코드 구현</h3>\n<ul>\n<li>기본 SIFT 구현 </li>\n</ul>\n<pre><code>def extract_sift_descriptors(img): # img.shape==[256,256,3]\n   ## SIFT 정의\n   sift = cv2.xfeatures2d.SIFT_create()\n   ## 영상의 키포인트를 detect 하고 키포인트의 Descriptor를 compute 하는것을 동시에 진행    \n   keypoints, descriptors = sift.detectAndCompute(img, None)\n   ## descriptor 반환\n   return descriptors\n</code></pre>\n<ul>\n<li>Dense SIFT구현</li>\n</ul>\n<pre><code>def extract_DenseSift_descriptors(img): # img.shape==[256,256,3]\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   return descriptors\n</code></pre>\n<h2>2. Codebook 생성</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F4359c190255960253b37f96f69a0d922%2Fcodevook.png?generation=1604904714473588&amp;alt=media\" alt=\"\"><br>\n[그림 5] BoVW 설명도 2 , Codebook<br>\n모든 영상의 SIFT 특징점을 검출하여 [그림 5]와 같이 모은다. 이렇게 모은 모든 특징점을 분석하여 이 전체 데이터셋을 대표할 수 있는 특징점들을 찾아야 한다. <br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F6ab011a3a36dac8b1ad1ed16431c8624%2FKmeans.png?generation=1604906528788962&amp;alt=media\" alt=\"\"><br>\n[그림 6] Kmeans clustering <br>\n모든 특징점을 대표할 수 있는 특징점(Codebook)을 찾는 방법론으로 Kmeans clustering 을 사용한다.  이 방법론은 데이터를 입력받아 이를 소수의 그룹으로 묶는 알고리즘이다. 이 알고리즘은 [그림 6]처럼 label이 없는 데이터를 입력받아 각 데이터에 label을 할당함으로써 군집화를 수행한다. 군집화를 한 후 각 군집을 표현할 수 있는 중심점들을 Codebook으로 사용한다. 군집의 갯수는 사용자가 정하는 것으로 클수록 좋다. (물론 어느순간부터 성능은 수렴한다. 약 cluster 2000개 정도부터는 수렴한다는 보고가 있다.) <br>\nKmeans 가 데이터를 군집화 하는 방식은 참고사이트에서 확인 바란다. </p>\n<h3>코드 구현</h3>\n<ul>\n<li>X=모든 영상의 특징점을 모은 Matrix</li>\n<li>X.shape ==[3060, 1024, 128]==[ 영상 갯수, 키포인트 갯수,SIFT descriptor길이] </li>\n<li>voc_size==cluster갯수</li>\n</ul>\n<pre><code>def build_codebook(X, voc_size): \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</code></pre>\n<h3>GPU Kmeans</h3>\n<ul>\n<li>Kmeans는 데이터가 많을떄 CPU로 처리한다면 시간이 오래 걸릴 것입니다. 아마 이번 문제도 약 한시간 정도 걸리는 것으로 알고 있습니다.</li>\n<li>시간문제를 해결 하기 위해서 Kmeans를 CPU로 연산하지 않고, GPU로 연산하는 방식 있습니다. GPU를 사용하는 방식은 kmc2 라이브러리를 사용하는 것이다. </li>\n</ul>\n<pre><code>def build_codebook_GPU(X, voc_size):\n   ###########################################\n   # X를 [3060*128]로 reshape\n   # kmc2.kmc2() 에 reshape 된 X와 voc_size를 입력으로 넣고 정의 \n   # Kmeans는 MiniBatchKMeans를 사용하며 MiniBatchKMeans 정의 시 init에 kmc2.kmc2로 정의된 변수 입력 \n   # MiniBatchKMeans 의 fit 함수를 사용해 data의 cluster center 찾기\n   ###########################################    \n   return # MiniBatchKMeans 내장 변수인 cluster_center_를 반환\n</code></pre>\n<h2>3. Histogram 생성</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F77ec2160ce96fb8e6a888e02ec9960f3%2FBow_hist.png?generation=1604907320515797&amp;alt=media\" alt=\"\"><br>\n[그림 7] BoVW 설명도 3. Histogram<br>\nCodebook을 생성한 후, 그림 7 과 같이 각 영상의 특징점과 Codebook을 비교하여 Histogram을 생성합니다. 특징점과 codebook을 비교하여, 그 특징점과 가장 유사한 Cluster center의 빈도 수를 높히는 것이다. 영상의 모든 특징점과 codebook을 비교하여 histogram을 생성하게 되면, 2D 영상을 1D feature vector로 표현할 수 있게 된다.     </p>\n<h3>코드 구현</h3>\n<ul>\n<li>def BoW( descriptor, codebook)<ul>\n<li>descriptor= 영상하나의 특징점 Matrix </li>\n<li>descriptor.shape==[1024,128]</li>\n<li>codebook= Kmeans를 통해 검출한 Cluster centers </li>\n<li>codebook.shape==[num_cluster,1024,128]</li></ul></li>\n<li>def input_vector_encoder(feature, codebook)<ul>\n<li>feature=descriptor</li>\n<li>codebook=codebook</li></ul></li>\n</ul>\n<pre><code>def input_vector_encoder(feature, codebook): \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\ndef BoW( descriptor, codebook):\n   code = input_vector_encoder(descriptor.tolist(), codebook) \n   return # code를 flatten 하여 반환 \n</code></pre>\n<h2>4. SVM : classification</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F8c305606c612af03417ef3334e47e575%2FSVM.png?generation=1605013920265537&amp;alt=media\" alt=\"\"><br>\n[그림 8] SVM <br>\nHistogram으로 이루어진 feature vector 를 이용해 Classification을 진행할때는, 머신러닝의 정석적인 방법론이라 할수있는 Support vector maching(SVM)을 사용한다.  SVM은 결정 경계(Decision Boundary) 즉 분류를 위한 기준 선을 정의하는 모델이다. 이 모델은 그림 8의 margin 즉 선과 데이터의 최단 거리가 최대한 먼 경계를 찾는 것을 목표로 한다.  자세한 설명은 참고 사이트를 확인 바란다. <br>\nSVM 을 통해 Decision Boundary를 찾게 된다면 Test dataset의 라벨을 분류 할 수 있게된다. </p>\n<h3>코드 구현</h3>\n<ul>\n<li>def SVM(train_data,train_label,test_data)<ul>\n<li>train_data=모든 학습 영상의 BoW Matrix</li>\n<li>train_data.shape==[3060,200]</li>\n<li>train_label=모든 학습 영상의 라벨</li>\n<li>train_label.shape==[3060,]</li>\n<li>test_data=모든 시험 영상의 BoW Matrix </li>\n<li>test_data.shape==[1712,200]</li></ul></li>\n</ul>\n<pre><code>def 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\n</code></pre>\n<h2>5. Inference</h2>\n<p>SVM 까지 학습을 완료하면 Test Set의 라벨을 추정할 수 있게 된다. 추정하는 과정을 다시 요약하면 다음과 같다. </p>\n<ul>\n<li>1. Test 영상의 SIFT 특징점 검출</li>\n<li>2. SIFT 특징점와 codebook을 비교해 histogram 생성</li>\n<li>3. histogram 을 SVM 모델에 넣어 클래스를 추정 </li>\n</ul>\n<h3>참고 자료</h3>\n<ul>\n<li><a href=\"https://darkpgmr.tistory.com/125\" target=\"_blank\">BoVW</a></li>\n<li><a href=\"https://darkpgmr.tistory.com/131\" target=\"_blank\">영상 특징점 &amp;&amp; SIFT</a></li>\n<li><a href=\"https://bskyvision.com/21\" target=\"_blank\">SIFT</a></li>\n<li><a href=\"https://untitledtblog.tistory.com/132\" target=\"_blank\">kmeans</a></li>\n<li><a href=\"https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%8B%E1%85%B5%E1%84%85%E1%85%A9%E1%86%AB.pdf\" target=\"_blank\">SVM 이론</a></li>\n<li><a href=\"https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%89%E1%85%B5%E1%86%AF%E1%84%89%E1%85%B3%E1%86%B8.pdf\" target=\"_blank\">SVM 실습</a></li>\n</ul>",
  "messages": [
    {
      "id": 1073981,
      "postDate": "2020-11-10T05:27:42.540Z",
      "content": "<p>[한대찬 조교님] </p>\n<ol>\n<li>참고자료는 맨 밑으로 내려주세요. </li>\n<li>extract_sift_descriptors() 사용을 위해 RGB영상을 흑백영상으로 변경해야 하는 설명이 없는 것 같습니다.</li>\n<li>Dense SIFT에 대한 설명이 없는 것 같습니다. 그리고 Sparse SIFT와 Dense SIFT에 대한 차이 설명 부분도 없는거 같습니다. 왜 Dense Feature를 사용해야 하는지 설명 부탁드립니다.</li>\n<li>각 함수의 입력 아규먼트 설명이 없는 것 같습니다.<br>\n예를들어 build_codebook(X, voc_size) 에서 X가 뭐고 어떤 형태의 행렬로 넣어야 되는지 정보가 부족해 보입니다. Matrix는 행과 열에 맞춰서 정보를 담아야 하니 이런 설명이 중요해 보입니다.</li>\n<li>BoW(image, descriptor, codebook) 에서 입력 image 는 사용되지 않는데 왜 넣는거죠?</li>\n<li>SVM에 대한 이론은 다른 웹사이트가 아닌 교수님 강의를 참고하라고 넣는게 맞는 거 같습니다. (교안을 좀 보시는게 어떤가요)<br>\n최대한 수업과 연관지어주는 것이 학생들의 학습을 위해 좋지 않을까요?</li>\n</ol>",
      "rawMarkdown": "[한대찬 조교님] \n1. 참고자료는 맨 밑으로 내려주세요. \n2. extract_sift_descriptors() 사용을 위해 RGB영상을 흑백영상으로 변경해야 하는 설명이 없는 것 같습니다.\n3. Dense SIFT에 대한 설명이 없는 것 같습니다. 그리고 Sparse SIFT와 Dense SIFT에 대한 차이 설명 부분도 없는거 같습니다. 왜 Dense Feature를 사용해야 하는지 설명 부탁드립니다.\n4. 각 함수의 입력 아규먼트 설명이 없는 것 같습니다.\n    예를들어 build_codebook(X, voc_size) 에서 X가 뭐고 어떤 형태의 행렬로 넣어야 되는지 정보가 부족해 보입니다. Matrix는 행과 열에 맞춰서 정보를 담아야 하니 이런 설명이 중요해 보입니다.\n5. BoW(image, descriptor, codebook) 에서 입력 image 는 사용되지 않는데 왜 넣는거죠?\n6. SVM에 대한 이론은 다른 웹사이트가 아닌 교수님 강의를 참고하라고 넣는게 맞는 거 같습니다. (교안을 좀 보시는게 어떤가요)\n    최대한 수업과 연관지어주는 것이 학생들의 학습을 위해 좋지 않을까요?\n"
    },
    {
      "id": 1073106,
      "postDate": "2020-11-09T06:07:25.377Z",
      "content": "<h1>BoVW</h1>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F309d819c6b29f7149c8a66e09e0f7da6%2FBow.png?generation=1604901070523914&amp;alt=media\" alt=\"\"><br>\n[그림 1] BoVW의 흐름도 <br>\nBoVW는 원래 Bag of Words(BoW)로 문서를 분류하기 위한 방법론으로 사용됐다. 문서 속 단어의 분포를 통해서 문서의 라벨을 추측하는 방법론이다. 이러한 방법론을 영상분류에 적용하기 위해서, 문서 속 단어의 분포를 영상의 특징점의 분포로 바꾼 것이 BoVW이다. <br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F287379c7e001b9c910af74a4d2c889a2%2FBoW_all.png?generation=1604905204813436&amp;alt=media\" alt=\"\"><br>\n[그림 2] BoVW 설명도 0<br>\nBoVW 의 전체적인 이해를 위해 그림 2번을 보면 아래와 같은 순서로 진행 된다. </p>\n<ul>\n<li>1. 각 클래스 사진들의 <strong>특징점</strong>을 검출한 후 사진 하단 부처럼 모은다. </li>\n<li>2. 모은 모든 특징점을 분석하여, 사진 중단부 그래프 속 x축 즉 모든 영상을 대표할 특징점들(codebook)을 선정한다. </li>\n<li>3. 사진 중단부 그래프와 같이 선정한 codebook 이 각 영상에 포함된 빈도 (histogram)를 모든 영상에 대해 구한다. 이 <strong>Histogram</strong> 이 2D 영상을 표현하는 1D vector 가 된다. </li>\n<li>4. 3번 과정을 통해 구한 1D vector를 feature vector로 생각하여 SVM을 학습하여 최종적으로 classification을 진행한다. </li>\n</ul>\n<h2>1. 영상 특징점(SIFT) 검출</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F47ee45e50d86f04bf4df3fc250bf8cb0%2FBow_1.png?generation=1604903376894286&amp;alt=media\" alt=\"\">  <br>\n[그림 3] BoVW 설명도 1, 영상 특징점 검출(words 검출)<br>\n기존 BoW가 단어의 분포를 보고 문서의 라벨을 추측했다면, BoVW는 영상의 특징점 분포를 보고 라벨을 추측한다. 설명을 위해 그림 3를 보면 , 사람 영상 속에서 특징이라 할 수 있는 특징점(눈,코,입, 턱 등) 을 특징점(\"words\") 라고 지칭하여 저장한다. <strong>예시를 위해서 특징점을 (눈,코,입 등) 으로 표현했지만 사실은 밝기값의 차이 등을 활용한 SIFT라는 영상의 특징점 검출하는 알고리즘을 사용한다.</strong><br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F08d89223aa2fbe3c2677a1c05a33c4ec%2FSIFT.png?generation=1604904329992771&amp;alt=media\" alt=\"\"><br>\n[그림 4]  SIFT 표현<br>\nSIFT를 사용해 영상의 특징점을 추출하여, 추출된 곳은 표현하면 그림 4 과 같이 표현 할 수 있다. SIFT에 관한 자세한 설명은 참고 자료들을 보길 바란다. </p>\n<h3>DenseSIFT</h3>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2Fe6decfdd3c78d611a87c8d5e6071ff85%2FSIFT.png?generation=1605022203856596&amp;alt=media\" alt=\"\"><br>\n[그림 SIFT] DenseSIFT와 SIFT 비교 <br>\nSIFT는 영상 전체를 분석하여 특징점을 추출한다. 이렇게 영상을 분석을 하면 특징점이 영상 전체에 고르게 분포되지 않고 특정 위치에 몰려있거나 아예 특징점이 검출되지 않을 수도있다. 따라서 영상의 모든 부분의 특징을 사용하기 위해서 DenseSIFT가 사용된다. DenseSIFT는 keypoint 즉 특징점의 위치를 미리 선정해두고 그 위치에서 특징점을 검출한다. SIFT와 DenseSIFT의 차이는 그림 SIFT를 통해 확인 할 수 있다. </p>\n<h3>코드 구현</h3>\n<ul>\n<li>기본 SIFT 구현 </li>\n</ul>\n<pre><code>def extract_sift_descriptors(img): # img.shape==[256,256,3]\n   ## SIFT 정의\n   sift = cv2.xfeatures2d.SIFT_create()\n   ## 영상의 키포인트를 detect 하고 키포인트의 Descriptor를 compute 하는것을 동시에 진행    \n   keypoints, descriptors = sift.detectAndCompute(img, None)\n   ## descriptor 반환\n   return descriptors\n</code></pre>\n<ul>\n<li>Dense SIFT구현</li>\n</ul>\n<pre><code>def extract_DenseSift_descriptors(img): # img.shape==[256,256,3]\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   return descriptors\n</code></pre>\n<h2>2. Codebook 생성</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F4359c190255960253b37f96f69a0d922%2Fcodevook.png?generation=1604904714473588&amp;alt=media\" alt=\"\"><br>\n[그림 5] BoVW 설명도 2 , Codebook<br>\n모든 영상의 SIFT 특징점을 검출하여 [그림 5]와 같이 모은다. 이렇게 모은 모든 특징점을 분석하여 이 전체 데이터셋을 대표할 수 있는 특징점들을 찾아야 한다. <br>\n<img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F6ab011a3a36dac8b1ad1ed16431c8624%2FKmeans.png?generation=1604906528788962&amp;alt=media\" alt=\"\"><br>\n[그림 6] Kmeans clustering <br>\n모든 특징점을 대표할 수 있는 특징점(Codebook)을 찾는 방법론으로 Kmeans clustering 을 사용한다.  이 방법론은 데이터를 입력받아 이를 소수의 그룹으로 묶는 알고리즘이다. 이 알고리즘은 [그림 6]처럼 label이 없는 데이터를 입력받아 각 데이터에 label을 할당함으로써 군집화를 수행한다. 군집화를 한 후 각 군집을 표현할 수 있는 중심점들을 Codebook으로 사용한다. 군집의 갯수는 사용자가 정하는 것으로 클수록 좋다. (물론 어느순간부터 성능은 수렴한다. 약 cluster 2000개 정도부터는 수렴한다는 보고가 있다.) <br>\nKmeans 가 데이터를 군집화 하는 방식은 참고사이트에서 확인 바란다. </p>\n<h3>코드 구현</h3>\n<ul>\n<li>X=모든 영상의 특징점을 모은 Matrix</li>\n<li>X.shape ==[3060, 1024, 128]==[ 영상 갯수, 키포인트 갯수,SIFT descriptor길이] </li>\n<li>voc_size==cluster갯수</li>\n</ul>\n<pre><code>def build_codebook(X, voc_size): \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</code></pre>\n<h3>GPU Kmeans</h3>\n<ul>\n<li>Kmeans는 데이터가 많을떄 CPU로 처리한다면 시간이 오래 걸릴 것입니다. 아마 이번 문제도 약 한시간 정도 걸리는 것으로 알고 있습니다.</li>\n<li>시간문제를 해결 하기 위해서 Kmeans를 CPU로 연산하지 않고, GPU로 연산하는 방식 있습니다. GPU를 사용하는 방식은 kmc2 라이브러리를 사용하는 것이다. </li>\n</ul>\n<pre><code>def build_codebook_GPU(X, voc_size):\n   ###########################################\n   # X를 [3060*128]로 reshape\n   # kmc2.kmc2() 에 reshape 된 X와 voc_size를 입력으로 넣고 정의 \n   # Kmeans는 MiniBatchKMeans를 사용하며 MiniBatchKMeans 정의 시 init에 kmc2.kmc2로 정의된 변수 입력 \n   # MiniBatchKMeans 의 fit 함수를 사용해 data의 cluster center 찾기\n   ###########################################    \n   return # MiniBatchKMeans 내장 변수인 cluster_center_를 반환\n</code></pre>\n<h2>3. Histogram 생성</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F77ec2160ce96fb8e6a888e02ec9960f3%2FBow_hist.png?generation=1604907320515797&amp;alt=media\" alt=\"\"><br>\n[그림 7] BoVW 설명도 3. Histogram<br>\nCodebook을 생성한 후, 그림 7 과 같이 각 영상의 특징점과 Codebook을 비교하여 Histogram을 생성합니다. 특징점과 codebook을 비교하여, 그 특징점과 가장 유사한 Cluster center의 빈도 수를 높히는 것이다. 영상의 모든 특징점과 codebook을 비교하여 histogram을 생성하게 되면, 2D 영상을 1D feature vector로 표현할 수 있게 된다.     </p>\n<h3>코드 구현</h3>\n<ul>\n<li>def BoW( descriptor, codebook)<ul>\n<li>descriptor= 영상하나의 특징점 Matrix </li>\n<li>descriptor.shape==[1024,128]</li>\n<li>codebook= Kmeans를 통해 검출한 Cluster centers </li>\n<li>codebook.shape==[num_cluster,1024,128]</li></ul></li>\n<li>def input_vector_encoder(feature, codebook)<ul>\n<li>feature=descriptor</li>\n<li>codebook=codebook</li></ul></li>\n</ul>\n<pre><code>def input_vector_encoder(feature, codebook): \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\ndef BoW( descriptor, codebook):\n   code = input_vector_encoder(descriptor.tolist(), codebook) \n   return # code를 flatten 하여 반환 \n</code></pre>\n<h2>4. SVM : classification</h2>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F8c305606c612af03417ef3334e47e575%2FSVM.png?generation=1605013920265537&amp;alt=media\" alt=\"\"><br>\n[그림 8] SVM <br>\nHistogram으로 이루어진 feature vector 를 이용해 Classification을 진행할때는, 머신러닝의 정석적인 방법론이라 할수있는 Support vector maching(SVM)을 사용한다.  SVM은 결정 경계(Decision Boundary) 즉 분류를 위한 기준 선을 정의하는 모델이다. 이 모델은 그림 8의 margin 즉 선과 데이터의 최단 거리가 최대한 먼 경계를 찾는 것을 목표로 한다.  자세한 설명은 참고 사이트를 확인 바란다. <br>\nSVM 을 통해 Decision Boundary를 찾게 된다면 Test dataset의 라벨을 분류 할 수 있게된다. </p>\n<h3>코드 구현</h3>\n<ul>\n<li>def SVM(train_data,train_label,test_data)<ul>\n<li>train_data=모든 학습 영상의 BoW Matrix</li>\n<li>train_data.shape==[3060,200]</li>\n<li>train_label=모든 학습 영상의 라벨</li>\n<li>train_label.shape==[3060,]</li>\n<li>test_data=모든 시험 영상의 BoW Matrix </li>\n<li>test_data.shape==[1712,200]</li></ul></li>\n</ul>\n<pre><code>def 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\n</code></pre>\n<h2>5. Inference</h2>\n<p>SVM 까지 학습을 완료하면 Test Set의 라벨을 추정할 수 있게 된다. 추정하는 과정을 다시 요약하면 다음과 같다. </p>\n<ul>\n<li>1. Test 영상의 SIFT 특징점 검출</li>\n<li>2. SIFT 특징점와 codebook을 비교해 histogram 생성</li>\n<li>3. histogram 을 SVM 모델에 넣어 클래스를 추정 </li>\n</ul>\n<h3>참고 자료</h3>\n<ul>\n<li><a href=\"https://darkpgmr.tistory.com/125\" target=\"_blank\">BoVW</a></li>\n<li><a href=\"https://darkpgmr.tistory.com/131\" target=\"_blank\">영상 특징점 &amp;&amp; SIFT</a></li>\n<li><a href=\"https://bskyvision.com/21\" target=\"_blank\">SIFT</a></li>\n<li><a href=\"https://untitledtblog.tistory.com/132\" target=\"_blank\">kmeans</a></li>\n<li><a href=\"https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%8B%E1%85%B5%E1%84%85%E1%85%A9%E1%86%AB.pdf\" target=\"_blank\">SVM 이론</a></li>\n<li><a href=\"https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%89%E1%85%B5%E1%86%AF%E1%84%89%E1%85%B3%E1%86%B8.pdf\" target=\"_blank\">SVM 실습</a></li>\n</ul>",
      "rawMarkdown": "\n# BoVW\n ![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F309d819c6b29f7149c8a66e09e0f7da6%2FBow.png?generation=1604901070523914&alt=media)\n[그림 1] BoVW의 흐름도 \n\nBoVW는 원래 Bag of Words(BoW)로 문서를 분류하기 위한 방법론으로 사용됐다. 문서 속 단어의 분포를 통해서 문서의 라벨을 추측하는 방법론이다. 이러한 방법론을 영상분류에 적용하기 위해서, 문서 속 단어의 분포를 영상의 특징점의 분포로 바꾼 것이 BoVW이다. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F287379c7e001b9c910af74a4d2c889a2%2FBoW_all.png?generation=1604905204813436&alt=media)\n[그림 2] BoVW 설명도 0\n\nBoVW 의 전체적인 이해를 위해 그림 2번을 보면 아래와 같은 순서로 진행 된다. \n- 1. 각 클래스 사진들의 **특징점**을 검출한 후 사진 하단 부처럼 모은다. \n- 2. 모은 모든 특징점을 분석하여, 사진 중단부 그래프 속 x축 즉 모든 영상을 대표할 특징점들(codebook)을 선정한다. \n- 3. 사진 중단부 그래프와 같이 선정한 codebook 이 각 영상에 포함된 빈도 (histogram)를 모든 영상에 대해 구한다. 이 **Histogram** 이 2D 영상을 표현하는 1D vector 가 된다. \n- 4. 3번 과정을 통해 구한 1D vector를 feature vector로 생각하여 SVM을 학습하여 최종적으로 classification을 진행한다. \n\n## 1. 영상 특징점(SIFT) 검출\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F47ee45e50d86f04bf4df3fc250bf8cb0%2FBow_1.png?generation=1604903376894286&alt=media)  \n[그림 3] BoVW 설명도 1, 영상 특징점 검출(words 검출)\n\n 기존 BoW가 단어의 분포를 보고 문서의 라벨을 추측했다면, BoVW는 영상의 특징점 분포를 보고 라벨을 추측한다. 설명을 위해 그림 3를 보면 , 사람 영상 속에서 특징이라 할 수 있는 특징점(눈,코,입, 턱 등) 을 특징점(\"words\") 라고 지칭하여 저장한다. **예시를 위해서 특징점을 (눈,코,입 등) 으로 표현했지만 사실은 밝기값의 차이 등을 활용한 SIFT라는 영상의 특징점 검출하는 알고리즘을 사용한다.**\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F08d89223aa2fbe3c2677a1c05a33c4ec%2FSIFT.png?generation=1604904329992771&alt=media)\n[그림 4]  SIFT 표현\n\n SIFT를 사용해 영상의 특징점을 추출하여, 추출된 곳은 표현하면 그림 4 과 같이 표현 할 수 있다. SIFT에 관한 자세한 설명은 참고 자료들을 보길 바란다. \n\n### DenseSIFT\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2Fe6decfdd3c78d611a87c8d5e6071ff85%2FSIFT.png?generation=1605022203856596&alt=media)\n[그림 SIFT] DenseSIFT와 SIFT 비교 \n\nSIFT는 영상 전체를 분석하여 특징점을 추출한다. 이렇게 영상을 분석을 하면 특징점이 영상 전체에 고르게 분포되지 않고 특정 위치에 몰려있거나 아예 특징점이 검출되지 않을 수도있다. 따라서 영상의 모든 부분의 특징을 사용하기 위해서 DenseSIFT가 사용된다. DenseSIFT는 keypoint 즉 특징점의 위치를 미리 선정해두고 그 위치에서 특징점을 검출한다. SIFT와 DenseSIFT의 차이는 그림 SIFT를 통해 확인 할 수 있다. \n\n### 코드 구현 \n- 기본 SIFT 구현 \n```\ndef extract_sift_descriptors(img): # img.shape==[256,256,3]\n\n    ## SIFT 정의\n    sift = cv2.xfeatures2d.SIFT_create()\n    ## 영상의 키포인트를 detect 하고 키포인트의 Descriptor를 compute 하는것을 동시에 진행    \n    keypoints, descriptors = sift.detectAndCompute(img, None)\n    ## descriptor 반환\n    return descriptors\n```\n\n- Dense SIFT구현\n\n```\ndef extract_DenseSift_descriptors(img): # img.shape==[256,256,3]\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```\n## 2. Codebook 생성\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F4359c190255960253b37f96f69a0d922%2Fcodevook.png?generation=1604904714473588&alt=media)\n[그림 5] BoVW 설명도 2 , Codebook\n\n 모든 영상의 SIFT 특징점을 검출하여 [그림 5]와 같이 모은다. 이렇게 모은 모든 특징점을 분석하여 이 전체 데이터셋을 대표할 수 있는 특징점들을 찾아야 한다. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F6ab011a3a36dac8b1ad1ed16431c8624%2FKmeans.png?generation=1604906528788962&alt=media)\n[그림 6] Kmeans clustering \n\n 모든 특징점을 대표할 수 있는 특징점(Codebook)을 찾는 방법론으로 Kmeans clustering 을 사용한다.  이 방법론은 데이터를 입력받아 이를 소수의 그룹으로 묶는 알고리즘이다. 이 알고리즘은 [그림 6]처럼 label이 없는 데이터를 입력받아 각 데이터에 label을 할당함으로써 군집화를 수행한다. 군집화를 한 후 각 군집을 표현할 수 있는 중심점들을 Codebook으로 사용한다. 군집의 갯수는 사용자가 정하는 것으로 클수록 좋다. (물론 어느순간부터 성능은 수렴한다. 약 cluster 2000개 정도부터는 수렴한다는 보고가 있다.) \n\nKmeans 가 데이터를 군집화 하는 방식은 참고사이트에서 확인 바란다. \n### 코드 구현 \n- X=모든 영상의 특징점을 모은 Matrix\n- X.shape ==[3060, 1024, 128]==[ 영상 갯수, 키포인트 갯수,SIFT descriptor길이] \n- voc_size==cluster갯수\n```\ndef build_codebook(X, voc_size): \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```\n### GPU Kmeans \n\n- Kmeans는 데이터가 많을떄 CPU로 처리한다면 시간이 오래 걸릴 것입니다. 아마 이번 문제도 약 한시간 정도 걸리는 것으로 알고 있습니다.\n- 시간문제를 해결 하기 위해서 Kmeans를 CPU로 연산하지 않고, GPU로 연산하는 방식 있습니다. GPU를 사용하는 방식은 kmc2 라이브러리를 사용하는 것이다. \n```\ndef build_codebook_GPU(X, voc_size):\n\n    ###########################################\n    # X를 [3060*128]로 reshape\n    # kmc2.kmc2() 에 reshape 된 X와 voc_size를 입력으로 넣고 정의 \n    # Kmeans는 MiniBatchKMeans를 사용하며 MiniBatchKMeans 정의 시 init에 kmc2.kmc2로 정의된 변수 입력 \n    # MiniBatchKMeans 의 fit 함수를 사용해 data의 cluster center 찾기\n    ###########################################    \n    return # MiniBatchKMeans 내장 변수인 cluster_center_를 반환\n\n```\n## 3. Histogram 생성\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F77ec2160ce96fb8e6a888e02ec9960f3%2FBow_hist.png?generation=1604907320515797&alt=media)\n[그림 7] BoVW 설명도 3. Histogram\n\n Codebook을 생성한 후, 그림 7 과 같이 각 영상의 특징점과 Codebook을 비교하여 Histogram을 생성합니다. 특징점과 codebook을 비교하여, 그 특징점과 가장 유사한 Cluster center의 빈도 수를 높히는 것이다. 영상의 모든 특징점과 codebook을 비교하여 histogram을 생성하게 되면, 2D 영상을 1D feature vector로 표현할 수 있게 된다.     \n\n### 코드 구현 \n- def BoW( descriptor, codebook)\n    - descriptor= 영상하나의 특징점 Matrix \n    - descriptor.shape==[1024,128]\n    - codebook= Kmeans를 통해 검출한 Cluster centers \n    - codebook.shape==[num_cluster,1024,128]\n- def input_vector_encoder(feature, codebook)\n    - feature=descriptor\n    - codebook=codebook\n    \n```\ndef input_vector_encoder(feature, codebook): \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```\n## 4. SVM : classification \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F8c305606c612af03417ef3334e47e575%2FSVM.png?generation=1605013920265537&alt=media)\n[그림 8] SVM \n\n Histogram으로 이루어진 feature vector 를 이용해 Classification을 진행할때는, 머신러닝의 정석적인 방법론이라 할수있는 Support vector maching(SVM)을 사용한다.  SVM은 결정 경계(Decision Boundary) 즉 분류를 위한 기준 선을 정의하는 모델이다. 이 모델은 그림 8의 margin 즉 선과 데이터의 최단 거리가 최대한 먼 경계를 찾는 것을 목표로 한다.  자세한 설명은 참고 사이트를 확인 바란다. \n SVM 을 통해 Decision Boundary를 찾게 된다면 Test dataset의 라벨을 분류 할 수 있게된다. \n\n### 코드 구현 \n- def SVM(train_data,train_label,test_data)\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```\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\n```\n## 5. Inference \n\nSVM 까지 학습을 완료하면 Test Set의 라벨을 추정할 수 있게 된다. 추정하는 과정을 다시 요약하면 다음과 같다. \n\n- 1. Test 영상의 SIFT 특징점 검출\n- 2. SIFT 특징점와 codebook을 비교해 histogram 생성\n- 3. histogram 을 SVM 모델에 넣어 클래스를 추정 \n\n### 참고 자료\n\n- [BoVW](https://darkpgmr.tistory.com/125)\n- [영상 특징점 && SIFT](https://darkpgmr.tistory.com/131)\n- [SIFT](https://bskyvision.com/21)\n- [kmeans](https://untitledtblog.tistory.com/132)\n- [SVM 이론](https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%8B%E1%85%B5%E1%84%85%E1%85%A9%E1%86%AB.pdf)\n- [SVM 실습](https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%89%E1%85%B5%E1%86%AF%E1%84%89%E1%85%B3%E1%86%B8.pdf)"
    },
    {
      "id": 1073109,
      "postDate": "2020-11-09T06:13:59.250Z",
      "rawMarkdown": "",
      "isDeleted": true
    }
  ],
  "comments": [
    {
      "id": 1073981,
      "author_name": "Yukyung Choi",
      "author_url": "",
      "post_date": "2020-11-10T05:27:42.540000",
      "content": "<p>[한대찬 조교님] </p>\n<ol>\n<li>참고자료는 맨 밑으로 내려주세요. </li>\n<li>extract_sift_descriptors() 사용을 위해 RGB영상을 흑백영상으로 변경해야 하는 설명이 없는 것 같습니다.</li>\n<li>Dense SIFT에 대한 설명이 없는 것 같습니다. 그리고 Sparse SIFT와 Dense SIFT에 대한 차이 설명 부분도 없는거 같습니다. 왜 Dense Feature를 사용해야 하는지 설명 부탁드립니다.</li>\n<li>각 함수의 입력 아규먼트 설명이 없는 것 같습니다.<br>\n예를들어 build_codebook(X, voc_size) 에서 X가 뭐고 어떤 형태의 행렬로 넣어야 되는지 정보가 부족해 보입니다. Matrix는 행과 열에 맞춰서 정보를 담아야 하니 이런 설명이 중요해 보입니다.</li>\n<li>BoW(image, descriptor, codebook) 에서 입력 image 는 사용되지 않는데 왜 넣는거죠?</li>\n<li>SVM에 대한 이론은 다른 웹사이트가 아닌 교수님 강의를 참고하라고 넣는게 맞는 거 같습니다. (교안을 좀 보시는게 어떤가요)<br>\n최대한 수업과 연관지어주는 것이 학생들의 학습을 위해 좋지 않을까요?</li>\n</ol>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 1073109,
      "author_name": "",
      "author_url": "",
      "post_date": "2020-11-09T06:13:59.250000",
      "content": "",
      "votes": 0,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "1073981": "[한대찬 조교님] \n1. 참고자료는 맨 밑으로 내려주세요. \n2. extract_sift_descriptors() 사용을 위해 RGB영상을 흑백영상으로 변경해야 하는 설명이 없는 것 같습니다.\n3. Dense SIFT에 대한 설명이 없는 것 같습니다. 그리고 Sparse SIFT와 Dense SIFT에 대한 차이 설명 부분도 없는거 같습니다. 왜 Dense Feature를 사용해야 하는지 설명 부탁드립니다.\n4. 각 함수의 입력 아규먼트 설명이 없는 것 같습니다.\n    예를들어 build_codebook(X, voc_size) 에서 X가 뭐고 어떤 형태의 행렬로 넣어야 되는지 정보가 부족해 보입니다. Matrix는 행과 열에 맞춰서 정보를 담아야 하니 이런 설명이 중요해 보입니다.\n5. BoW(image, descriptor, codebook) 에서 입력 image 는 사용되지 않는데 왜 넣는거죠?\n6. SVM에 대한 이론은 다른 웹사이트가 아닌 교수님 강의를 참고하라고 넣는게 맞는 거 같습니다. (교안을 좀 보시는게 어떤가요)\n    최대한 수업과 연관지어주는 것이 학생들의 학습을 위해 좋지 않을까요?\n",
    "1073106": "\n# BoVW\n ![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F309d819c6b29f7149c8a66e09e0f7da6%2FBow.png?generation=1604901070523914&alt=media)\n[그림 1] BoVW의 흐름도 \n\nBoVW는 원래 Bag of Words(BoW)로 문서를 분류하기 위한 방법론으로 사용됐다. 문서 속 단어의 분포를 통해서 문서의 라벨을 추측하는 방법론이다. 이러한 방법론을 영상분류에 적용하기 위해서, 문서 속 단어의 분포를 영상의 특징점의 분포로 바꾼 것이 BoVW이다. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F287379c7e001b9c910af74a4d2c889a2%2FBoW_all.png?generation=1604905204813436&alt=media)\n[그림 2] BoVW 설명도 0\n\nBoVW 의 전체적인 이해를 위해 그림 2번을 보면 아래와 같은 순서로 진행 된다. \n- 1. 각 클래스 사진들의 **특징점**을 검출한 후 사진 하단 부처럼 모은다. \n- 2. 모은 모든 특징점을 분석하여, 사진 중단부 그래프 속 x축 즉 모든 영상을 대표할 특징점들(codebook)을 선정한다. \n- 3. 사진 중단부 그래프와 같이 선정한 codebook 이 각 영상에 포함된 빈도 (histogram)를 모든 영상에 대해 구한다. 이 **Histogram** 이 2D 영상을 표현하는 1D vector 가 된다. \n- 4. 3번 과정을 통해 구한 1D vector를 feature vector로 생각하여 SVM을 학습하여 최종적으로 classification을 진행한다. \n\n## 1. 영상 특징점(SIFT) 검출\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F47ee45e50d86f04bf4df3fc250bf8cb0%2FBow_1.png?generation=1604903376894286&alt=media)  \n[그림 3] BoVW 설명도 1, 영상 특징점 검출(words 검출)\n\n 기존 BoW가 단어의 분포를 보고 문서의 라벨을 추측했다면, BoVW는 영상의 특징점 분포를 보고 라벨을 추측한다. 설명을 위해 그림 3를 보면 , 사람 영상 속에서 특징이라 할 수 있는 특징점(눈,코,입, 턱 등) 을 특징점(\"words\") 라고 지칭하여 저장한다. **예시를 위해서 특징점을 (눈,코,입 등) 으로 표현했지만 사실은 밝기값의 차이 등을 활용한 SIFT라는 영상의 특징점 검출하는 알고리즘을 사용한다.**\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F08d89223aa2fbe3c2677a1c05a33c4ec%2FSIFT.png?generation=1604904329992771&alt=media)\n[그림 4]  SIFT 표현\n\n SIFT를 사용해 영상의 특징점을 추출하여, 추출된 곳은 표현하면 그림 4 과 같이 표현 할 수 있다. SIFT에 관한 자세한 설명은 참고 자료들을 보길 바란다. \n\n### DenseSIFT\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2Fe6decfdd3c78d611a87c8d5e6071ff85%2FSIFT.png?generation=1605022203856596&alt=media)\n[그림 SIFT] DenseSIFT와 SIFT 비교 \n\nSIFT는 영상 전체를 분석하여 특징점을 추출한다. 이렇게 영상을 분석을 하면 특징점이 영상 전체에 고르게 분포되지 않고 특정 위치에 몰려있거나 아예 특징점이 검출되지 않을 수도있다. 따라서 영상의 모든 부분의 특징을 사용하기 위해서 DenseSIFT가 사용된다. DenseSIFT는 keypoint 즉 특징점의 위치를 미리 선정해두고 그 위치에서 특징점을 검출한다. SIFT와 DenseSIFT의 차이는 그림 SIFT를 통해 확인 할 수 있다. \n\n### 코드 구현 \n- 기본 SIFT 구현 \n```\ndef extract_sift_descriptors(img): # img.shape==[256,256,3]\n\n    ## SIFT 정의\n    sift = cv2.xfeatures2d.SIFT_create()\n    ## 영상의 키포인트를 detect 하고 키포인트의 Descriptor를 compute 하는것을 동시에 진행    \n    keypoints, descriptors = sift.detectAndCompute(img, None)\n    ## descriptor 반환\n    return descriptors\n```\n\n- Dense SIFT구현\n\n```\ndef extract_DenseSift_descriptors(img): # img.shape==[256,256,3]\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```\n## 2. Codebook 생성\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F4359c190255960253b37f96f69a0d922%2Fcodevook.png?generation=1604904714473588&alt=media)\n[그림 5] BoVW 설명도 2 , Codebook\n\n 모든 영상의 SIFT 특징점을 검출하여 [그림 5]와 같이 모은다. 이렇게 모은 모든 특징점을 분석하여 이 전체 데이터셋을 대표할 수 있는 특징점들을 찾아야 한다. \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F6ab011a3a36dac8b1ad1ed16431c8624%2FKmeans.png?generation=1604906528788962&alt=media)\n[그림 6] Kmeans clustering \n\n 모든 특징점을 대표할 수 있는 특징점(Codebook)을 찾는 방법론으로 Kmeans clustering 을 사용한다.  이 방법론은 데이터를 입력받아 이를 소수의 그룹으로 묶는 알고리즘이다. 이 알고리즘은 [그림 6]처럼 label이 없는 데이터를 입력받아 각 데이터에 label을 할당함으로써 군집화를 수행한다. 군집화를 한 후 각 군집을 표현할 수 있는 중심점들을 Codebook으로 사용한다. 군집의 갯수는 사용자가 정하는 것으로 클수록 좋다. (물론 어느순간부터 성능은 수렴한다. 약 cluster 2000개 정도부터는 수렴한다는 보고가 있다.) \n\nKmeans 가 데이터를 군집화 하는 방식은 참고사이트에서 확인 바란다. \n### 코드 구현 \n- X=모든 영상의 특징점을 모은 Matrix\n- X.shape ==[3060, 1024, 128]==[ 영상 갯수, 키포인트 갯수,SIFT descriptor길이] \n- voc_size==cluster갯수\n```\ndef build_codebook(X, voc_size): \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```\n### GPU Kmeans \n\n- Kmeans는 데이터가 많을떄 CPU로 처리한다면 시간이 오래 걸릴 것입니다. 아마 이번 문제도 약 한시간 정도 걸리는 것으로 알고 있습니다.\n- 시간문제를 해결 하기 위해서 Kmeans를 CPU로 연산하지 않고, GPU로 연산하는 방식 있습니다. GPU를 사용하는 방식은 kmc2 라이브러리를 사용하는 것이다. \n```\ndef build_codebook_GPU(X, voc_size):\n\n    ###########################################\n    # X를 [3060*128]로 reshape\n    # kmc2.kmc2() 에 reshape 된 X와 voc_size를 입력으로 넣고 정의 \n    # Kmeans는 MiniBatchKMeans를 사용하며 MiniBatchKMeans 정의 시 init에 kmc2.kmc2로 정의된 변수 입력 \n    # MiniBatchKMeans 의 fit 함수를 사용해 data의 cluster center 찾기\n    ###########################################    \n    return # MiniBatchKMeans 내장 변수인 cluster_center_를 반환\n\n```\n## 3. Histogram 생성\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F77ec2160ce96fb8e6a888e02ec9960f3%2FBow_hist.png?generation=1604907320515797&alt=media)\n[그림 7] BoVW 설명도 3. Histogram\n\n Codebook을 생성한 후, 그림 7 과 같이 각 영상의 특징점과 Codebook을 비교하여 Histogram을 생성합니다. 특징점과 codebook을 비교하여, 그 특징점과 가장 유사한 Cluster center의 빈도 수를 높히는 것이다. 영상의 모든 특징점과 codebook을 비교하여 histogram을 생성하게 되면, 2D 영상을 1D feature vector로 표현할 수 있게 된다.     \n\n### 코드 구현 \n- def BoW( descriptor, codebook)\n    - descriptor= 영상하나의 특징점 Matrix \n    - descriptor.shape==[1024,128]\n    - codebook= Kmeans를 통해 검출한 Cluster centers \n    - codebook.shape==[num_cluster,1024,128]\n- def input_vector_encoder(feature, codebook)\n    - feature=descriptor\n    - codebook=codebook\n    \n```\ndef input_vector_encoder(feature, codebook): \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```\n## 4. SVM : classification \n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F3879542%2F8c305606c612af03417ef3334e47e575%2FSVM.png?generation=1605013920265537&alt=media)\n[그림 8] SVM \n\n Histogram으로 이루어진 feature vector 를 이용해 Classification을 진행할때는, 머신러닝의 정석적인 방법론이라 할수있는 Support vector maching(SVM)을 사용한다.  SVM은 결정 경계(Decision Boundary) 즉 분류를 위한 기준 선을 정의하는 모델이다. 이 모델은 그림 8의 margin 즉 선과 데이터의 최단 거리가 최대한 먼 경계를 찾는 것을 목표로 한다.  자세한 설명은 참고 사이트를 확인 바란다. \n SVM 을 통해 Decision Boundary를 찾게 된다면 Test dataset의 라벨을 분류 할 수 있게된다. \n\n### 코드 구현 \n- def SVM(train_data,train_label,test_data)\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```\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\n```\n## 5. Inference \n\nSVM 까지 학습을 완료하면 Test Set의 라벨을 추정할 수 있게 된다. 추정하는 과정을 다시 요약하면 다음과 같다. \n\n- 1. Test 영상의 SIFT 특징점 검출\n- 2. SIFT 특징점와 codebook을 비교해 histogram 생성\n- 3. histogram 을 SVM 모델에 넣어 클래스를 추정 \n\n### 참고 자료\n\n- [BoVW](https://darkpgmr.tistory.com/125)\n- [영상 특징점 && SIFT](https://darkpgmr.tistory.com/131)\n- [SIFT](https://bskyvision.com/21)\n- [kmeans](https://untitledtblog.tistory.com/132)\n- [SVM 이론](https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%8B%E1%85%B5%E1%84%85%E1%85%A9%E1%86%AB.pdf)\n- [SVM 실습](https://github.com/sejongresearch/2020.MachineLearning/blob/master/LectureNote/10%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1_SVM(%E1%84%80%E1%85%B5%E1%84%80%E1%85%A8%E1%84%92%E1%85%A1%E1%86%A8%E1%84%89%E1%85%B3%E1%86%B8)_%E1%84%89%E1%85%B5%E1%86%AF%E1%84%89%E1%85%B3%E1%86%B8.pdf)",
    "1073109": ""
  }
}