레이블이 Caffe인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Caffe인 게시물을 표시합니다. 모든 게시물 표시

2017년 8월 20일 일요일

jetson tx2 board - face detect - face verification - hand gesture classification

 skt - nvidia 에서 진행한 t 해커톤에 참가했었습니다. 주제는 jetson tx2 board를 이용한 AI 제품 개발이 었고, 2017 8/26,27 무박 2일로 진행했습니다. 하루만에 시제품을 만들어내느라 엄청난 몰입을 했고, 좋은 팀원들과 협업도 해서 재미있는 경험이었습니다. (끝나고 나서는 엄청난 피로가 몰려왔지만ㅜ)

 jetson에 face detect, face verification 과 hand gesture classification으로 password 입력, face classification 해서 인물에 따라 안내 SMS 를 보내는 기능 등을 개발 했습니다.

 deep learning frame work는 caffe 를 사용했고, 메인 code는 qt에서 c++로 작성했습니다. source code는 여기 (https://github.com/ttagu99/dguardian) 에 있습니다.
  training도 caffe 이긴 한데 제가 bvlc 에서 fork해서 몇몇 기능을 추가한 거라, 이번에 사용한 train_val.prototxt는 bvlc caffe에서는 바로 안돌아 갑니다. 제 caffe code는 여기(https://github.com/ttagu99/caffe/tree/caffe_nccl)에 있습니다.

 아래 동영상은 집주인인 저의 얼굴을 인식, 인증하고, 제 Password인 손동작을 인식해서 문이 열리는 것입니다.





 아래 동영상은 집주인이 누군가와 같이 와서 Password를 보여주면 안되니 경고를 띄워주는 것과, 강도에게 협박 당해서 문을 열어야 할 경우 문은 열어 주되, 내부적으로 경찰에 신고 하는 겁니다. (지금은 진짜 경찰에 신고는 아니고 ㅎ, 제 핸드폰으로 문자를 보내는걸로 구현했습니다.)



 아래 동영상은 미리 등록된 범죄자의 얼굴을 인식해서, 집앞에 나타날 경우 경찰에 신고하는 동영상입니다. (이것도 물론 제 전화로 문자만)




 아래 동영상은 미리 등록된 택배기사님의 얼굴을 인식하고, 물건을 맡길 것을 안내하고, 집주인에게는 택배가 도착했다고 안내 SMS를 보내주는 시나리오입니다.





 아래 동영상은 외부인이 밖에 있을 경우, 집에서 나가려고 할때 밖에 누군가 있다고 알려주고, 문을 열지 물어봤을때 거절을 하는 시나리오입니다.




 아래 동영상은 외부인이 밖에 있을 경우, 집에서 나가려고 할때 밖에 누군가 있다고 알려주고, 문을 열지 물어봤을때 승락을 하는 시나리오입니다.






2017년 6월 3일 토요일

opencv Mat 를 caffe datum으로 변환, datum을 Mat로 변환

 기존 opencv에서 영상처리 하던게 익숙해서 caffe를 Mat로 변환 후에 Opencv 로 처리 할 경우가 많은데, bvlc caffe에 아직 float형 image와 multi channel(4개 이상) 이미지 변환함수가 안 만들어져 있어서 만들어 보았습니다.

 아래는 Mat를 datum으로 변환하는 것.
void CVMatToDatum(const cv::Mat& cv_img, Datum* datum, int depth)
{
 if (depth == CV_8U)
 {
  CVMatToDatum(cv_img, datum);
  return;
 }

 CHECK(cv_img.depth() == CV_32F) << "data type must be 32bit float";

 datum->set_channels(cv_img.channels());
 datum->set_height(cv_img.rows);
 datum->set_width(cv_img.cols);
 datum->clear_data();
 datum->clear_float_data();
 datum->set_encoded(false);
 int datum_channels = datum->channels();
 int datum_height = datum->height();
 int datum_width = datum->width();
 int datum_size = datum_channels * datum_height * datum_width;

 for (int h = 0; h < datum_height; ++h) 
 {
  const float* ptr = cv_img.ptr<float>(h);
  int img_index = 0;
  for (int w = 0; w < datum_width; ++w) {
   for (int c = 0; c < datum_channels; ++c) {
    datum->add_float_data( ptr[img_index++]);
   }
  }
 }
 return;
}

void CVMatToDatum(const cv::Mat& cv_img, Datum* datum) {
  CHECK(cv_img.depth() == CV_8U) << "Image data type must be unsigned byte";
  datum->set_channels(cv_img.channels());
  datum->set_height(cv_img.rows);
  datum->set_width(cv_img.cols);
  datum->clear_data();
  datum->clear_float_data();
  datum->set_encoded(false);
  int datum_channels = datum->channels();
  int datum_height = datum->height();
  int datum_width = datum->width();
  int datum_size = datum_channels * datum_height * datum_width;
  std::string buffer(datum_size, ' ');
  for (int h = 0; h < datum_height; ++h) {
    const uchar* ptr = cv_img.ptr<uchar>(h);
    int img_index = 0;
    for (int w = 0; w < datum_width; ++w) {
      for (int c = 0; c < datum_channels; ++c) {
        int datum_index = (c * datum_height + h) * datum_width + w;
        buffer[datum_index] = static_cast<char>(ptr[img_index++]);
      }
    }
  }
  datum->set_data(buffer);
}

 아래는 datum을 Mat로 변환하는 것.
cv::Mat DatumToCVMat(const Datum& datum)
{
 int datum_channels = datum.channels();
 int datum_height = datum.height();
 int datum_width = datum.width();

 string strData = datum.data();
 cv::Mat cv_img;
 if (strData.size() != 0)
 {
  cv_img.create(datum_height, datum_width, CV_8UC(datum_channels));
  const string& data = datum.data();
  std::vector<char> vec_data(data.c_str(), data.c_str() + data.size());

  for (int h = 0; h < datum_height; ++h) {
   uchar* ptr = cv_img.ptr<uchar>(h);
   int img_index = 0;
   for (int w = 0; w < datum_width; ++w) {
    for (int c = 0; c < datum_channels; ++c) {
     int datum_index = (c * datum_height + h) * datum_width + w;
     ptr[img_index++] = static_cast<uchar>(vec_data[datum_index]);
    }
   }
  }
 }
 else
 {
  cv_img.create(datum_height, datum_width, CV_32FC(datum_channels));
  for (int h = 0; h < datum_height; ++h) {
   float* ptr = cv_img.ptr<float>(h);
   int img_index = 0;
   for (int w = 0; w < datum_width; ++w) {
    for (int c = 0; c < datum_channels; ++c) {
     ptr[img_index++] = static_cast<float>(datum.float_data(img_index));
    }
   }
  }
 }
 return cv_img;
}

2017년 1월 25일 수요일

caffe data augmentation

딥러닝할때 주어진 DATA의 량은 정합성을 좌우 하죠.. 때문에 DATA Augmentation 이 필요하죠.. Caffe 가 기본 제공 하는 augmentation은 random crop 과 mirror(flip vertical) 입니다. 그리고 Train Phase만 사용 가능하구요. 다른 사람들이 만들어 놓은것도 있는데, 추가로 더 필요한 것들이 많네요.

 가장 general 한 방법들이 많이 추가 된 곳이 https://github.com/kevinlin311tw/caffe-augmentation 여기인데 Train phase 만, Image Data Type만 지원합니다. 제 PC 환경에서는 Image Data Type 과 LMDB 로 Train 하는것은.. 약 3배 정도 차이납니다.


그래서 Data Augmentaion 을 추가로 만들어 보았습니다. https://github.com/ttagu99/caffe/tree/windows

 DATA AUGUMENTATION 을 추가합니다. 사용은 아래의 예처럼 쓰면되는데, 주의 할 점은 기존에는 crop_size에 값을 입력할 경우, ramdomly crop을 하게 되는데 변경된 코드에서는 crop_offset_rand를 true로 해줘야 합니다.

  1. layer {
  2. name: "train-data"
  3. type: "Data"
  4. top: "data"
  5. top: "label"
  6. include {
  7. phase: TRAIN
  8. }
  9. transform_param {
  10. mirror: true
  11. flip_hor: true
  12. crop_size: 300
  13. crop_offset_rand: true
  14. mean_file: "CAR_DISTANCE/train.binaryproto"
  15. contrast_adjustment: true
  16. smooth_filtering: true
  17. jpeg_compression: true
  18. rotation_angle_interval: 0
  19. display: false
  20. }
  21. data_param {
  22. source: "CAR_DISTANCE/Train_out/"
  23. batch_size: 10
  24. backend: LMDB
  25. }
  26. }
  27. layer {
  28. name: "val-data"
  29. type: "Data"
  30. top: "data"
  31. top: "label"
  32. include {
  33. phase: TEST
  34. }
  35. transform_param {
  36. mirror: true
  37. flip_hor: true
  38. crop_size: 300
  39.     crop_offset_rand: true
  40. mean_file: "CAR_DISTANCE/validation.binaryproto"
  41.     contrast_adjustment: true
  42. smooth_filtering: true
  43. jpeg_compression: true
  44.     rotation_angle_interval: 0
  45. display: false
  46. }
  47. data_param {
  48. source: "CAR_DISTANCE/Validation_out/"
  49. batch_size: 10
  50. backend: LMDB
  51. }
  52. }

  lmdb type 및 image data tpye 모두 가능합니다. train phase, test phase 모두 가능합니다. @kevinlin311tw/caffe-augmentation 를 기반으로 만들었습니다. Thank you for your inspiration!