Commit 5e008c87 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #276 from Wangyida:cnn_3dobj

parents 8d2c1321 44663a24
......@@ -47,7 +47,7 @@ $ cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules -D BUILD_opencv_re
19. **opencv_xfeatures2d**: Extra 2D Features Framework containing experimental and non-free 2D feature algorithms.
20. **opencv_ximgproc**: Extended Image Processing: Structured Forests / Domain Transform Filter / Guided Filter / Adaptive Manifold Filter / Joint Bilateral Filter / Superpixels.
21. **opencv_xobjdetect**: Integral Channel Features Detector Framework.
22. **opencv_xphoto**: Additional photo processing algorithms: Color balance / Denoising / Inpainting.
......
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})
find_package(Caffe)
if(Caffe_FOUND)
message(STATUS "Caffe: YES")
set(HAVE_CAFFE 1)
else()
message(STATUS "Caffe: NO")
endif()
find_package(Protobuf)
if(Protobuf_FOUND)
message(STATUS "Protobuf: YES")
set(HAVE_PROTOBUF 1)
else()
message(STATUS "Protobuf: NO")
endif()
find_package(Glog)
if(Glog_FOUND)
message(STATUS "Glog: YES")
set(HAVE_GLOG 1)
else()
message(STATUS "Glog: NO")
endif()
if(HAVE_CAFFE)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cnn_3dobj_config.hpp.in
${CMAKE_CURRENT_SOURCE_DIR}/include/opencv2/cnn_3dobj_config.hpp @ONLY)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(${Caffe_FOUND})
include_directories(${Caffe_INCLUDE_DIR})
endif()
set(the_description "CNN for 3D object recognition and pose estimation including a completed Sphere View on 3D objects")
ocv_define_module(cnn_3dobj opencv_core opencv_imgproc opencv_viz opencv_highgui OPTIONAL WRAP python)
if(${Caffe_FOUND})
target_link_libraries(opencv_cnn_3dobj ${Caffe_LIBS} ${Glog_LIBS} ${Protobuf_LIBS})
endif()
endif()
# Caffe package for CNN Triplet training
unset(Caffe_FOUND)
find_path(Caffe_INCLUDE_DIR NAMES caffe/caffe.hpp caffe/common.hpp caffe/net.hpp caffe/proto/caffe.pb.h caffe/util/io.hpp caffe/vision_layers.hpp
HINTS
/usr/local/include)
find_library(Caffe_LIBS NAMES caffe
HINTS
/usr/local/lib)
if(Caffe_LIBS AND Caffe_INCLUDE_DIR)
set(Caffe_FOUND 1)
endif()
# Glog package for CNN Triplet training
unset(Glog_FOUND)
find_library(Glog_LIBS NAMES glog
HINTS
/usr/local/lib)
if(Glog_LIBS)
set(Glog_FOUND 1)
endif()
# Protobuf package for CNN Triplet training
unset(Protobuf_FOUND)
find_library(Protobuf_LIBS NAMES protobuf
HINTS
/usr/local/lib)
if(Protobuf_LIBS)
set(Protobuf_FOUND 1)
endif()
#Convolutional Neural Network for 3D object classification and pose estimation.
===========================================================
#Module Description on cnn_3dobj:
####This learning structure construction and feature extraction concept is based on Convolutional Neural Network, the main reference paper could be found at:
<https://cvarlab.icg.tugraz.at/pubs/wohlhart_cvpr15.pdf>.
####The author provided Codes on Theano on:
<https://cvarlab.icg.tugraz.at/projects/3d_object_detection/>.
####I implemented the training and feature extraction codes mainly based on CAFFE project(<http://caffe.berkeleyvision.org/>) which will be compiled as libcaffe for the cnn_3dobj OpenCV module, codes are mainly concentrating on triplet and pair-wise jointed loss layer, the training data arrangement is also important which basic training information.
####Codes about my triplet version of caffe are released on Github:
<https://github.com/Wangyida/caffe/tree/cnn_triplet>.
####You can git it through:
```
$ git clone https://github.com/Wangyida/caffe/tree/cnn_triplet.
```
===========================================================
#Module Building Process:
####Prerequisite for this module: protobuf and caffe, for the libcaffe installation, you can install it on standard system path for the aim of being able to be linked by this OpenCV module when compiling and function using. Using: -D CMAKE_INSTALL_PREFIX=/usr/local as an building option when you cmake, the building process on Caffe on system could be like this:
```
$ cd <caffe_source_directory>
$ mkdir biuld
$ cd build
$ cmake -D CMAKE_INSTALL_PREFIX=/usr/local ..
$ make all -j4
$ sudo make install
```
####After all these steps, the headers and libs of CAFFE will be set on /usr/local/ path, and when you compiling opencv with opencv_contrib modules as below, the protobuf and caffe will be recognized as already installed while building. Protobuf is needed.
#Compiling OpenCV
```
$ cd <opencv_source_directory>
$ mkdir build
$ cd build
$ cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D WITH_V4L=ON -D WITH_QT=OFF -D WITH_OPENGL=ON -D WITH_VTK=ON -D INSTALL_TESTS=ON -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules ..
$ make -j4
$ sudo make install
```
##Tips on compiling problems:
####If you encouter the no declaration errors when you 'make', it might becaused that you have installed the older version of cnn_3dobj module and the header file changed in a newly released version of codes. This problem is the cmake and make can't detect the header should be updated and it keeps the older header remains in /usr/local/include/opencv2 whithout updating. This error could be solved by remove the installed older version of cnn_3dobj module by:
```
$ cd /
$ cd usr/local/include/opencv2/
$ sudo rm -rf cnn_3dobj.hpp
```
####And redo the compiling steps above again.
===========================================================
#Building samples
```
$ cd <opencv_contrib>/modules/cnn_3dobj/samples
$ mkdir build
$ cd build
$ cmake ..
$ make
```
===========================================================
#Demos
##Demo1: training data generation
####Imagas generation from different pose, by default there are 4 models used, there will be 276 images in all which each class contains 69 iamges, if you want to use additional .ply models, it is necessary to change the class number parameter to the new class number and also give it a new class label. If you will train net work and extract feature from RGB images set the parameter rgb_use as 1.
```
$ ./sphereview_test -plymodel=../data/3Dmodel/ape.ply -label_class=0 -cam_head_x=0 -cam_head_y=0 -cam_head_z=1
```
####press 'Q' to start 2D image genaration
```
$ ./sphereview_test -plymodel=../data/3Dmodel/ant.ply -label_class=1 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
```
```
$ ./sphereview_test -plymodel=../data/3Dmodel/cow.ply -label_class=2 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
```
```
$ ./sphereview_test -plymodel=../data/3Dmodel/plane.ply -label_class=3 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
```
```
$ ./sphereview_test -plymodel=../data/3Dmodel/bunny.ply -label_class=4 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
```
```
$ ./sphereview_test -plymodel=../data/3Dmodel/horse.ply -label_class=5 -cam_head_x=0 -cam_head_y=0 -cam_head_z=-1
```
####When all images are created in images_all folder as a collection of training images for network tranining and as a gallery of reference images for the classification part, then proceed on.
####After this demo, the binary files of images and labels will be stored as 'binary_image' and 'binary_label' in current path, you should copy them into the leveldb folder in Caffe triplet training, for example: copy these 2 files in <caffe_source_directory>/data/linemod and rename them as 'binary_image_train', 'binary_image_test' and 'binary_label_train', 'binary_label_train'. Here I use the same as trianing and testing data, you can use different data for training and testing the performance in the CAFFE training process. It's important to observe the loss of testing data to check whether training data is suitable for the your aim. Loss should be obseved as keep decreasing and remain on a much smaller number than the initial loss.
####You could start triplet tranining using Caffe like this:
```
$ cd
$ cd <caffe_source_directory>
$ ./examples/triplet/create_3d_triplet.sh
$ ./examples/triplet/train_3d_triplet.sh
```
####After doing this, you will get .caffemodel files as the trained parameter of net work. I have already provide the net definition .prototxt files and the pretrained .caffemodel in <opencv_contrib>/modules/cnn_3dobj/testdata/cv folder, you could just use them without training in caffe.
===========================================================
##Demo2: feature extraction and classification
```
$ cd
$ cd <opencv_contrib>/modules/cnn_3dobj/samples/build
```
####Classifier, this will extracting the feature of a single image and compare it with features of gallery samples for prediction. This demo uses a set of images for feature extraction in a given path, these features will be a reference for prediction on target image. The caffe model and network prototxt file is attached in <opencv_contrib>/modules/cnn_3dobj/testdata/cv. Just run:
```
$ ./classify_test
```
####if the classification and pose estimation issue need to extract mean got from all training images, you can run this:
```
$ ./classify_test -mean_file=../data/images_mean/triplet_mean.binaryproto
```
===========================================================
##Demo3: model performance test
####This demo will have a test on the performance of trained CNN model on several images. If the the model fail on telling different samples from seperate classes or confused on samples with similar pose but from different classes, it will give some information on the model analysis.
```
$ ./model_test
```
===========================================================
#Test
####If you want to have a test on cnn_3dobj module, the path of test data must be set in advance:
```
$ export OPENCV_TEST_DATA_PATH=<opencv_contrib>/modules/cnn_3dobj/testdata
```
#ifndef __OPENCV_CNN_3DOBJ_CONFIG_HPP__
#define __OPENCV_CNN_3DOBJ_CONFIG_HPP__
// HAVE CAFFE
#cmakedefine HAVE_CAFFE
#endif
@Article{hinterstoisser2008panter,
author = {Hinterstoisser, S. and Benhimane, S. and and Lepetit, V. and Navab, N.},
title = {Simultaneous Recognition and Homography Extraction of Local Patches with a Simple Linear Classifier},
booktitle = {BMVC British Machine Vision Conference 2008},
year = {2008}
}
@inproceedings{wohlhart15,
author = {Paul Wohlhart and Vincent Lepetit},
title = {Learning Descriptors for Object Recognition and 3D Pose Estimation},
booktitle = {Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
year = {2015}
}
This diff is collapsed.
cmake_minimum_required(VERSION 2.8)
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb ")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
project(cnn_3dobj)
find_package(OpenCV REQUIRED)
set(SOURCES_generator demo_sphereview_data.cpp)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(sphereview_test ${SOURCES_generator})
target_link_libraries(sphereview_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
set(SOURCES_classifier demo_classify.cpp)
add_executable(classify_test ${SOURCES_classifier})
target_link_libraries(classify_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
set(SOURCES_modelanalysis demo_model_analysis.cpp)
add_executable(model_test ${SOURCES_modelanalysis})
target_link_libraries(model_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
set(SOURCES_video demo_video.cpp)
add_executable(video_test ${SOURCES_video})
target_link_libraries(video_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/01.ply -label_class=1 -label_item=1 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/02.ply -label_class=1 -label_item=2 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/03.ply -label_class=1 -label_item=3 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/04.ply -label_class=1 -label_item=4 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/05.ply -label_class=1 -label_item=5 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/06.ply -label_class=1 -label_item=6 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/07.ply -label_class=1 -label_item=7 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/aeroplane/08.ply -label_class=1 -label_item=8 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/aeroplane_pascal/ -semisphere=0 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bicycle/01.ply -label_class=2 -label_item=1 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bicycle_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bicycle/02.ply -label_class=2 -label_item=2 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bicycle_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bicycle/03.ply -label_class=2 -label_item=3 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bicycle_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bicycle/04.ply -label_class=2 -label_item=4 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bicycle_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bicycle/05.ply -label_class=2 -label_item=5 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bicycle_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bicycle/06.ply -label_class=2 -label_item=6 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bicycle_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/boat/01.ply -label_class=3 -label_item=1 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/boat_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/boat/02.ply -label_class=3 -label_item=2 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/boat_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/boat/04.ply -label_class=3 -label_item=4 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/boat_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/boat/05.ply -label_class=3 -label_item=5 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/boat_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/boat/06.ply -label_class=3 -label_item=6 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/boat_pascal/ -z_range=0.6 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bus/01.ply -label_class=5 -label_item=1 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bus_pascal/ -z_range=0.2 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bus/02.ply -label_class=5 -label_item=2 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bus_pascal/ -z_range=0.2 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bus/03.ply -label_class=5 -label_item=3 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bus_pascal/ -z_range=0.2 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bus/04.ply -label_class=5 -label_item=4 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bus_pascal/ -z_range=0.2 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bus/05.ply -label_class=5 -label_item=5 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bus_pascal/ -z_range=0.2 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/bus/06.ply -label_class=5 -label_item=6 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/bus_pascal/ -z_range=0.2 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/01.ply -label_class=6 -label_item=1 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/02.ply -label_class=6 -label_item=2 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/03.ply -label_class=6 -label_item=3 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/04.ply -label_class=6 -label_item=4 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/05.ply -label_class=6 -label_item=5 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/06.ply -label_class=6 -label_item=6 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/07.ply -label_class=6 -label_item=7 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/08.ply -label_class=6 -label_item=8 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/09.ply -label_class=6 -label_item=9 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/car/10.ply -label_class=6 -label_item=10 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/car_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/motorbike/01.ply -label_class=9 -label_item=1 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/motorbike_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/motorbike/02.ply -label_class=9 -label_item=2 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/motorbike_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/motorbike/03.ply -label_class=9 -label_item=3 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/motorbike_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/motorbike/04.ply -label_class=9 -label_item=4 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/motorbike_pascal/ -z_range=0.5 -view_region=2
./sphereview_test -plymodel=/Users/yidawang/Documents/database/PASCAL3D+_release1.1/CAD/motorbike/05.ply -label_class=9 -label_item=5 -bakgrdir=/Users/yidawang/Documents/database/backgrd_pascal/motorbike_pascal/ -z_range=0.5 -view_region=2
\ No newline at end of file
This diff is collapsed.
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2009, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file demo_classify.cpp
* @brief Feature extraction and classification.
* @author Yida Wang
*/
#include <opencv2/cnn_3dobj.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iomanip>
using namespace cv;
using namespace std;
using namespace cv::cnn_3dobj;
/**
* @function listDir
* @brief Making all files names under a directory into a list
*/
void listDir(const char *path, std::vector<String>& files, bool r)
{
DIR *pDir;
struct dirent *ent;
char childpath[512];
pDir = opendir(path);
memset(childpath, 0, sizeof(childpath));
while ((ent = readdir(pDir)) != NULL)
{
if (ent->d_type & DT_DIR)
{
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".DS_Store") == 0)
{
continue;
}
if (r)
{
sprintf(childpath, "%s/%s", path, ent->d_name);
listDir(childpath,files,false);
}
}
else
{
if (strcmp(ent->d_name, ".DS_Store") != 0)
files.push_back(ent->d_name);
}
}
sort(files.begin(),files.end());
};
/**
* @function featureWrite
* @brief Writing features of gallery images into binary files
*/
int featureWrite(const Mat &features, const String &fname)
{
ofstream ouF;
ouF.open(fname.c_str(), std::ofstream::binary);
if (!ouF)
{
cerr << "failed to open the file : " << fname << endl;
return 0;
}
for (int r = 0; r < features.rows; r++)
{
ouF.write(reinterpret_cast<const char*>(features.ptr(r)), features.cols*features.elemSize());
}
ouF.close();
return 1;
}
/**
* @function main
*/
int main(int argc, char** argv)
{
const String keys = "{help | | This sample will extract features from reference images and target image for classification. You can add a mean_file if there little variance in data such as human faces, otherwise it is not so useful}"
"{src_dir | ../data/images_all/ | Source direction of the images ready for being used for extract feature as gallery.}"
"{caffemodel | ../../testdata/cv/3d_triplet_iter_30000.caffemodel | caffe model for feature exrtaction.}"
"{network_forIMG | ../../testdata/cv/3d_triplet_testIMG.prototxt | Network definition file used for extracting feature from a single image and making a classification}"
"{mean_file | no | The mean file generated by Caffe from all gallery images, this could be used for mean value substraction from all images. If you want to use the mean file, you can set this as ../data/images_mean/triplet_mean.binaryproto.}"
"{target_img | ../data/images_all/4_78.png | Path of image waiting to be classified.}"
"{feature_blob | feat | Name of layer which will represent as the feature, in this network, ip1 or feat is well.}"
"{num_candidate | 15 | Number of candidates in gallery as the prediction result.}"
"{device | CPU | Device type: CPU or GPU}"
"{dev_id | 0 | Device id}"
"{gallery_out | 0 | Option on output binary features on gallery images}";
/* get parameters from comand line */
cv::CommandLineParser parser(argc, argv, keys);
parser.about("Feature extraction and classification");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
String src_dir = parser.get<String>("src_dir");
String caffemodel = parser.get<String>("caffemodel");
String network_forIMG = parser.get<String>("network_forIMG");
String mean_file = parser.get<String>("mean_file");
String target_img = parser.get<String>("target_img");
String feature_blob = parser.get<String>("feature_blob");
int num_candidate = parser.get<int>("num_candidate");
String device = parser.get<String>("device");
int dev_id = parser.get<int>("dev_id");
int gallery_out = parser.get<int>("gallery_out");
/* Initialize a net work with Device */
cv::cnn_3dobj::descriptorExtractor descriptor(device);
std::cout << "Using" << descriptor.getDeviceType() << std::endl;
/* Load net with the caffe trained net work parameter and structure */
if (strcmp(mean_file.c_str(), "no") == 0)
descriptor.loadNet(network_forIMG, caffemodel);
else
descriptor.loadNet(network_forIMG, caffemodel, mean_file);
std::vector<String> name_gallery;
/* List the file names under a given path */
listDir(src_dir.c_str(), name_gallery, false);
if (gallery_out)
{
ofstream namelist_out("gallelist.txt");
/* Writing name of the reference images. */
for (unsigned int i = 0; i < name_gallery.size(); i++)
namelist_out << name_gallery.at(i) << endl;
}
for (unsigned int i = 0; i < name_gallery.size(); i++)
{
name_gallery[i] = src_dir + name_gallery[i];
}
std::vector<cv::Mat> img_gallery;
cv::Mat feature_reference;
for (unsigned int i = 0; i < name_gallery.size(); i++)
{
img_gallery.push_back(cv::imread(name_gallery[i]));
}
/* Extract feature from a set of images */
descriptor.extract(img_gallery, feature_reference, feature_blob);
if (gallery_out)
{
std::cout << std::endl << "---------- Features of gallery images ----------" << std::endl;
/* Print features of the reference images. */
for (unsigned int i = 0; i < feature_reference.rows; i++)
std::cout << feature_reference.row(i) << endl;
std::cout << std::endl << "---------- Saving features of gallery images into feature.bin ----------" << std::endl;
featureWrite(feature_reference, "feature.bin");
}
else
{
std::cout << std::endl << "---------- Prediction for " << target_img << " ----------" << std::endl;
cv::Mat img = cv::imread(target_img);
std::cout << std::endl << "---------- Features of gallery images ----------" << std::endl;
std::vector<std::pair<String, float> > prediction;
/* Print features of the reference images. */
for (unsigned int i = 0; i < feature_reference.rows; i++)
std::cout << feature_reference.row(i) << endl;
cv::Mat feature_test;
descriptor.extract(img, feature_test, feature_blob);
/* Initialize a matcher which using L2 distance. */
cv::BFMatcher matcher(NORM_L2);
std::vector<std::vector<cv::DMatch> > matches;
/* Have a KNN match on the target and reference images. */
matcher.knnMatch(feature_test, feature_reference, matches, num_candidate);
/* Print feature of the target image waiting to be classified. */
std::cout << std::endl << "---------- Features of target image: " << target_img << "----------" << endl << feature_test << std::endl;
/* Print the top N prediction. */
std::cout << std::endl << "---------- Prediction result(Distance - File Name in Gallery) ----------" << std::endl;
for (size_t i = 0; i < matches[0].size(); ++i)
{
std::cout << i << " - " << std::fixed << std::setprecision(2) << name_gallery[matches[0][i].trainIdx] << " - \"" << matches[0][i].distance << "\"" << std::endl;
}
}
return 0;
}
\ No newline at end of file
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2009, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file sphereview_3dobj_demo.cpp
* @brief Generating training data for CNN with triplet loss.
* @author Yida Wang
*/
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/cnn_3dobj.hpp"
using namespace cv;
using namespace cv::cnn_3dobj;
int main(int argc, char** argv)
{
const String keys = "{help | | this demo will have an analysis on the trained model, it will print information about whether the model is suit for set different classes apart and also discriminant on object pose at the same time.}"
"{caffemodel | ../../testdata/cv/3d_triplet_iter_30000.caffemodel | caffe model for feature exrtaction.}"
"{network_forIMG | ../../testdata/cv/3d_triplet_testIMG.prototxt | Network definition file used for extracting feature from a single image and making a classification}"
"{mean_file | no | The mean file generated by Caffe from all gallery images, this could be used for mean value substraction from all images. If you want to use the mean file, you can set this as ../data/images_mean/triplet_mean.binaryproto.}"
"{target_img | ../data/images_all/4_78.png | Path of image in reference.}"
"{ref_img1 | ../data/images_all/4_79.png | Path of closest image.}"
"{ref_img2 | ../data/images_all/4_87.png | Path of less closer image in the same class with reference image.}"
"{ref_img3 | ../data/images_all/3_78.png | Path of image with the same pose in another class.}"
"{feature_blob | feat | Name of layer which will represent as the feature, in this network, ip1 or feat is well.}"
"{device | CPU | device}"
"{dev_id | 0 | dev_id}";
/* Get parameters from comand line. */
cv::CommandLineParser parser(argc, argv, keys);
parser.about("Demo for object data classification and pose estimation");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
String caffemodel = parser.get<String>("caffemodel");
String network_forIMG = parser.get<String>("network_forIMG");
String mean_file = parser.get<String>("mean_file");
String target_img = parser.get<String>("target_img");
String ref_img1 = parser.get<String>("ref_img1");
String ref_img2 = parser.get<String>("ref_img2");
String ref_img3 = parser.get<String>("ref_img3");
String feature_blob = parser.get<String>("feature_blob");
String device = parser.get<String>("device");
int dev_id = parser.get<int>("dev_id");
std::vector<String> ref_img;
/* Sample which is most closest in pose to reference image
*and also the same class.
*/
ref_img.push_back(ref_img1);
/* Sample which is less closest in pose to reference image
*and also the same class.
*/
ref_img.push_back(ref_img2);
/* Sample which is very close in pose to reference image
*but not the same class.
*/
ref_img.push_back(ref_img3);
/* Initialize a net work with Device. */
cv::cnn_3dobj::descriptorExtractor descriptor(device, dev_id);
/* Load net with the caffe trained net work parameter and structure. */
if (strcmp(mean_file.c_str(), "no") == 0)
descriptor.loadNet(network_forIMG, caffemodel);
else
descriptor.loadNet(network_forIMG, caffemodel, mean_file);
cv::Mat img_base = cv::imread(target_img, -1);
if (img_base.empty())
{
printf("could not read reference image %s\n, make sure the path of images are set properly.", target_img.c_str());
}
std::vector<cv::Mat> img;
for (unsigned int i = 0; i < ref_img.size(); i++)
{
img.push_back(cv::imread(ref_img[i], -1));
if (img[i].empty()) {
printf("could not read reference image %s\n, make sure the path of images are set properly.", ref_img[i].c_str());
}
}
cv::Mat feature_test;
descriptor.extract(img_base, feature_test, feature_blob);
if (feature_test.empty()) {
printf("could not extract feature from test image which is read into cv::Mat.");
}
cv::Mat feature_reference;
descriptor.extract(img, feature_reference, feature_blob);
if (feature_reference.empty()) {
printf("could not extract feature from reference images which is already stored in vector<cv::Mat>.");
}
std::vector<float> matches;
for (int i = 0; i < feature_reference.rows; i++)
{
cv::Mat distance = feature_test-feature_reference.row(i);
matches.push_back(cv::norm(distance));
}
bool pose_pass = false;
bool class_pass = false;
/* Have comparations on the distance between reference image and 3 other images
*distance between closest sample and reference image should be smallest and
*distance between sample in another class and reference image should be largest.
*/
if (matches[0] < matches[1] && matches[0] < matches[2])
pose_pass = true;
if (matches[1] < matches[2])
class_pass = true;
if (!pose_pass)
{
printf("\n =========== Model %s ========== \nIs not trained properly that the similar pose could not be tell from a cluster of features.\n", caffemodel.c_str());
}
else if (!class_pass)
{
printf("\n =========== Model %s ========== \nIs not trained properly that feature from the same class is not discriminant from the one of another class with similar pose.\n", caffemodel.c_str());
}
else
{
printf("\n =========== Model %s ========== \nSuits for setting different classes apart and also discriminant on object pose at the same time.\n", caffemodel.c_str());
}
return 0;
}
This diff is collapsed.
This diff is collapsed.
./classify_test --src_dir=/Users/yidawang/Downloads/PASCAL3D+_release1.1/ImageCollection/ --network_forIMG=/Users/yidawang/Documents/buildboat/caffe/examples/triplet/pascal_triplet.prototxt --caffemodel=/Users/yidawang/Documents/buildboat/caffe/examples/triplet/pascal_triplet_iter_10000.caffemodel --gallery_out=1
\ No newline at end of file
This diff is collapsed.
#include "precomp.hpp"
using namespace cv;
using namespace std;
namespace cv
{
namespace cnn_3dobj
{
icoSphere::icoSphere(float radius_in, int depth_in)
{
X = 0.5f;
Z = 0.5f;
float vdata[12][3] = { { -X, 0.0f, Z }, { X, 0.0f, Z },
{ -X, 0.0f, -Z }, { X, 0.0f, -Z }, { 0.0f, Z, X }, { 0.0f, Z, -X },
{ 0.0f, -Z, X }, { 0.0f, -Z, -X }, { Z, X, 0.0f }, { -Z, X, 0.0f },
{ Z, -X, 0.0f }, { -Z, -X, 0.0f } };
int tindices[20][3] = { { 0, 4, 1 }, { 0, 9, 4 }, { 9, 5, 4 },
{ 4, 5, 8 }, { 4, 8, 1 }, { 8, 10, 1 }, { 8, 3, 10 }, { 5, 3, 8 },
{ 5, 2, 3 }, { 2, 7, 3 }, { 7, 10, 3 }, { 7, 6, 10 }, { 7, 11, 6 },
{ 11, 0, 6 }, { 0, 1, 6 }, { 6, 1, 10 }, { 9, 0, 11 },
{ 9, 11, 2 }, { 9, 2, 5 }, { 7, 2, 11 } };
diff = 0.00000001;
X *= (int)radius_in;
Z *= (int)radius_in;
// Iterate over points
for (int i = 0; i < 20; ++i)
{
subdivide(vdata[tindices[i][0]], vdata[tindices[i][1]],
vdata[tindices[i][2]], depth_in);
}
CameraPos_temp.push_back(CameraPos[0]);
for (unsigned int j = 1; j < CameraPos.size(); ++j)
{
for (unsigned int k = 0; k < j; ++k)
{
float dist_x, dist_y, dist_z;
dist_x = (CameraPos.at(k).x-CameraPos.at(j).x) * (CameraPos.at(k).x-CameraPos.at(j).x);
dist_y = (CameraPos.at(k).y-CameraPos.at(j).y) * (CameraPos.at(k).y-CameraPos.at(j).y);
dist_z = (CameraPos.at(k).z-CameraPos.at(j).z) * (CameraPos.at(k).z-CameraPos.at(j).z);
if (dist_x < diff && dist_y < diff && dist_z < diff)
break;
else if (k == j-1)
CameraPos_temp.push_back(CameraPos[j]);
}
}
CameraPos = CameraPos_temp;
cout << "View points in total: " << CameraPos.size() << endl;
cout << "The coordinate of view point: " << endl;
for(unsigned int i = 0; i < CameraPos.size(); i++)
{
cout << CameraPos.at(i).x <<' '<< CameraPos.at(i).y << ' ' << CameraPos.at(i).z << endl;
}
};
void icoSphere::norm(float v[])
{
float len = 0;
for (int i = 0; i < 3; ++i)
{
len += v[i] * v[i];
}
len = sqrt(len);
for (int i = 0; i < 3; ++i)
{
v[i] /= ((float)len);
}
};
void icoSphere::add(float v[])
{
Point3f temp_Campos;
std::vector<float>* temp = new std::vector<float>;
for (int k = 0; k < 3; ++k)
{
temp->push_back(v[k]);
}
temp_Campos.x = temp->at(0);temp_Campos.y = temp->at(1);temp_Campos.z = temp->at(2);
CameraPos.push_back(temp_Campos);
};
void icoSphere::subdivide(float v1[], float v2[], float v3[], int depth)
{
norm(v1);
norm(v2);
norm(v3);
if (depth == 0)
{
add(v1);
add(v2);
add(v3);
return;
}
float* v12 = new float[3];
float* v23 = new float[3];
float* v31 = new float[3];
for (int i = 0; i < 3; ++i)
{
v12[i] = (v1[i] + v2[i]) / 2;
v23[i] = (v2[i] + v3[i]) / 2;
v31[i] = (v3[i] + v1[i]) / 2;
}
norm(v12);
norm(v23);
norm(v31);
subdivide(v1, v12, v31, depth - 1);
subdivide(v2, v23, v12, depth - 1);
subdivide(v3, v31, v23, depth - 1);
subdivide(v12, v23, v31, depth - 1);
};
int icoSphere::swapEndian(int val)
{
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
return (val << 16) | (val >> 16);
};
cv::Point3d icoSphere::getCenter(cv::Mat cloud)
{
Point3f* data = cloud.ptr<cv::Point3f>();
Point3d dataout;
for(int i = 0; i < cloud.cols; ++i)
{
dataout.x += data[i].x;
dataout.y += data[i].y;
dataout.z += data[i].z;
}
dataout.x = dataout.x/cloud.cols;
dataout.y = dataout.y/cloud.cols;
dataout.z = dataout.z/cloud.cols;
return dataout;
};
float icoSphere::getRadius(cv::Mat cloud, cv::Point3d center)
{
float radiusCam = 0;
Point3f* data = cloud.ptr<cv::Point3f>();
Point3d datatemp;
for(int i = 0; i < cloud.cols; ++i)
{
datatemp.x = data[i].x - (float)center.x;
datatemp.y = data[i].y - (float)center.y;
datatemp.z = data[i].z - (float)center.z;
float Radius = sqrt(pow(datatemp.x,2)+pow(datatemp.y,2)+pow(datatemp.z,2));
if(Radius > radiusCam)
{
radiusCam = Radius;
}
}
return radiusCam;
};
void icoSphere::createHeader(int num_item, int rows, int cols, const char* headerPath)
{
char* a0 = (char*)malloc(1024);
strcpy(a0, headerPath);
char a1[] = "image";
char a2[] = "label";
char* headerPathimg = (char*)malloc(1024);
strcpy(headerPathimg, a0);
strcat(headerPathimg, a1);
char* headerPathlab = (char*)malloc(1024);
strcpy(headerPathlab, a0);
strcat(headerPathlab, a2);
std::ofstream headerImg(headerPathimg, ios::out|ios::binary);
std::ofstream headerLabel(headerPathlab, ios::out|ios::binary);
int headerimg[4] = {2051,num_item,rows,cols};
for (int i=0; i<4; i++)
headerimg[i] = swapEndian(headerimg[i]);
int headerlabel[2] = {2050,num_item};
for (int i=0; i<2; i++)
headerlabel[i] = swapEndian(headerlabel[i]);
headerImg.write(reinterpret_cast<const char*>(headerimg), sizeof(int)*4);
headerImg.close();
headerLabel.write(reinterpret_cast<const char*>(headerlabel), sizeof(int)*2);
headerLabel.close();
};
void icoSphere::writeBinaryfile(String filenameImg, const char* binaryPath, const char* headerPath, int num_item, int label_class, int x, int y, int z, int isrgb)
{
cv::Mat ImgforBin = cv::imread(filenameImg, isrgb);
char* A0 = (char*)malloc(1024);
strcpy(A0, binaryPath);
char A1[] = "image";
char A2[] = "label";
char* binPathimg = (char*)malloc(1024);
strcpy(binPathimg, A0);
strcat(binPathimg, A1);
char* binPathlab = (char*)malloc(1024);
strcpy(binPathlab, A0);
strcat(binPathlab, A2);
fstream img_file, lab_file;
img_file.open(binPathimg,ios::in);
lab_file.open(binPathlab,ios::in);
if(!img_file)
{
cout << "Creating the training data at: " << binaryPath << ". " << endl;
char* a0 = (char*)malloc(1024);
strcpy(a0, headerPath);
char a1[] = "image";
char a2[] = "label";
char* headerPathimg = (char*)malloc(1024);
strcpy(headerPathimg, a0);
strcat(headerPathimg,a1);
char* headerPathlab = (char*)malloc(1024);
strcpy(headerPathlab, a0);
strcat(headerPathlab,a2);
createHeader(num_item, 64, 64, binaryPath);
img_file.open(binPathimg,ios::out|ios::binary|ios::app);
lab_file.open(binPathlab,ios::out|ios::binary|ios::app);
if (isrgb == 0)
{
for (int r = 0; r < ImgforBin.rows; r++)
{
img_file.write(reinterpret_cast<const char*>(ImgforBin.ptr(r)), ImgforBin.cols*ImgforBin.elemSize());
}
}
else
{
std::vector<cv::Mat> Img3forBin;
cv::split(ImgforBin,Img3forBin);
for (unsigned int i = 0; i < Img3forBin.size(); i++)
{
for (int r = 0; r < Img3forBin[i].rows; r++)
{
img_file.write(reinterpret_cast<const char*>(Img3forBin[i].ptr(r)), Img3forBin[i].cols*Img3forBin[i].elemSize());
}
}
}
signed char templab = (signed char)label_class;
lab_file << templab << (signed char)x << (signed char)y << (signed char)z;
}
else
{
img_file.close();
lab_file.close();
img_file.open(binPathimg,ios::out|ios::binary|ios::app);
lab_file.open(binPathlab,ios::out|ios::binary|ios::app);
cout <<"Concatenating the training data at: " << binaryPath << ". " << endl;
if (isrgb == 0)
{
for (int r = 0; r < ImgforBin.rows; r++)
{
img_file.write(reinterpret_cast<const char*>(ImgforBin.ptr(r)), ImgforBin.cols*ImgforBin.elemSize());
}
}
else
{
std::vector<cv::Mat> Img3forBin;
cv::split(ImgforBin,Img3forBin);
for (unsigned int i = 0; i < Img3forBin.size(); i++)
{
for (int r = 0; r < Img3forBin[i].rows; r++)
{
img_file.write(reinterpret_cast<const char*>(Img3forBin[i].ptr(r)), Img3forBin[i].cols*Img3forBin[i].elemSize());
}
}
}
signed char templab = (signed char)label_class;
lab_file << templab << (signed char)x << (signed char)y << (signed char)z;
}
img_file.close();
lab_file.close();
};
} /* namespace cnn_3dobj */
} /* namespace cv */
/*
By downloading, copying, installing or using the software you agree to this
license. If you do not agree to this license, do not download, install,
copy or use the software.
License Agreement
For Open Source Computer Vision Library
(3-clause BSD License)
Copyright (C) 2013, OpenCV Foundation, all rights reserved.
Third party copyrights are property of their respective owners.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the names of the copyright holders nor the names of the contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are
disclaimed. In no event shall copyright holders or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused
and on any theory of liability, whether in contract, strict liability,
or tort (including negligence or otherwise) arising in any way out of
the use of this software, even if advised of the possibility of such damage.
*/
#ifndef __OPENCV_CNN_3DOBJ_PRECOMP_HPP__
#define __OPENCV_CNN_3DOBJ_PRECOMP_HPP__
#include <opencv2/cnn_3dobj.hpp>
#endif
/*
* Created on: Aug 14, 2015
* Author: Yida Wang
*/
#include "test_precomp.hpp"
using namespace cv;
using namespace cv::cnn_3dobj;
class CV_CNN_Feature_Test : public cvtest::BaseTest
{
public:
CV_CNN_Feature_Test();
protected:
void run(int);
};
CV_CNN_Feature_Test::CV_CNN_Feature_Test()
{
}
/**
* This test checks the following:
* Feature extraction by the triplet trained CNN model
*/
void CV_CNN_Feature_Test::run(int)
{
String caffemodel = String(ts->get_data_path()) + "3d_triplet_iter_30000.caffemodel";
String network_forIMG = cvtest::TS::ptr()->get_data_path() + "3d_triplet_testIMG.prototxt";
String mean_file = "no";
std::vector<String> ref_img;
String target_img = String(ts->get_data_path()) + "1_8.png";
String feature_blob = "feat";
String device = "CPU";
int dev_id = 0;
cv::Mat img_base = cv::imread(target_img, -1);
if (img_base.empty())
{
ts->printf(cvtest::TS::LOG, "could not read reference image %s\n", target_img.c_str(), "make sure the path of images are set properly.");
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
cv::cnn_3dobj::descriptorExtractor descriptor(device, dev_id);
if (strcmp(mean_file.c_str(), "no") == 0)
descriptor.loadNet(network_forIMG, caffemodel);
else
descriptor.loadNet(network_forIMG, caffemodel, mean_file);
cv::Mat feature_test;
descriptor.extract(img_base, feature_test, feature_blob);
Mat feature_reference = (Mat_<float>(1,16) << -134.03548, -203.48265, -105.96752, 55.343075, -211.36378, 487.85968, -182.15063, 62.229042, 297.19876, 206.07578, 291.74951, -19.906454, -464.09152, 135.79895, 420.43616, 2.2887282);
printf("Reference feature is computed by Caffe extract_features tool by \n To generate values for different images, use extract_features \n with the resetted image list in prototxt.");
float dist = norm(feature_test - feature_reference);
if (dist > 5) {
ts->printf(cvtest::TS::LOG, "Extracted featrue is not the same from the one extracted from Caffe.");
ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
return;
}
}
TEST(CNN_FEATURE, accuracy) { CV_CNN_Feature_Test test; test.safe_run(); }
#include "test_precomp.hpp"
CV_TEST_MAIN("cv")
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wmissing-declarations"
# if defined __clang__ || defined __APPLE__
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
# pragma GCC diagnostic ignored "-Wextra"
# endif
#endif
#ifndef __OPENCV_TEST_PRECOMP_HPP__
#define __OPENCV_TEST_PRECOMP_HPP__
#include <iostream>
#include "opencv2/ts.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/cnn_3dobj_config.hpp"
#include "opencv2/cnn_3dobj.hpp"
#endif
name: "3d_triplet"
input: "data"
input_dim: 1
input_dim: 1
input_dim: 64
input_dim: 64
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
convolution_param {
num_output: 16
kernel_size: 8
stride: 1
}
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "pool1"
top: "pool1"
}
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
convolution_param {
num_output: 7
kernel_size: 5
stride: 1
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "relu2"
type: "ReLU"
bottom: "pool2"
top: "pool2"
}
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
inner_product_param {
num_output: 256
}
}
layer {
name: "relu3"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
layer {
name: "feat"
type: "InnerProduct"
bottom: "ip1"
top: "feat"
inner_product_param {
num_output: 3
}
}
../../testdata/cv/3d_triplet_iter_1.caffemodel
../../testdata/cv/3d_triplet_iter_2.caffemodel
../../testdata/cv/3d_triplet_iter_3.caffemodel
../../testdata/cv/3d_triplet_iter_4.caffemodel
../../testdata/cv/3d_triplet_iter_5.caffemodel
../../testdata/cv/3d_triplet_iter_6.caffemodel
../../testdata/cv/3d_triplet_iter_7.caffemodel
../../testdata/cv/3d_triplet_iter_8.caffemodel
../../testdata/cv/3d_triplet_iter_9.caffemodel
../../testdata/cv/3d_triplet_iter_10.caffemodel
../../testdata/cv/3d_triplet_iter_20.caffemodel
../../testdata/cv/3d_triplet_iter_30.caffemodel
../../testdata/cv/3d_triplet_iter_40.caffemodel
../../testdata/cv/3d_triplet_iter_50.caffemodel
../../testdata/cv/3d_triplet_iter_60.caffemodel
../../testdata/cv/3d_triplet_iter_70.caffemodel
../../testdata/cv/3d_triplet_iter_80.caffemodel
../../testdata/cv/3d_triplet_iter_90.caffemodel
../../testdata/cv/3d_triplet_iter_100.caffemodel
../../testdata/cv/3d_triplet_iter_200.caffemodel
../../testdata/cv/3d_triplet_iter_300.caffemodel
../../testdata/cv/3d_triplet_iter_400.caffemodel
../../testdata/cv/3d_triplet_iter_500.caffemodel
../../testdata/cv/3d_triplet_iter_600.caffemodel
../../testdata/cv/3d_triplet_iter_700.caffemodel
../../testdata/cv/3d_triplet_iter_800.caffemodel
../../testdata/cv/3d_triplet_iter_900.caffemodel
../../testdata/cv/3d_triplet_iter_1000.caffemodel
../../testdata/cv/3d_triplet_iter_2000.caffemodel
../../testdata/cv/3d_triplet_iter_3000.caffemodel
../../testdata/cv/3d_triplet_iter_4000.caffemodel
../../testdata/cv/3d_triplet_iter_5000.caffemodel
../../testdata/cv/3d_triplet_iter_6000.caffemodel
../../testdata/cv/3d_triplet_iter_7000.caffemodel
../../testdata/cv/3d_triplet_iter_8000.caffemodel
../../testdata/cv/3d_triplet_iter_9000.caffemodel
../../testdata/cv/3d_triplet_iter_10000.caffemodel
../../testdata/cv/3d_triplet_iter_20000.caffemodel
../../testdata/cv/3d_triplet_iter_30000.caffemodel
../../testdata/cv/3d_triplet_iter_40000.caffemodel
../../testdata/cv/3d_triplet_iter_50000.caffemodel
../../testdata/cv/3d_triplet_iter_60000.caffemodel
../../testdata/cv/3d_triplet_iter_70000.caffemodel
../../testdata/cv/3d_triplet_iter_110000.caffemodel
../../testdata/cv/3d_triplet_iter_120000.caffemodel
../../testdata/cv/3d_triplet_iter_130000.caffemodel
../../testdata/cv/3d_triplet_iter_140000.caffemodel
../../testdata/cv/3d_triplet_iter_150000.caffemodel
../../testdata/cv/3d_triplet_iter_160000.caffemodel
../../testdata/cv/3d_triplet_iter_170000.caffemodel
../../testdata/cv/3d_triplet_iter_180000.caffemodel
../../testdata/cv/3d_triplet_iter_190000.caffemodel
\ No newline at end of file
Training data generation using Icosphere {#tutorial_data_generation}
=============
Goal
----
In this tutorial you will learn how to
- Conduct a point cloud of camera view on sphere.
- Generate training images using 3D model.
Code
----
You can download the code from [here ](https://github.com/Wangyida/opencv_contrib/blob/cnn_3dobj/samples/demo_sphereview_data.cpp).
@include cnn_3dobj/samples/demo_sphereview_data.cpp
Explanation
-----------
Here is the general structure of the program:
- Create a window.
@code{.cpp}
viz::Viz3d myWindow("Coordinate Frame");
@endcode
- Set window size as 64*64, we use this scale as default.
@code{.cpp}
myWindow.setWindowSize(Size(64,64));
@endcode
- Add coordinate axes.
@code{.cpp}
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
myWindow.setBackgroundColor(viz::Color::gray());
myWindow.spin();
@endcode
- Create a Mesh widget, loading .ply models.
@code{.cpp}
viz::Mesh objmesh = viz::Mesh::load(plymodel);
@endcode
- Get the center of the generated mesh widget, cause some .ply files.
@code{.cpp}
Point3d cam_focal_point = ViewSphere.getCenter(objmesh.cloud);
@endcode
- Get the pose of the camera using makeCameraPoses.
@code{.cpp}
Affine3f cam_pose = viz::makeCameraPose(campos.at(pose)*radius+cam_focal_point, cam_focal_point, cam_y_dir*radius+cam_focal_point);
@endcode
- Get the transformation matrix from camera coordinate system to global.
@code{.cpp}
Affine3f transform = viz::makeTransformToGlobal(Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f), campos.at(pose));
viz::WMesh mesh_widget(objmesh);
@endcode
- Save screen shot as images.
@code{.cpp}
myWindow.saveScreenshot(filename);
@endcode
- Write images into binary files for further using in CNN training.
@code{.cpp}
ViewSphere.writeBinaryfile(filename, binaryPath, headerPath,(int)campos.size()*num_class, label_class, (int)(campos.at(pose).x*100), (int)(campos.at(pose).y*100), (int)(campos.at(pose).z*100), rgb_use);
@endcode
Results
-------
Here is collection images created by this demo using 4 model.
![](images_all/1_8.png)
Classify {#tutorial_classify}
===============
Goal
----
In this tutorial you will learn how to
- How to extract feature from an image
- How to extract features from images under a given root path
- How to make a prediction using reference images and target image
Code
----
You can download the code from [here ](https://github.com/Wangyida/opencv_contrib/blob/cnn_3dobj/samples/demo_classify.cpp).
@include cnn_3dobj/samples/demo_classify.cpp
Explanation
-----------
Here is the general structure of the program:
- Initialize a net work with Device.
@code{.cpp}
cv::cnn_3dobj::descriptorExtractor descriptor(device);
@endcode
- Load net with the caffe trained net work parameter and structure.
@code{.cpp}
if (strcmp(mean_file.c_str(), "no") == 0)
descriptor.loadNet(network_forIMG, caffemodel);
else
descriptor.loadNet(network_forIMG, caffemodel, mean_file);
@endcode
- List the file names under a given path.
@code{.cpp}
listDir(src_dir.c_str(), name_gallery, false);
for (unsigned int i = 0; i < name_gallery.size(); i++)
{
name_gallery[i] = src_dir + name_gallery[i];
}
@endcode
- Extract feature from a set of images.
@code{.cpp}
descriptor.extract(img_gallery, feature_reference, feature_blob);
@endcode
- Initialize a matcher which using L2 distance.
@code{.cpp}
cv::BFMatcher matcher(NORM_L2);
std::vector<std::vector<cv::DMatch> > matches;
@endcode
- Have a KNN match on the target and reference images.
@code{.cpp}
matcher.knnMatch(feature_test, feature_reference, matches, num_candidate);
@endcode
- Print features of the reference images.
@code{.cpp}std::cout << std::endl << "---------- Features of target image: " << target_img << "----------" << endl << feature_test << std::endl;
@endcode
Results
-------
Training data generation using Icosphere {#tutorial_model_analysis}
=============
Goal
----
In this tutorial you will learn how to
- Extract feature from particular image.
- Have a meaningful comparation on the extracted feature.
Code
----
You can download the code from [here ](https://github.com/Wangyida/opencv_contrib/blob/cnn_3dobj/samples/demo_model_analysis.cpp).
@include cnn_3dobj/samples/demo_model_analysis.cpp
Explanation
-----------
Here is the general structure of the program:
- Sample which is most closest in pose to reference image and also the same class.
@code{.cpp}
ref_img.push_back(ref_img1);
@endcode
- Sample which is less closest in pose to reference image and also the same class.
@code{.cpp}
ref_img.push_back(ref_img2);
@endcode
- Sample which is very close in pose to reference image but not the same class.
@code{.cpp}
ref_img.push_back(ref_img3);
@endcode
- Initialize a net work with Device.
@code{.cpp}
cv::cnn_3dobj::descriptorExtractor descriptor(device, dev_id);
@endcode
- Load net with the caffe trained net work parameter and structure.
@code{.cpp}
if (strcmp(mean_file.c_str(), "no") == 0)
descriptor.loadNet(network_forIMG, caffemodel);
else
descriptor.loadNet(network_forIMG, caffemodel, mean_file);
@endcode
- Have comparations on the distance between reference image and 3 other images
distance between closest sample and reference image should be smallest and
distance between sample in another class and reference image should be largest.
@code{.cpp}
if (matches[0] < matches[1] && matches[0] < matches[2])
pose_pass = true;
if (matches[1] < matches[2])
class_pass = true;
@endcode
Results
-------
CNN for 3D Object Classification and Pose Estimation {#tutorial_table_of_content_cnn_3dobj}
==========
- @subpage tutorial_data_generation
*Compatibility:* \> OpenCV 3.0.0
*Author:* Yida Wang
You will learn how to generate training images from 3D models with proper poses for CNN training.
- @subpage tutorial_feature_classification
*Compatibility:* \> OpenCV 3.0.0
*Author:* Yida Wang
You will learn how to extract features from images and make a prediction using descriptor.
- @subpage tutorial_model_analysis
*Compatibility:* \> OpenCV 3.0.0
*Author:* Yida Wang
You will learn how to have an analysis on performance of the trained Model.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment