Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2306 lines
79 KiB
2306 lines
79 KiB
/* |
|
* cvoneway.cpp |
|
* one_way_sample |
|
* |
|
* Created by Victor Eruhimov on 3/23/10. |
|
* Copyright 2010 Argus Corp. All rights reserved. |
|
* |
|
*/ |
|
|
|
#include "precomp.hpp" |
|
#include "opencv2/opencv_modules.hpp" |
|
#ifdef HAVE_OPENCV_HIGHGUI |
|
# include "opencv2/highgui.hpp" |
|
#endif |
|
#include <stdio.h> |
|
|
|
namespace cv{ |
|
|
|
inline int round(float value) |
|
{ |
|
if(value > 0) |
|
{ |
|
return int(value + 0.5f); |
|
} |
|
else |
|
{ |
|
return int(value - 0.5f); |
|
} |
|
} |
|
|
|
inline CvRect resize_rect(CvRect rect, float alpha) |
|
{ |
|
return cvRect(rect.x + round((float)(0.5*(1 - alpha)*rect.width)), rect.y + round((float)(0.5*(1 - alpha)*rect.height)), |
|
round(rect.width*alpha), round(rect.height*alpha)); |
|
} |
|
|
|
CvMat* ConvertImageToMatrix(IplImage* patch); |
|
|
|
class CvCameraPose |
|
{ |
|
public: |
|
CvCameraPose() |
|
{ |
|
m_rotation = cvCreateMat(1, 3, CV_32FC1); |
|
m_translation = cvCreateMat(1, 3, CV_32FC1); |
|
}; |
|
|
|
~CvCameraPose() |
|
{ |
|
cvReleaseMat(&m_rotation); |
|
cvReleaseMat(&m_translation); |
|
}; |
|
|
|
void SetPose(CvMat* rotation, CvMat* translation) |
|
{ |
|
cvCopy(rotation, m_rotation); |
|
cvCopy(translation, m_translation); |
|
}; |
|
|
|
CvMat* GetRotation() {return m_rotation;}; |
|
CvMat* GetTranslation() {return m_translation;}; |
|
|
|
protected: |
|
CvMat* m_rotation; |
|
CvMat* m_translation; |
|
}; |
|
|
|
// AffineTransformPatch: generates an affine transformed image patch. |
|
// - src: source image (roi is supported) |
|
// - dst: output image. ROI of dst image should be 2 times smaller than ROI of src. |
|
// - pose: parameters of an affine transformation |
|
void AffineTransformPatch(IplImage* src, IplImage* dst, CvAffinePose pose); |
|
|
|
// GenerateAffineTransformFromPose: generates an affine transformation matrix from CvAffinePose instance |
|
// - size: the size of image patch |
|
// - pose: affine transformation |
|
// - transform: 2x3 transformation matrix |
|
void GenerateAffineTransformFromPose(CvSize size, CvAffinePose pose, CvMat* transform); |
|
|
|
// Generates a random affine pose |
|
CvAffinePose GenRandomAffinePose(); |
|
|
|
|
|
const static int num_mean_components = 500; |
|
const static float noise_intensity = 0.15f; |
|
|
|
|
|
static inline CvPoint rect_center(CvRect rect) |
|
{ |
|
return cvPoint(rect.x + rect.width/2, rect.y + rect.height/2); |
|
} |
|
|
|
// static void homography_transform(IplImage* frontal, IplImage* result, CvMat* homography) |
|
// { |
|
// cvWarpPerspective(frontal, result, homography); |
|
// } |
|
|
|
static CvAffinePose perturbate_pose(CvAffinePose pose, float noise) |
|
{ |
|
// perturbate the matrix |
|
float noise_mult_factor = 1 + (0.5f - float(rand())/RAND_MAX)*noise; |
|
float noise_add_factor = noise_mult_factor - 1; |
|
|
|
CvAffinePose pose_pert = pose; |
|
pose_pert.phi += noise_add_factor; |
|
pose_pert.theta += noise_mult_factor; |
|
pose_pert.lambda1 *= noise_mult_factor; |
|
pose_pert.lambda2 *= noise_mult_factor; |
|
|
|
return pose_pert; |
|
} |
|
|
|
static void generate_mean_patch(IplImage* frontal, IplImage* result, CvAffinePose pose, int pose_count, float noise) |
|
{ |
|
IplImage* sum = cvCreateImage(cvSize(result->width, result->height), IPL_DEPTH_32F, 1); |
|
IplImage* workspace = cvCloneImage(result); |
|
IplImage* workspace_float = cvCloneImage(sum); |
|
|
|
cvSetZero(sum); |
|
for(int i = 0; i < pose_count; i++) |
|
{ |
|
CvAffinePose pose_pert = perturbate_pose(pose, noise); |
|
|
|
AffineTransformPatch(frontal, workspace, pose_pert); |
|
cvConvertScale(workspace, workspace_float); |
|
cvAdd(sum, workspace_float, sum); |
|
} |
|
|
|
cvConvertScale(sum, result, 1.0f/pose_count); |
|
|
|
cvReleaseImage(&workspace); |
|
cvReleaseImage(&sum); |
|
cvReleaseImage(&workspace_float); |
|
} |
|
|
|
// static void generate_mean_patch_fast(IplImage* /*frontal*/, IplImage* /*result*/, CvAffinePose /*pose*/, |
|
// CvMat* /*pca_hr_avg*/, CvMat* /*pca_hr_eigenvectors*/, const OneWayDescriptor* /*pca_descriptors*/) |
|
// { |
|
// /*for(int i = 0; i < pca_hr_eigenvectors->cols; i++) |
|
// { |
|
|
|
// }*/ |
|
// } |
|
|
|
void readPCAFeatures(const char *filename, CvMat** avg, CvMat** eigenvectors, const char *postfix = ""); |
|
void readPCAFeatures(const FileNode &fn, CvMat** avg, CvMat** eigenvectors, const char* postfix = ""); |
|
void savePCAFeatures(FileStorage &fs, const char* postfix, CvMat* avg, CvMat* eigenvectors); |
|
void calcPCAFeatures(std::vector<IplImage*>& patches, FileStorage &fs, const char* postfix, CvMat** avg, |
|
CvMat** eigenvectors); |
|
void loadPCAFeatures(const char* path, const char* images_list, std::vector<IplImage*>& patches, CvSize patch_size); |
|
void generatePCAFeatures(const char* path, const char* img_filename, FileStorage& fs, const char* postfix, |
|
CvSize patch_size, CvMat** avg, CvMat** eigenvectors); |
|
|
|
void eigenvector2image(CvMat* eigenvector, IplImage* img); |
|
|
|
void FindOneWayDescriptor(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, int& desc_idx, int& pose_idx, float& distance, |
|
CvMat* avg = 0, CvMat* eigenvalues = 0); |
|
|
|
void FindOneWayDescriptor(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, int n, |
|
std::vector<int>& desc_idxs, std::vector<int>& pose_idxs, std::vector<float>& distances, |
|
CvMat* avg = 0, CvMat* eigenvalues = 0); |
|
|
|
void FindOneWayDescriptor(cv::flann::Index* m_pca_descriptors_tree, CvSize patch_size, int m_pca_dim_low, int m_pose_count, IplImage* patch, int& desc_idx, int& pose_idx, float& distance, |
|
CvMat* avg = 0, CvMat* eigenvalues = 0); |
|
|
|
void FindOneWayDescriptorEx(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, |
|
float scale_min, float scale_max, float scale_step, |
|
int& desc_idx, int& pose_idx, float& distance, float& scale, |
|
CvMat* avg, CvMat* eigenvectors); |
|
|
|
void FindOneWayDescriptorEx(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, |
|
float scale_min, float scale_max, float scale_step, |
|
int n, std::vector<int>& desc_idxs, std::vector<int>& pose_idxs, |
|
std::vector<float>& distances, std::vector<float>& scales, |
|
CvMat* avg, CvMat* eigenvectors); |
|
|
|
void FindOneWayDescriptorEx(cv::flann::Index* m_pca_descriptors_tree, CvSize patch_size, int m_pca_dim_low, int m_pose_count, IplImage* patch, |
|
float scale_min, float scale_max, float scale_step, |
|
int& desc_idx, int& pose_idx, float& distance, float& scale, |
|
CvMat* avg, CvMat* eigenvectors); |
|
|
|
inline CvRect fit_rect_roi_fixedsize(CvRect rect, CvRect roi) |
|
{ |
|
CvRect fit = rect; |
|
fit.x = MAX(fit.x, roi.x); |
|
fit.y = MAX(fit.y, roi.y); |
|
fit.x = MIN(fit.x, roi.x + roi.width - fit.width - 1); |
|
fit.y = MIN(fit.y, roi.y + roi.height - fit.height - 1); |
|
return(fit); |
|
} |
|
|
|
inline CvRect fit_rect_fixedsize(CvRect rect, IplImage* img) |
|
{ |
|
CvRect roi = cvGetImageROI(img); |
|
return fit_rect_roi_fixedsize(rect, roi); |
|
} |
|
|
|
OneWayDescriptor::OneWayDescriptor() |
|
{ |
|
m_pose_count = 0; |
|
m_samples = 0; |
|
m_input_patch = 0; |
|
m_train_patch = 0; |
|
m_pca_coeffs = 0; |
|
m_affine_poses = 0; |
|
m_transforms = 0; |
|
m_pca_dim_low = 100; |
|
m_pca_dim_high = 100; |
|
} |
|
|
|
OneWayDescriptor::~OneWayDescriptor() |
|
{ |
|
if(m_pose_count) |
|
{ |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
cvReleaseImage(&m_samples[i]); |
|
cvReleaseMat(&m_pca_coeffs[i]); |
|
} |
|
cvReleaseImage(&m_input_patch); |
|
cvReleaseImage(&m_train_patch); |
|
delete []m_samples; |
|
delete []m_pca_coeffs; |
|
|
|
if(!m_transforms) |
|
{ |
|
delete []m_affine_poses; |
|
} |
|
} |
|
} |
|
|
|
void OneWayDescriptor::Allocate(int pose_count, CvSize size, int nChannels) |
|
{ |
|
m_pose_count = pose_count; |
|
m_samples = new IplImage* [m_pose_count]; |
|
m_pca_coeffs = new CvMat* [m_pose_count]; |
|
m_patch_size = cvSize(size.width/2, size.height/2); |
|
|
|
if(!m_transforms) |
|
{ |
|
m_affine_poses = new CvAffinePose[m_pose_count]; |
|
} |
|
|
|
int length = m_pca_dim_low;//roi.width*roi.height; |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
m_samples[i] = cvCreateImage(cvSize(size.width/2, size.height/2), IPL_DEPTH_32F, nChannels); |
|
m_pca_coeffs[i] = cvCreateMat(1, length, CV_32FC1); |
|
} |
|
|
|
m_input_patch = cvCreateImage(GetPatchSize(), IPL_DEPTH_8U, 1); |
|
m_train_patch = cvCreateImage(GetInputPatchSize(), IPL_DEPTH_8U, 1); |
|
} |
|
|
|
// static void cvmSet2DPoint(CvMat* matrix, int row, int col, CvPoint2D32f point) |
|
// { |
|
// cvmSet(matrix, row, col, point.x); |
|
// cvmSet(matrix, row, col + 1, point.y); |
|
// } |
|
|
|
// static void cvmSet3DPoint(CvMat* matrix, int row, int col, CvPoint3D32f point) |
|
// { |
|
// cvmSet(matrix, row, col, point.x); |
|
// cvmSet(matrix, row, col + 1, point.y); |
|
// cvmSet(matrix, row, col + 2, point.z); |
|
// } |
|
|
|
CvAffinePose GenRandomAffinePose() |
|
{ |
|
const float scale_min = 0.8f; |
|
const float scale_max = 1.2f; |
|
CvAffinePose pose; |
|
pose.theta = float(rand())/RAND_MAX*120 - 60; |
|
pose.phi = float(rand())/RAND_MAX*360; |
|
pose.lambda1 = scale_min + float(rand())/RAND_MAX*(scale_max - scale_min); |
|
pose.lambda2 = scale_min + float(rand())/RAND_MAX*(scale_max - scale_min); |
|
|
|
return pose; |
|
} |
|
|
|
void GenerateAffineTransformFromPose(CvSize size, CvAffinePose pose, CvMat* transform) |
|
{ |
|
CvMat* temp = cvCreateMat(3, 3, CV_32FC1); |
|
CvMat* final = cvCreateMat(3, 3, CV_32FC1); |
|
cvmSet(temp, 2, 0, 0.0f); |
|
cvmSet(temp, 2, 1, 0.0f); |
|
cvmSet(temp, 2, 2, 1.0f); |
|
|
|
CvMat rotation; |
|
cvGetSubRect(temp, &rotation, cvRect(0, 0, 3, 2)); |
|
|
|
cv2DRotationMatrix(cvPoint2D32f(size.width/2, size.height/2), pose.phi, 1.0, &rotation); |
|
cvCopy(temp, final); |
|
|
|
cvmSet(temp, 0, 0, pose.lambda1); |
|
cvmSet(temp, 0, 1, 0.0f); |
|
cvmSet(temp, 1, 0, 0.0f); |
|
cvmSet(temp, 1, 1, pose.lambda2); |
|
cvmSet(temp, 0, 2, size.width/2*(1 - pose.lambda1)); |
|
cvmSet(temp, 1, 2, size.height/2*(1 - pose.lambda2)); |
|
cvMatMul(temp, final, final); |
|
|
|
cv2DRotationMatrix(cvPoint2D32f(size.width/2, size.height/2), pose.theta - pose.phi, 1.0, &rotation); |
|
cvMatMul(temp, final, final); |
|
|
|
cvGetSubRect(final, &rotation, cvRect(0, 0, 3, 2)); |
|
cvCopy(&rotation, transform); |
|
|
|
cvReleaseMat(&temp); |
|
cvReleaseMat(&final); |
|
} |
|
|
|
void AffineTransformPatch(IplImage* src, IplImage* dst, CvAffinePose pose) |
|
{ |
|
CvRect src_large_roi = cvGetImageROI(src); |
|
|
|
IplImage* temp = cvCreateImage(cvSize(src_large_roi.width, src_large_roi.height), IPL_DEPTH_32F, src->nChannels); |
|
cvSetZero(temp); |
|
IplImage* temp2 = cvCloneImage(temp); |
|
CvMat* rotation_phi = cvCreateMat(2, 3, CV_32FC1); |
|
|
|
CvSize new_size = cvSize(cvRound(temp->width*pose.lambda1), cvRound(temp->height*pose.lambda2)); |
|
IplImage* temp3 = cvCreateImage(new_size, IPL_DEPTH_32F, src->nChannels); |
|
|
|
cvConvertScale(src, temp); |
|
cvResetImageROI(temp); |
|
|
|
|
|
cv2DRotationMatrix(cvPoint2D32f(temp->width/2, temp->height/2), pose.phi, 1.0, rotation_phi); |
|
cvWarpAffine(temp, temp2, rotation_phi); |
|
|
|
cvSetZero(temp); |
|
|
|
cvResize(temp2, temp3); |
|
|
|
cv2DRotationMatrix(cvPoint2D32f(temp3->width/2, temp3->height/2), pose.theta - pose.phi, 1.0, rotation_phi); |
|
cvWarpAffine(temp3, temp, rotation_phi); |
|
|
|
cvSetImageROI(temp, cvRect(temp->width/2 - src_large_roi.width/4, temp->height/2 - src_large_roi.height/4, |
|
src_large_roi.width/2, src_large_roi.height/2)); |
|
cvConvertScale(temp, dst); |
|
cvReleaseMat(&rotation_phi); |
|
|
|
cvReleaseImage(&temp3); |
|
cvReleaseImage(&temp2); |
|
cvReleaseImage(&temp); |
|
} |
|
|
|
void OneWayDescriptor::GenerateSamples(int pose_count, IplImage* frontal, int norm) |
|
{ |
|
/* if(m_transforms) |
|
{ |
|
GenerateSamplesWithTransforms(pose_count, frontal); |
|
return; |
|
} |
|
*/ |
|
CvRect roi = cvGetImageROI(frontal); |
|
IplImage* patch_8u = cvCreateImage(cvSize(roi.width/2, roi.height/2), frontal->depth, frontal->nChannels); |
|
for(int i = 0; i < pose_count; i++) |
|
{ |
|
if(!m_transforms) |
|
{ |
|
m_affine_poses[i] = GenRandomAffinePose(); |
|
} |
|
//AffineTransformPatch(frontal, patch_8u, m_affine_poses[i]); |
|
generate_mean_patch(frontal, patch_8u, m_affine_poses[i], num_mean_components, noise_intensity); |
|
|
|
double scale = 1.0f; |
|
if(norm) |
|
{ |
|
double sum = cvSum(patch_8u).val[0]; |
|
scale = 1/sum; |
|
} |
|
cvConvertScale(patch_8u, m_samples[i], scale); |
|
|
|
#if 0 |
|
double maxval; |
|
cvMinMaxLoc(m_samples[i], 0, &maxval); |
|
IplImage* test = cvCreateImage(cvSize(roi.width/2, roi.height/2), IPL_DEPTH_8U, 1); |
|
cvConvertScale(m_samples[i], test, 255.0/maxval); |
|
cvNamedWindow("1", 1); |
|
cvShowImage("1", test); |
|
cvWaitKey(0); |
|
#endif |
|
} |
|
cvReleaseImage(&patch_8u); |
|
} |
|
|
|
void OneWayDescriptor::GenerateSamplesFast(IplImage* frontal, CvMat* pca_hr_avg, |
|
CvMat* pca_hr_eigenvectors, OneWayDescriptor* pca_descriptors) |
|
{ |
|
CvRect roi = cvGetImageROI(frontal); |
|
if(roi.width != GetInputPatchSize().width || roi.height != GetInputPatchSize().height) |
|
{ |
|
cvResize(frontal, m_train_patch); |
|
frontal = m_train_patch; |
|
} |
|
|
|
CvMat* pca_coeffs = cvCreateMat(1, pca_hr_eigenvectors->cols, CV_32FC1); |
|
double maxval; |
|
cvMinMaxLoc(frontal, 0, &maxval); |
|
CvMat* frontal_data = ConvertImageToMatrix(frontal); |
|
|
|
double sum = cvSum(frontal_data).val[0]; |
|
cvConvertScale(frontal_data, frontal_data, 1.0f/sum); |
|
cvProjectPCA(frontal_data, pca_hr_avg, pca_hr_eigenvectors, pca_coeffs); |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
cvSetZero(m_samples[i]); |
|
for(int j = 0; j < m_pca_dim_high; j++) |
|
{ |
|
double coeff = cvmGet(pca_coeffs, 0, j); |
|
IplImage* patch = pca_descriptors[j + 1].GetPatch(i); |
|
cvAddWeighted(m_samples[i], 1.0, patch, coeff, 0, m_samples[i]); |
|
|
|
#if 0 |
|
printf("coeff%d = %f\n", j, coeff); |
|
IplImage* test = cvCreateImage(cvSize(12, 12), IPL_DEPTH_8U, 1); |
|
double maxval; |
|
cvMinMaxLoc(patch, 0, &maxval); |
|
cvConvertScale(patch, test, 255.0/maxval); |
|
cvNamedWindow("1", 1); |
|
cvShowImage("1", test); |
|
cvWaitKey(0); |
|
#endif |
|
} |
|
|
|
cvAdd(pca_descriptors[0].GetPatch(i), m_samples[i], m_samples[i]); |
|
double sm = cvSum(m_samples[i]).val[0]; |
|
cvConvertScale(m_samples[i], m_samples[i], 1.0/sm); |
|
|
|
#if 0 |
|
IplImage* test = cvCreateImage(cvSize(12, 12), IPL_DEPTH_8U, 1); |
|
/* IplImage* temp1 = cvCreateImage(cvSize(12, 12), IPL_DEPTH_32F, 1); |
|
eigenvector2image(pca_hr_avg, temp1); |
|
IplImage* test = cvCreateImage(cvSize(12, 12), IPL_DEPTH_8U, 1); |
|
cvAdd(m_samples[i], temp1, temp1); |
|
cvMinMaxLoc(temp1, 0, &maxval); |
|
cvConvertScale(temp1, test, 255.0/maxval);*/ |
|
cvMinMaxLoc(m_samples[i], 0, &maxval); |
|
cvConvertScale(m_samples[i], test, 255.0/maxval); |
|
|
|
cvNamedWindow("1", 1); |
|
cvShowImage("1", frontal); |
|
cvNamedWindow("2", 1); |
|
cvShowImage("2", test); |
|
cvWaitKey(0); |
|
#endif |
|
} |
|
|
|
cvReleaseMat(&pca_coeffs); |
|
cvReleaseMat(&frontal_data); |
|
} |
|
|
|
void OneWayDescriptor::SetTransforms(CvAffinePose* poses, CvMat** transforms) |
|
{ |
|
if(m_affine_poses) |
|
{ |
|
delete []m_affine_poses; |
|
} |
|
|
|
m_affine_poses = poses; |
|
m_transforms = transforms; |
|
} |
|
|
|
void OneWayDescriptor::Initialize(int pose_count, IplImage* frontal, const char* feature_name, int norm) |
|
{ |
|
m_feature_name = String(feature_name); |
|
CvRect roi = cvGetImageROI(frontal); |
|
m_center = rect_center(roi); |
|
|
|
Allocate(pose_count, cvSize(roi.width, roi.height), frontal->nChannels); |
|
|
|
GenerateSamples(pose_count, frontal, norm); |
|
} |
|
|
|
void OneWayDescriptor::InitializeFast(int pose_count, IplImage* frontal, const char* feature_name, |
|
CvMat* pca_hr_avg, CvMat* pca_hr_eigenvectors, OneWayDescriptor* pca_descriptors) |
|
{ |
|
if(pca_hr_avg == 0) |
|
{ |
|
Initialize(pose_count, frontal, feature_name, 1); |
|
return; |
|
} |
|
m_feature_name = String(feature_name); |
|
CvRect roi = cvGetImageROI(frontal); |
|
m_center = rect_center(roi); |
|
|
|
Allocate(pose_count, cvSize(roi.width, roi.height), frontal->nChannels); |
|
|
|
GenerateSamplesFast(frontal, pca_hr_avg, pca_hr_eigenvectors, pca_descriptors); |
|
} |
|
|
|
void OneWayDescriptor::InitializePCACoeffs(CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
ProjectPCASample(m_samples[i], avg, eigenvectors, m_pca_coeffs[i]); |
|
} |
|
} |
|
|
|
void OneWayDescriptor::ProjectPCASample(IplImage* patch, CvMat* avg, CvMat* eigenvectors, CvMat* pca_coeffs) const |
|
{ |
|
CvMat* patch_mat = ConvertImageToMatrix(patch); |
|
// CvMat eigenvectorsr; |
|
// cvGetSubRect(eigenvectors, &eigenvectorsr, cvRect(0, 0, eigenvectors->cols, pca_coeffs->cols)); |
|
CvMat* temp = cvCreateMat(1, eigenvectors->cols, CV_32FC1); |
|
cvProjectPCA(patch_mat, avg, eigenvectors, temp); |
|
CvMat temp1; |
|
cvGetSubRect(temp, &temp1, cvRect(0, 0, pca_coeffs->cols, 1)); |
|
cvCopy(&temp1, pca_coeffs); |
|
|
|
cvReleaseMat(&temp); |
|
cvReleaseMat(&patch_mat); |
|
} |
|
|
|
void OneWayDescriptor::EstimatePosePCA(CvArr* patch, int& pose_idx, float& distance, CvMat* avg, CvMat* eigenvectors) const |
|
{ |
|
if(avg == 0) |
|
{ |
|
// do not use pca |
|
if (!CV_IS_MAT(patch)) |
|
{ |
|
EstimatePose((IplImage*)patch, pose_idx, distance); |
|
} |
|
else |
|
{ |
|
|
|
} |
|
return; |
|
} |
|
CvRect roi; |
|
if (!CV_IS_MAT(patch)) |
|
{ |
|
roi = cvGetImageROI((IplImage*)patch); |
|
if(roi.width != GetPatchSize().width || roi.height != GetPatchSize().height) |
|
{ |
|
cvResize(patch, m_input_patch); |
|
patch = m_input_patch; |
|
roi = cvGetImageROI((IplImage*)patch); |
|
} |
|
} |
|
|
|
CvMat* pca_coeffs = cvCreateMat(1, m_pca_dim_low, CV_32FC1); |
|
|
|
if (CV_IS_MAT(patch)) |
|
{ |
|
cvCopy((CvMat*)patch, pca_coeffs); |
|
} |
|
else |
|
{ |
|
IplImage* patch_32f = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_32F, 1); |
|
double sum = cvSum(patch).val[0]; |
|
cvConvertScale(patch, patch_32f, 1.0f/sum); |
|
ProjectPCASample(patch_32f, avg, eigenvectors, pca_coeffs); |
|
cvReleaseImage(&patch_32f); |
|
} |
|
|
|
|
|
distance = 1e10; |
|
pose_idx = -1; |
|
|
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
double dist = cvNorm(m_pca_coeffs[i], pca_coeffs); |
|
// float dist = 0; |
|
// float data1, data2; |
|
// //CvMat* pose_pca_coeffs = m_pca_coeffs[i]; |
|
// for (int x=0; x < pca_coeffs->width; x++) |
|
// for (int y =0 ; y < pca_coeffs->height; y++) |
|
// { |
|
// data1 = ((float*)(pca_coeffs->data.ptr + pca_coeffs->step*x))[y]; |
|
// data2 = ((float*)(m_pca_coeffs[i]->data.ptr + m_pca_coeffs[i]->step*x))[y]; |
|
// dist+=(data1-data2)*(data1-data2); |
|
// } |
|
////#if 1 |
|
// for (int j = 0; j < m_pca_dim_low; j++) |
|
// { |
|
// dist += (pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j])*(pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j]); |
|
// } |
|
//#else |
|
// for (int j = 0; j <= m_pca_dim_low - 4; j += 4) |
|
// { |
|
// dist += (pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j])* |
|
// (pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j]); |
|
// dist += (pose_pca_coeffs->data.fl[j+1]- pca_coeffs->data.fl[j+1])* |
|
// (pose_pca_coeffs->data.fl[j+1]- pca_coeffs->data.fl[j+1]); |
|
// dist += (pose_pca_coeffs->data.fl[j+2]- pca_coeffs->data.fl[j+2])* |
|
// (pose_pca_coeffs->data.fl[j+2]- pca_coeffs->data.fl[j+2]); |
|
// dist += (pose_pca_coeffs->data.fl[j+3]- pca_coeffs->data.fl[j+3])* |
|
// (pose_pca_coeffs->data.fl[j+3]- pca_coeffs->data.fl[j+3]); |
|
// } |
|
//#endif |
|
if(dist < distance) |
|
{ |
|
distance = (float)dist; |
|
pose_idx = i; |
|
} |
|
} |
|
|
|
cvReleaseMat(&pca_coeffs); |
|
} |
|
|
|
void OneWayDescriptor::EstimatePose(IplImage* patch, int& pose_idx, float& distance) const |
|
{ |
|
distance = 1e10; |
|
pose_idx = -1; |
|
|
|
CvRect roi = cvGetImageROI(patch); |
|
IplImage* patch_32f = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_32F, patch->nChannels); |
|
double sum = cvSum(patch).val[0]; |
|
cvConvertScale(patch, patch_32f, 1/sum); |
|
|
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
if(m_samples[i]->width != patch_32f->width || m_samples[i]->height != patch_32f->height) |
|
{ |
|
continue; |
|
} |
|
double dist = cvNorm(m_samples[i], patch_32f); |
|
//float dist = 0.0f; |
|
//float i1,i2; |
|
|
|
//for (int y = 0; y<patch_32f->height; y++) |
|
// for (int x = 0; x< patch_32f->width; x++) |
|
// { |
|
// i1 = ((float*)(m_samples[i]->imageData + m_samples[i]->widthStep*y))[x]; |
|
// i2 = ((float*)(patch_32f->imageData + patch_32f->widthStep*y))[x]; |
|
// dist+= (i1-i2)*(i1-i2); |
|
// } |
|
|
|
if(dist < distance) |
|
{ |
|
distance = (float)dist; |
|
pose_idx = i; |
|
} |
|
|
|
#if 0 |
|
IplImage* img1 = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_8U, 1); |
|
IplImage* img2 = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_8U, 1); |
|
double maxval; |
|
cvMinMaxLoc(m_samples[i], 0, &maxval); |
|
cvConvertScale(m_samples[i], img1, 255.0/maxval); |
|
cvMinMaxLoc(patch_32f, 0, &maxval); |
|
cvConvertScale(patch_32f, img2, 255.0/maxval); |
|
|
|
cvNamedWindow("1", 1); |
|
cvShowImage("1", img1); |
|
cvNamedWindow("2", 1); |
|
cvShowImage("2", img2); |
|
printf("Distance = %f\n", dist); |
|
cvWaitKey(0); |
|
#endif |
|
} |
|
|
|
cvReleaseImage(&patch_32f); |
|
} |
|
|
|
void OneWayDescriptor::Save(const char* path) |
|
{ |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
char buf[1024]; |
|
sprintf(buf, "%s/patch_%04d.png", path, i); |
|
IplImage* patch = cvCreateImage(cvSize(m_samples[i]->width, m_samples[i]->height), IPL_DEPTH_8U, m_samples[i]->nChannels); |
|
|
|
double maxval; |
|
cvMinMaxLoc(m_samples[i], 0, &maxval); |
|
cvConvertScale(m_samples[i], patch, 255/maxval); |
|
|
|
#ifdef HAVE_OPENCV_HIGHGUI |
|
cv::imwrite(buf, cv::cvarrToMat(patch)); |
|
#else |
|
CV_Error(CV_StsNotImplemented, "OpenCV has been compiled without image I/O support"); |
|
#endif |
|
|
|
cvReleaseImage(&patch); |
|
} |
|
} |
|
|
|
void OneWayDescriptor::Write(CvFileStorage* fs, const char* name) |
|
{ |
|
CvMat* mat = cvCreateMat(m_pose_count, m_samples[0]->width*m_samples[0]->height, CV_32FC1); |
|
|
|
// prepare data to write as a single matrix |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
for(int y = 0; y < m_samples[i]->height; y++) |
|
{ |
|
for(int x = 0; x < m_samples[i]->width; x++) |
|
{ |
|
float val = *((float*)(m_samples[i]->imageData + m_samples[i]->widthStep*y) + x); |
|
cvmSet(mat, i, y*m_samples[i]->width + x, val); |
|
} |
|
} |
|
} |
|
|
|
cvWrite(fs, name, mat); |
|
|
|
cvReleaseMat(&mat); |
|
} |
|
|
|
int OneWayDescriptor::ReadByName(const FileNode &parent, const char* name) |
|
{ |
|
CvMat* mat = reinterpret_cast<CvMat*> (parent[name].readObj ()); |
|
if(!mat) |
|
{ |
|
return 0; |
|
} |
|
|
|
|
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
for(int y = 0; y < m_samples[i]->height; y++) |
|
{ |
|
for(int x = 0; x < m_samples[i]->width; x++) |
|
{ |
|
float val = (float)cvmGet(mat, i, y*m_samples[i]->width + x); |
|
*((float*)(m_samples[i]->imageData + y*m_samples[i]->widthStep) + x) = val; |
|
} |
|
} |
|
} |
|
|
|
cvReleaseMat(&mat); |
|
return 1; |
|
} |
|
|
|
int OneWayDescriptor::ReadByName(CvFileStorage* fs, CvFileNode* parent, const char* name) |
|
{ |
|
return ReadByName (FileNode (fs, parent), name); |
|
} |
|
|
|
IplImage* OneWayDescriptor::GetPatch(int index) |
|
{ |
|
return m_samples[index]; |
|
} |
|
|
|
CvAffinePose OneWayDescriptor::GetPose(int index) const |
|
{ |
|
return m_affine_poses[index]; |
|
} |
|
|
|
void FindOneWayDescriptor(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, int& desc_idx, int& pose_idx, float& distance, |
|
CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
desc_idx = -1; |
|
pose_idx = -1; |
|
distance = 1e10; |
|
//-------- |
|
//PCA_coeffs precalculating |
|
int m_pca_dim_low = descriptors[0].GetPCADimLow(); |
|
CvMat* pca_coeffs = cvCreateMat(1, m_pca_dim_low, CV_32FC1); |
|
int patch_width = descriptors[0].GetPatchSize().width; |
|
int patch_height = descriptors[0].GetPatchSize().height; |
|
if (avg) |
|
{ |
|
CvRect _roi = cvGetImageROI((IplImage*)patch); |
|
IplImage* test_img = cvCreateImage(cvSize(patch_width,patch_height), IPL_DEPTH_8U, 1); |
|
if(_roi.width != patch_width|| _roi.height != patch_height) |
|
{ |
|
|
|
cvResize(patch, test_img); |
|
_roi = cvGetImageROI(test_img); |
|
} |
|
else |
|
{ |
|
cvCopy(patch,test_img); |
|
} |
|
IplImage* patch_32f = cvCreateImage(cvSize(_roi.width, _roi.height), IPL_DEPTH_32F, 1); |
|
double sum = cvSum(test_img).val[0]; |
|
cvConvertScale(test_img, patch_32f, 1.0f/sum); |
|
|
|
//ProjectPCASample(patch_32f, avg, eigenvectors, pca_coeffs); |
|
//Projecting PCA |
|
CvMat* patch_mat = ConvertImageToMatrix(patch_32f); |
|
CvMat* temp = cvCreateMat(1, eigenvectors->cols, CV_32FC1); |
|
cvProjectPCA(patch_mat, avg, eigenvectors, temp); |
|
CvMat temp1; |
|
cvGetSubRect(temp, &temp1, cvRect(0, 0, pca_coeffs->cols, 1)); |
|
cvCopy(&temp1, pca_coeffs); |
|
cvReleaseMat(&temp); |
|
cvReleaseMat(&patch_mat); |
|
//End of projecting |
|
|
|
cvReleaseImage(&patch_32f); |
|
cvReleaseImage(&test_img); |
|
} |
|
|
|
//-------- |
|
|
|
|
|
|
|
for(int i = 0; i < desc_count; i++) |
|
{ |
|
int _pose_idx = -1; |
|
float _distance = 0; |
|
|
|
#if 0 |
|
descriptors[i].EstimatePose(patch, _pose_idx, _distance); |
|
#else |
|
if (!avg) |
|
{ |
|
descriptors[i].EstimatePosePCA(patch, _pose_idx, _distance, avg, eigenvectors); |
|
} |
|
else |
|
{ |
|
descriptors[i].EstimatePosePCA(pca_coeffs, _pose_idx, _distance, avg, eigenvectors); |
|
} |
|
#endif |
|
|
|
if(_distance < distance) |
|
{ |
|
desc_idx = i; |
|
pose_idx = _pose_idx; |
|
distance = _distance; |
|
} |
|
} |
|
cvReleaseMat(&pca_coeffs); |
|
} |
|
|
|
#if defined(_KDTREE) |
|
|
|
void FindOneWayDescriptor(cv::flann::Index* m_pca_descriptors_tree, CvSize patch_size, int m_pca_dim_low, int m_pose_count, IplImage* patch, int& desc_idx, int& pose_idx, float& distance, |
|
CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
desc_idx = -1; |
|
pose_idx = -1; |
|
distance = 1e10; |
|
//-------- |
|
//PCA_coeffs precalculating |
|
CvMat* pca_coeffs = cvCreateMat(1, m_pca_dim_low, CV_32FC1); |
|
int patch_width = patch_size.width; |
|
int patch_height = patch_size.height; |
|
//if (avg) |
|
//{ |
|
CvRect _roi = cvGetImageROI((IplImage*)patch); |
|
IplImage* test_img = cvCreateImage(cvSize(patch_width,patch_height), IPL_DEPTH_8U, 1); |
|
if(_roi.width != patch_width|| _roi.height != patch_height) |
|
{ |
|
|
|
cvResize(patch, test_img); |
|
_roi = cvGetImageROI(test_img); |
|
} |
|
else |
|
{ |
|
cvCopy(patch,test_img); |
|
} |
|
IplImage* patch_32f = cvCreateImage(cvSize(_roi.width, _roi.height), IPL_DEPTH_32F, 1); |
|
float sum = cvSum(test_img).val[0]; |
|
cvConvertScale(test_img, patch_32f, 1.0f/sum); |
|
|
|
//ProjectPCASample(patch_32f, avg, eigenvectors, pca_coeffs); |
|
//Projecting PCA |
|
CvMat* patch_mat = ConvertImageToMatrix(patch_32f); |
|
CvMat* temp = cvCreateMat(1, eigenvectors->cols, CV_32FC1); |
|
cvProjectPCA(patch_mat, avg, eigenvectors, temp); |
|
CvMat temp1; |
|
cvGetSubRect(temp, &temp1, cvRect(0, 0, pca_coeffs->cols, 1)); |
|
cvCopy(&temp1, pca_coeffs); |
|
cvReleaseMat(&temp); |
|
cvReleaseMat(&patch_mat); |
|
//End of projecting |
|
|
|
cvReleaseImage(&patch_32f); |
|
cvReleaseImage(&test_img); |
|
// } |
|
|
|
//-------- |
|
|
|
//float* target = new float[m_pca_dim_low]; |
|
//::cvflann::KNNResultSet res(1,pca_coeffs->data.fl,m_pca_dim_low); |
|
//::cvflann::SearchParams params; |
|
//params.checks = -1; |
|
|
|
//int maxDepth = 1000000; |
|
//int neighbors_count = 1; |
|
//int* neighborsIdx = new int[neighbors_count]; |
|
//float* distances = new float[neighbors_count]; |
|
//if (m_pca_descriptors_tree->findNearest(pca_coeffs->data.fl,neighbors_count,maxDepth,neighborsIdx,0,distances) > 0) |
|
//{ |
|
// desc_idx = neighborsIdx[0] / m_pose_count; |
|
// pose_idx = neighborsIdx[0] % m_pose_count; |
|
// distance = distances[0]; |
|
//} |
|
//delete[] neighborsIdx; |
|
//delete[] distances; |
|
|
|
cv::Mat m_object(1, m_pca_dim_low, CV_32F); |
|
cv::Mat m_indices(1, 1, CV_32S); |
|
cv::Mat m_dists(1, 1, CV_32F); |
|
|
|
float* object_ptr = m_object.ptr<float>(0); |
|
for (int i=0;i<m_pca_dim_low;i++) |
|
{ |
|
object_ptr[i] = pca_coeffs->data.fl[i]; |
|
} |
|
|
|
m_pca_descriptors_tree->knnSearch(m_object, m_indices, m_dists, 1, cv::flann::SearchParams(-1) ); |
|
|
|
desc_idx = ((int*)(m_indices.ptr<int>(0)))[0] / m_pose_count; |
|
pose_idx = ((int*)(m_indices.ptr<int>(0)))[0] % m_pose_count; |
|
distance = ((float*)(m_dists.ptr<float>(0)))[0]; |
|
|
|
// delete[] target; |
|
|
|
|
|
// for(int i = 0; i < desc_count; i++) |
|
// { |
|
// int _pose_idx = -1; |
|
// float _distance = 0; |
|
// |
|
//#if 0 |
|
// descriptors[i].EstimatePose(patch, _pose_idx, _distance); |
|
//#else |
|
// if (!avg) |
|
// { |
|
// descriptors[i].EstimatePosePCA(patch, _pose_idx, _distance, avg, eigenvectors); |
|
// } |
|
// else |
|
// { |
|
// descriptors[i].EstimatePosePCA(pca_coeffs, _pose_idx, _distance, avg, eigenvectors); |
|
// } |
|
//#endif |
|
// |
|
// if(_distance < distance) |
|
// { |
|
// desc_idx = i; |
|
// pose_idx = _pose_idx; |
|
// distance = _distance; |
|
// } |
|
// } |
|
cvReleaseMat(&pca_coeffs); |
|
} |
|
#endif |
|
//** |
|
void FindOneWayDescriptor(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, int n, |
|
std::vector<int>& desc_idxs, std::vector<int>& pose_idxs, std::vector<float>& distances, |
|
CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
for (int i=0;i<n;i++) |
|
{ |
|
desc_idxs[i] = -1; |
|
pose_idxs[i] = -1; |
|
distances[i] = 1e10; |
|
} |
|
//-------- |
|
//PCA_coeffs precalculating |
|
int m_pca_dim_low = descriptors[0].GetPCADimLow(); |
|
CvMat* pca_coeffs = cvCreateMat(1, m_pca_dim_low, CV_32FC1); |
|
int patch_width = descriptors[0].GetPatchSize().width; |
|
int patch_height = descriptors[0].GetPatchSize().height; |
|
if (avg) |
|
{ |
|
CvRect _roi = cvGetImageROI((IplImage*)patch); |
|
IplImage* test_img = cvCreateImage(cvSize(patch_width,patch_height), IPL_DEPTH_8U, 1); |
|
if(_roi.width != patch_width|| _roi.height != patch_height) |
|
{ |
|
|
|
cvResize(patch, test_img); |
|
_roi = cvGetImageROI(test_img); |
|
} |
|
else |
|
{ |
|
cvCopy(patch,test_img); |
|
} |
|
IplImage* patch_32f = cvCreateImage(cvSize(_roi.width, _roi.height), IPL_DEPTH_32F, 1); |
|
double sum = cvSum(test_img).val[0]; |
|
cvConvertScale(test_img, patch_32f, 1.0f/sum); |
|
|
|
//ProjectPCASample(patch_32f, avg, eigenvectors, pca_coeffs); |
|
//Projecting PCA |
|
CvMat* patch_mat = ConvertImageToMatrix(patch_32f); |
|
CvMat* temp = cvCreateMat(1, eigenvectors->cols, CV_32FC1); |
|
cvProjectPCA(patch_mat, avg, eigenvectors, temp); |
|
CvMat temp1; |
|
cvGetSubRect(temp, &temp1, cvRect(0, 0, pca_coeffs->cols, 1)); |
|
cvCopy(&temp1, pca_coeffs); |
|
cvReleaseMat(&temp); |
|
cvReleaseMat(&patch_mat); |
|
//End of projecting |
|
|
|
cvReleaseImage(&patch_32f); |
|
cvReleaseImage(&test_img); |
|
} |
|
//-------- |
|
|
|
|
|
|
|
for(int i = 0; i < desc_count; i++) |
|
{ |
|
int _pose_idx = -1; |
|
float _distance = 0; |
|
|
|
#if 0 |
|
descriptors[i].EstimatePose(patch, _pose_idx, _distance); |
|
#else |
|
if (!avg) |
|
{ |
|
descriptors[i].EstimatePosePCA(patch, _pose_idx, _distance, avg, eigenvectors); |
|
} |
|
else |
|
{ |
|
descriptors[i].EstimatePosePCA(pca_coeffs, _pose_idx, _distance, avg, eigenvectors); |
|
} |
|
#endif |
|
|
|
for (int j=0;j<n;j++) |
|
{ |
|
if(_distance < distances[j]) |
|
{ |
|
for (int k=(n-1);k > j;k--) |
|
{ |
|
desc_idxs[k] = desc_idxs[k-1]; |
|
pose_idxs[k] = pose_idxs[k-1]; |
|
distances[k] = distances[k-1]; |
|
} |
|
desc_idxs[j] = i; |
|
pose_idxs[j] = _pose_idx; |
|
distances[j] = _distance; |
|
break; |
|
} |
|
} |
|
} |
|
cvReleaseMat(&pca_coeffs); |
|
} |
|
|
|
void FindOneWayDescriptorEx(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, |
|
float scale_min, float scale_max, float scale_step, |
|
int& desc_idx, int& pose_idx, float& distance, float& scale, |
|
CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
CvSize patch_size = descriptors[0].GetPatchSize(); |
|
IplImage* input_patch; |
|
CvRect roi; |
|
|
|
input_patch= cvCreateImage(patch_size, IPL_DEPTH_8U, 1); |
|
roi = cvGetImageROI((IplImage*)patch); |
|
|
|
int _desc_idx, _pose_idx; |
|
float _distance; |
|
distance = 1e10; |
|
for(float cur_scale = scale_min; cur_scale < scale_max; cur_scale *= scale_step) |
|
{ |
|
// printf("Scale = %f\n", cur_scale); |
|
|
|
CvRect roi_scaled = resize_rect(roi, cur_scale); |
|
cvSetImageROI(patch, roi_scaled); |
|
cvResize(patch, input_patch); |
|
|
|
|
|
#if 0 |
|
if(roi.x > 244 && roi.y < 200) |
|
{ |
|
cvNamedWindow("1", 1); |
|
cvShowImage("1", input_patch); |
|
cvWaitKey(0); |
|
} |
|
#endif |
|
|
|
FindOneWayDescriptor(desc_count, descriptors, input_patch, _desc_idx, _pose_idx, _distance, avg, eigenvectors); |
|
if(_distance < distance) |
|
{ |
|
distance = _distance; |
|
desc_idx = _desc_idx; |
|
pose_idx = _pose_idx; |
|
scale = cur_scale; |
|
} |
|
} |
|
|
|
|
|
cvSetImageROI((IplImage*)patch, roi); |
|
cvReleaseImage(&input_patch); |
|
|
|
} |
|
|
|
void FindOneWayDescriptorEx(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch, |
|
float scale_min, float scale_max, float scale_step, |
|
int n, std::vector<int>& desc_idxs, std::vector<int>& pose_idxs, |
|
std::vector<float>& distances, std::vector<float>& scales, |
|
CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
CvSize patch_size = descriptors[0].GetPatchSize(); |
|
IplImage* input_patch; |
|
CvRect roi; |
|
|
|
input_patch= cvCreateImage(patch_size, IPL_DEPTH_8U, 1); |
|
roi = cvGetImageROI((IplImage*)patch); |
|
|
|
// float min_distance = 1e10; |
|
std::vector<int> _desc_idxs; |
|
_desc_idxs.resize(n); |
|
std::vector<int> _pose_idxs; |
|
_pose_idxs.resize(n); |
|
std::vector<float> _distances; |
|
_distances.resize(n); |
|
|
|
|
|
for (int i=0;i<n;i++) |
|
{ |
|
distances[i] = 1e10; |
|
} |
|
|
|
for(float cur_scale = scale_min; cur_scale < scale_max; cur_scale *= scale_step) |
|
{ |
|
|
|
CvRect roi_scaled = resize_rect(roi, cur_scale); |
|
cvSetImageROI(patch, roi_scaled); |
|
cvResize(patch, input_patch); |
|
|
|
|
|
|
|
FindOneWayDescriptor(desc_count, descriptors, input_patch, n,_desc_idxs, _pose_idxs, _distances, avg, eigenvectors); |
|
for (int i=0;i<n;i++) |
|
{ |
|
if(_distances[i] < distances[i]) |
|
{ |
|
distances[i] = _distances[i]; |
|
desc_idxs[i] = _desc_idxs[i]; |
|
pose_idxs[i] = _pose_idxs[i]; |
|
scales[i] = cur_scale; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
cvSetImageROI((IplImage*)patch, roi); |
|
cvReleaseImage(&input_patch); |
|
} |
|
|
|
#if defined(_KDTREE) |
|
void FindOneWayDescriptorEx(cv::flann::Index* m_pca_descriptors_tree, CvSize patch_size, int m_pca_dim_low, |
|
int m_pose_count, IplImage* patch, |
|
float scale_min, float scale_max, float scale_step, |
|
int& desc_idx, int& pose_idx, float& distance, float& scale, |
|
CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
IplImage* input_patch; |
|
CvRect roi; |
|
|
|
input_patch= cvCreateImage(patch_size, IPL_DEPTH_8U, 1); |
|
roi = cvGetImageROI((IplImage*)patch); |
|
|
|
int _desc_idx, _pose_idx; |
|
float _distance; |
|
distance = 1e10; |
|
for(float cur_scale = scale_min; cur_scale < scale_max; cur_scale *= scale_step) |
|
{ |
|
// printf("Scale = %f\n", cur_scale); |
|
|
|
CvRect roi_scaled = resize_rect(roi, cur_scale); |
|
cvSetImageROI(patch, roi_scaled); |
|
cvResize(patch, input_patch); |
|
|
|
FindOneWayDescriptor(m_pca_descriptors_tree, patch_size, m_pca_dim_low, m_pose_count, input_patch, _desc_idx, _pose_idx, _distance, avg, eigenvectors); |
|
if(_distance < distance) |
|
{ |
|
distance = _distance; |
|
desc_idx = _desc_idx; |
|
pose_idx = _pose_idx; |
|
scale = cur_scale; |
|
} |
|
} |
|
|
|
|
|
cvSetImageROI((IplImage*)patch, roi); |
|
cvReleaseImage(&input_patch); |
|
|
|
} |
|
#endif |
|
|
|
const char* OneWayDescriptor::GetFeatureName() const |
|
{ |
|
return m_feature_name.c_str(); |
|
} |
|
|
|
CvPoint OneWayDescriptor::GetCenter() const |
|
{ |
|
return m_center; |
|
} |
|
|
|
int OneWayDescriptor::GetPCADimLow() const |
|
{ |
|
return m_pca_dim_low; |
|
} |
|
|
|
int OneWayDescriptor::GetPCADimHigh() const |
|
{ |
|
return m_pca_dim_high; |
|
} |
|
|
|
CvMat* ConvertImageToMatrix(IplImage* patch) |
|
{ |
|
CvRect roi = cvGetImageROI(patch); |
|
CvMat* mat = cvCreateMat(1, roi.width*roi.height, CV_32FC1); |
|
|
|
if(patch->depth == 32) |
|
{ |
|
for(int y = 0; y < roi.height; y++) |
|
{ |
|
for(int x = 0; x < roi.width; x++) |
|
{ |
|
mat->data.fl[y*roi.width + x] = *((float*)(patch->imageData + (y + roi.y)*patch->widthStep) + x + roi.x); |
|
} |
|
} |
|
} |
|
else if(patch->depth == 8) |
|
{ |
|
for(int y = 0; y < roi.height; y++) |
|
{ |
|
for(int x = 0; x < roi.width; x++) |
|
{ |
|
mat->data.fl[y*roi.width + x] = (float)(unsigned char)patch->imageData[(y + roi.y)*patch->widthStep + x + roi.x]; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
printf("Image depth %d is not supported\n", patch->depth); |
|
return 0; |
|
} |
|
|
|
return mat; |
|
} |
|
|
|
OneWayDescriptorBase::OneWayDescriptorBase(CvSize patch_size, int pose_count, const char* train_path, |
|
const char* pca_config, const char* pca_hr_config, |
|
const char* pca_desc_config, int pyr_levels, |
|
int pca_dim_high, int pca_dim_low) |
|
: m_pca_dim_high(pca_dim_high), m_pca_dim_low(pca_dim_low), scale_min (0.7f), scale_max(1.5f), scale_step (1.2f) |
|
{ |
|
#if defined(_KDTREE) |
|
m_pca_descriptors_matrix = 0; |
|
m_pca_descriptors_tree = 0; |
|
#endif |
|
// m_pca_descriptors_matrix = 0; |
|
m_patch_size = patch_size; |
|
m_pose_count = pose_count; |
|
m_pyr_levels = pyr_levels; |
|
m_poses = 0; |
|
m_transforms = 0; |
|
|
|
m_pca_avg = 0; |
|
m_pca_eigenvectors = 0; |
|
m_pca_hr_avg = 0; |
|
m_pca_hr_eigenvectors = 0; |
|
m_pca_descriptors = 0; |
|
|
|
m_descriptors = 0; |
|
|
|
if(train_path == 0 || strlen(train_path) == 0) |
|
{ |
|
// skip pca loading |
|
return; |
|
} |
|
char pca_config_filename[1024]; |
|
sprintf(pca_config_filename, "%s/%s", train_path, pca_config); |
|
readPCAFeatures(pca_config_filename, &m_pca_avg, &m_pca_eigenvectors); |
|
if(pca_hr_config && strlen(pca_hr_config) > 0) |
|
{ |
|
char pca_hr_config_filename[1024]; |
|
sprintf(pca_hr_config_filename, "%s/%s", train_path, pca_hr_config); |
|
readPCAFeatures(pca_hr_config_filename, &m_pca_hr_avg, &m_pca_hr_eigenvectors); |
|
} |
|
|
|
m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1]; |
|
|
|
#if !defined(_GH_REGIONS) |
|
if(pca_desc_config && strlen(pca_desc_config) > 0) |
|
// if(0) |
|
{ |
|
//printf("Loading the descriptors..."); |
|
char pca_desc_config_filename[1024]; |
|
sprintf(pca_desc_config_filename, "%s/%s", train_path, pca_desc_config); |
|
LoadPCADescriptors(pca_desc_config_filename); |
|
//printf("done.\n"); |
|
} |
|
else |
|
{ |
|
printf("Initializing the descriptors...\n"); |
|
InitializePoseTransforms(); |
|
CreatePCADescriptors(); |
|
SavePCADescriptors("pca_descriptors.yml"); |
|
} |
|
#endif //_GH_REGIONS |
|
// SavePCADescriptors("./pca_descriptors.yml"); |
|
|
|
} |
|
|
|
OneWayDescriptorBase::OneWayDescriptorBase(CvSize patch_size, int pose_count, const String &pca_filename, |
|
const String &train_path, const String &images_list, float _scale_min, float _scale_max, |
|
float _scale_step, int pyr_levels, |
|
int pca_dim_high, int pca_dim_low) |
|
: m_pca_dim_high(pca_dim_high), m_pca_dim_low(pca_dim_low), scale_min(_scale_min), scale_max(_scale_max), scale_step(_scale_step) |
|
{ |
|
#if defined(_KDTREE) |
|
m_pca_descriptors_matrix = 0; |
|
m_pca_descriptors_tree = 0; |
|
#endif |
|
m_patch_size = patch_size; |
|
m_pose_count = pose_count; |
|
m_pyr_levels = pyr_levels; |
|
m_poses = 0; |
|
m_transforms = 0; |
|
|
|
m_pca_avg = 0; |
|
m_pca_eigenvectors = 0; |
|
m_pca_hr_avg = 0; |
|
m_pca_hr_eigenvectors = 0; |
|
m_pca_descriptors = 0; |
|
|
|
m_descriptors = 0; |
|
|
|
|
|
if (pca_filename.length() == 0) |
|
{ |
|
return; |
|
} |
|
|
|
CvFileStorage* fs = cvOpenFileStorage(pca_filename.c_str(), NULL, CV_STORAGE_READ); |
|
if (fs != 0) |
|
{ |
|
cvReleaseFileStorage(&fs); |
|
|
|
readPCAFeatures(pca_filename.c_str(), &m_pca_avg, &m_pca_eigenvectors, "_lr"); |
|
readPCAFeatures(pca_filename.c_str(), &m_pca_hr_avg, &m_pca_hr_eigenvectors, "_hr"); |
|
m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1]; |
|
#if !defined(_GH_REGIONS) |
|
LoadPCADescriptors(pca_filename.c_str()); |
|
#endif //_GH_REGIONS |
|
} |
|
else |
|
{ |
|
GeneratePCA(train_path.c_str(), images_list.c_str()); |
|
m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1]; |
|
char pca_default_filename[1024]; |
|
sprintf(pca_default_filename, "%s/%s", train_path.c_str(), GetPCAFilename().c_str()); |
|
LoadPCADescriptors(pca_default_filename); |
|
} |
|
} |
|
|
|
void OneWayDescriptorBase::Read (const FileNode &fn) |
|
{ |
|
clear (); |
|
|
|
m_pose_count = fn["poseCount"]; |
|
int patch_width = fn["patchWidth"]; |
|
int patch_height = fn["patchHeight"]; |
|
m_patch_size = cvSize (patch_width, patch_height); |
|
m_pyr_levels = fn["pyrLevels"]; |
|
m_pca_dim_high = fn["pcaDimHigh"]; |
|
m_pca_dim_low = fn["pcaDimLow"]; |
|
scale_min = fn["minScale"]; |
|
scale_max = fn["maxScale"]; |
|
scale_step = fn["stepScale"]; |
|
|
|
LoadPCAall (fn); |
|
} |
|
|
|
void OneWayDescriptorBase::LoadPCAall (const FileNode &fn) |
|
{ |
|
readPCAFeatures(fn, &m_pca_avg, &m_pca_eigenvectors, "_lr"); |
|
readPCAFeatures(fn, &m_pca_hr_avg, &m_pca_hr_eigenvectors, "_hr"); |
|
m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1]; |
|
#if !defined(_GH_REGIONS) |
|
LoadPCADescriptors(fn); |
|
#endif //_GH_REGIONS |
|
} |
|
|
|
OneWayDescriptorBase::~OneWayDescriptorBase() |
|
{ |
|
cvReleaseMat(&m_pca_avg); |
|
cvReleaseMat(&m_pca_eigenvectors); |
|
|
|
if(m_pca_hr_eigenvectors) |
|
{ |
|
delete[] m_pca_descriptors; |
|
cvReleaseMat(&m_pca_hr_avg); |
|
cvReleaseMat(&m_pca_hr_eigenvectors); |
|
} |
|
|
|
|
|
if(m_descriptors) |
|
delete []m_descriptors; |
|
|
|
if(m_poses) |
|
delete []m_poses; |
|
|
|
if (m_transforms) |
|
{ |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
cvReleaseMat(&m_transforms[i]); |
|
} |
|
delete []m_transforms; |
|
} |
|
#if defined(_KDTREE) |
|
if (m_pca_descriptors_matrix) |
|
{ |
|
cvReleaseMat(&m_pca_descriptors_matrix); |
|
} |
|
if (m_pca_descriptors_tree) |
|
{ |
|
delete m_pca_descriptors_tree; |
|
} |
|
#endif |
|
} |
|
|
|
void OneWayDescriptorBase::clear(){ |
|
if (m_descriptors) |
|
{ |
|
delete []m_descriptors; |
|
m_descriptors = 0; |
|
} |
|
|
|
#if defined(_KDTREE) |
|
if (m_pca_descriptors_matrix) |
|
{ |
|
cvReleaseMat(&m_pca_descriptors_matrix); |
|
m_pca_descriptors_matrix = 0; |
|
} |
|
if (m_pca_descriptors_tree) |
|
{ |
|
delete m_pca_descriptors_tree; |
|
m_pca_descriptors_tree = 0; |
|
} |
|
#endif |
|
} |
|
|
|
void OneWayDescriptorBase::InitializePoses() |
|
{ |
|
m_poses = new CvAffinePose[m_pose_count]; |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
m_poses[i] = GenRandomAffinePose(); |
|
} |
|
} |
|
|
|
void OneWayDescriptorBase::InitializeTransformsFromPoses() |
|
{ |
|
m_transforms = new CvMat*[m_pose_count]; |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
m_transforms[i] = cvCreateMat(2, 3, CV_32FC1); |
|
GenerateAffineTransformFromPose(cvSize(m_patch_size.width*2, m_patch_size.height*2), m_poses[i], m_transforms[i]); |
|
} |
|
} |
|
|
|
void OneWayDescriptorBase::InitializePoseTransforms() |
|
{ |
|
InitializePoses(); |
|
InitializeTransformsFromPoses(); |
|
} |
|
|
|
void OneWayDescriptorBase::InitializeDescriptor(int desc_idx, IplImage* train_image, const KeyPoint& keypoint, const char* feature_label) |
|
{ |
|
|
|
// TBD add support for octave != 0 |
|
CvPoint center = keypoint.pt; |
|
|
|
CvRect roi = cvRect(center.x - m_patch_size.width/2, center.y - m_patch_size.height/2, m_patch_size.width, m_patch_size.height); |
|
cvResetImageROI(train_image); |
|
roi = fit_rect_fixedsize(roi, train_image); |
|
cvSetImageROI(train_image, roi); |
|
if(roi.width != m_patch_size.width || roi.height != m_patch_size.height) |
|
{ |
|
return; |
|
} |
|
|
|
InitializeDescriptor(desc_idx, train_image, feature_label); |
|
cvResetImageROI(train_image); |
|
} |
|
|
|
void OneWayDescriptorBase::InitializeDescriptor(int desc_idx, IplImage* train_image, const char* feature_label) |
|
{ |
|
m_descriptors[desc_idx].SetPCADimHigh(m_pca_dim_high); |
|
m_descriptors[desc_idx].SetPCADimLow(m_pca_dim_low); |
|
m_descriptors[desc_idx].SetTransforms(m_poses, m_transforms); |
|
|
|
if(!m_pca_hr_eigenvectors) |
|
{ |
|
m_descriptors[desc_idx].Initialize(m_pose_count, train_image, feature_label); |
|
} |
|
else |
|
{ |
|
m_descriptors[desc_idx].InitializeFast(m_pose_count, train_image, feature_label, |
|
m_pca_hr_avg, m_pca_hr_eigenvectors, m_pca_descriptors); |
|
} |
|
|
|
if(m_pca_avg) |
|
{ |
|
m_descriptors[desc_idx].InitializePCACoeffs(m_pca_avg, m_pca_eigenvectors); |
|
} |
|
} |
|
|
|
void OneWayDescriptorBase::FindDescriptor(IplImage* src, cv::Point2f pt, int& desc_idx, int& pose_idx, float& distance) const |
|
{ |
|
CvRect roi = cvRect(cvRound(pt.x - m_patch_size.width/4), |
|
cvRound(pt.y - m_patch_size.height/4), |
|
m_patch_size.width/2, m_patch_size.height/2); |
|
cvSetImageROI(src, roi); |
|
|
|
FindDescriptor(src, desc_idx, pose_idx, distance); |
|
cvResetImageROI(src); |
|
} |
|
|
|
void OneWayDescriptorBase::FindDescriptor(IplImage* patch, int& desc_idx, int& pose_idx, float& distance, float* _scale, float* scale_ranges) const |
|
{ |
|
#if 0 |
|
::FindOneWayDescriptor(m_train_feature_count, m_descriptors, patch, desc_idx, pose_idx, distance, m_pca_avg, m_pca_eigenvectors); |
|
#else |
|
float min = scale_min; |
|
float max = scale_max; |
|
float step = scale_step; |
|
|
|
if (scale_ranges) |
|
{ |
|
min = scale_ranges[0]; |
|
max = scale_ranges[1]; |
|
} |
|
|
|
float scale = 1.0f; |
|
|
|
#if !defined(_KDTREE) |
|
cv::FindOneWayDescriptorEx(m_train_feature_count, m_descriptors, patch, |
|
min, max, step, desc_idx, pose_idx, distance, scale, |
|
m_pca_avg, m_pca_eigenvectors); |
|
#else |
|
cv::FindOneWayDescriptorEx(m_pca_descriptors_tree, m_descriptors[0].GetPatchSize(), m_descriptors[0].GetPCADimLow(), m_pose_count, patch, |
|
min, max, step, desc_idx, pose_idx, distance, scale, |
|
m_pca_avg, m_pca_eigenvectors); |
|
#endif |
|
|
|
if (_scale) |
|
*_scale = scale; |
|
|
|
#endif |
|
} |
|
|
|
void OneWayDescriptorBase::FindDescriptor(IplImage* patch, int n, std::vector<int>& desc_idxs, std::vector<int>& pose_idxs, |
|
std::vector<float>& distances, std::vector<float>& _scales, float* scale_ranges) const |
|
{ |
|
float min = scale_min; |
|
float max = scale_max; |
|
float step = scale_step; |
|
|
|
if (scale_ranges) |
|
{ |
|
min = scale_ranges[0]; |
|
max = scale_ranges[1]; |
|
} |
|
|
|
distances.resize(n); |
|
_scales.resize(n); |
|
desc_idxs.resize(n); |
|
pose_idxs.resize(n); |
|
/*float scales = 1.0f;*/ |
|
|
|
cv::FindOneWayDescriptorEx(m_train_feature_count, m_descriptors, patch, |
|
min, max, step ,n, desc_idxs, pose_idxs, distances, _scales, |
|
m_pca_avg, m_pca_eigenvectors); |
|
|
|
} |
|
|
|
void OneWayDescriptorBase::SetPCAHigh(CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
m_pca_hr_avg = cvCloneMat(avg); |
|
m_pca_hr_eigenvectors = cvCloneMat(eigenvectors); |
|
} |
|
|
|
void OneWayDescriptorBase::SetPCALow(CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
m_pca_avg = cvCloneMat(avg); |
|
m_pca_eigenvectors = cvCloneMat(eigenvectors); |
|
} |
|
|
|
void OneWayDescriptorBase::AllocatePCADescriptors() |
|
{ |
|
m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1]; |
|
for(int i = 0; i < m_pca_dim_high + 1; i++) |
|
{ |
|
m_pca_descriptors[i].SetPCADimHigh(m_pca_dim_high); |
|
m_pca_descriptors[i].SetPCADimLow(m_pca_dim_low); |
|
} |
|
} |
|
|
|
void OneWayDescriptorBase::CreatePCADescriptors() |
|
{ |
|
if(m_pca_descriptors == 0) |
|
{ |
|
AllocatePCADescriptors(); |
|
} |
|
IplImage* frontal = cvCreateImage(m_patch_size, IPL_DEPTH_32F, 1); |
|
|
|
eigenvector2image(m_pca_hr_avg, frontal); |
|
m_pca_descriptors[0].SetTransforms(m_poses, m_transforms); |
|
m_pca_descriptors[0].Initialize(m_pose_count, frontal, "", 0); |
|
|
|
for(int j = 0; j < m_pca_dim_high; j++) |
|
{ |
|
CvMat eigenvector; |
|
cvGetSubRect(m_pca_hr_eigenvectors, &eigenvector, cvRect(0, j, m_pca_hr_eigenvectors->cols, 1)); |
|
eigenvector2image(&eigenvector, frontal); |
|
|
|
m_pca_descriptors[j + 1].SetTransforms(m_poses, m_transforms); |
|
m_pca_descriptors[j + 1].Initialize(m_pose_count, frontal, "", 0); |
|
|
|
printf("Created descriptor for PCA component %d\n", j); |
|
} |
|
|
|
cvReleaseImage(&frontal); |
|
} |
|
|
|
|
|
int OneWayDescriptorBase::LoadPCADescriptors(const char* filename) |
|
{ |
|
FileStorage fs = FileStorage (filename, FileStorage::READ); |
|
if(!fs.isOpened ()) |
|
{ |
|
printf("File %s not found...\n", filename); |
|
return 0; |
|
} |
|
|
|
LoadPCADescriptors (fs.root ()); |
|
|
|
printf("Successfully read %d pca components\n", m_pca_dim_high); |
|
fs.release (); |
|
|
|
return 1; |
|
} |
|
|
|
int OneWayDescriptorBase::LoadPCADescriptors(const FileNode &fn) |
|
{ |
|
// read affine poses |
|
// FileNode* node = cvGetFileNodeByName(fs, 0, "affine poses"); |
|
CvMat* poses = reinterpret_cast<CvMat*> (fn["affine_poses"].readObj ()); |
|
if (poses == 0) |
|
{ |
|
poses = reinterpret_cast<CvMat*> (fn["affine poses"].readObj ()); |
|
if (poses == 0) |
|
return 0; |
|
} |
|
|
|
|
|
if(m_poses) |
|
{ |
|
delete m_poses; |
|
} |
|
m_poses = new CvAffinePose[m_pose_count]; |
|
for(int i = 0; i < m_pose_count; i++) |
|
{ |
|
m_poses[i].phi = (float)cvmGet(poses, i, 0); |
|
m_poses[i].theta = (float)cvmGet(poses, i, 1); |
|
m_poses[i].lambda1 = (float)cvmGet(poses, i, 2); |
|
m_poses[i].lambda2 = (float)cvmGet(poses, i, 3); |
|
} |
|
cvReleaseMat(&poses); |
|
|
|
// now initialize pose transforms |
|
InitializeTransformsFromPoses(); |
|
|
|
m_pca_dim_high = (int) fn["pca_components_number"]; |
|
if (m_pca_dim_high == 0) |
|
{ |
|
m_pca_dim_high = (int) fn["pca components number"]; |
|
} |
|
if(m_pca_descriptors) |
|
{ |
|
delete []m_pca_descriptors; |
|
} |
|
AllocatePCADescriptors(); |
|
for(int i = 0; i < m_pca_dim_high + 1; i++) |
|
{ |
|
m_pca_descriptors[i].Allocate(m_pose_count, m_patch_size, 1); |
|
m_pca_descriptors[i].SetTransforms(m_poses, m_transforms); |
|
char buf[1024]; |
|
sprintf(buf, "descriptor_for_pca_component_%d", i); |
|
|
|
if (! m_pca_descriptors[i].ReadByName(fn, buf)) |
|
{ |
|
sprintf(buf, "descriptor for pca component %d", i); |
|
m_pca_descriptors[i].ReadByName(fn, buf); |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
|
|
void savePCAFeatures(FileStorage &fs, const char* postfix, CvMat* avg, CvMat* eigenvectors) |
|
{ |
|
char buf[1024]; |
|
sprintf(buf, "avg_%s", postfix); |
|
fs.writeObj(buf, avg); |
|
sprintf(buf, "eigenvectors_%s", postfix); |
|
fs.writeObj(buf, eigenvectors); |
|
} |
|
|
|
void calcPCAFeatures(std::vector<IplImage*>& patches, FileStorage &fs, const char* postfix, CvMat** avg, |
|
CvMat** eigenvectors) |
|
{ |
|
int width = patches[0]->width; |
|
int height = patches[0]->height; |
|
int length = width * height; |
|
int patch_count = (int)patches.size(); |
|
|
|
CvMat* data = cvCreateMat(patch_count, length, CV_32FC1); |
|
*avg = cvCreateMat(1, length, CV_32FC1); |
|
CvMat* eigenvalues = cvCreateMat(1, length, CV_32FC1); |
|
*eigenvectors = cvCreateMat(length, length, CV_32FC1); |
|
|
|
for (int i = 0; i < patch_count; i++) |
|
{ |
|
float nf = (float)(1./cvSum(patches[i]).val[0]); |
|
for (int y = 0; y < height; y++) |
|
{ |
|
for (int x = 0; x < width; x++) |
|
{ |
|
*((float*)(data->data.ptr + data->step * i) + y * width + x) |
|
= (unsigned char)patches[i]->imageData[y * patches[i]->widthStep + x] * nf; |
|
} |
|
} |
|
} |
|
|
|
//printf("Calculating PCA..."); |
|
cvCalcPCA(data, *avg, eigenvalues, *eigenvectors, CV_PCA_DATA_AS_ROW); |
|
//printf("done\n"); |
|
|
|
// save pca data |
|
savePCAFeatures(fs, postfix, *avg, *eigenvectors); |
|
|
|
cvReleaseMat(&data); |
|
cvReleaseMat(&eigenvalues); |
|
} |
|
|
|
static void extractPatches (IplImage *img, std::vector<IplImage*>& patches, CvSize patch_size) |
|
{ |
|
std::vector<KeyPoint> features; |
|
Ptr<FeatureDetector> surf_extractor = FeatureDetector::create("SURF"); |
|
if( !surf_extractor ) |
|
CV_Error(CV_StsNotImplemented, "OpenCV was built without SURF support"); |
|
surf_extractor->set("hessianThreshold", 1.0); |
|
//printf("Extracting SURF features..."); |
|
surf_extractor->detect(cv::cvarrToMat(img), features); |
|
//printf("done\n"); |
|
|
|
for (int j = 0; j < (int)features.size(); j++) |
|
{ |
|
int patch_width = patch_size.width; |
|
int patch_height = patch_size.height; |
|
|
|
CvPoint center = features[j].pt; |
|
|
|
CvRect roi = cvRect(center.x - patch_width / 2, center.y - patch_height / 2, patch_width, patch_height); |
|
cvSetImageROI(img, roi); |
|
roi = cvGetImageROI(img); |
|
if (roi.width != patch_width || roi.height != patch_height) |
|
{ |
|
continue; |
|
} |
|
|
|
IplImage* patch = cvCreateImage(cvSize(patch_width, patch_height), IPL_DEPTH_8U, 1); |
|
cvCopy(img, patch); |
|
patches.push_back(patch); |
|
cvResetImageROI(img); |
|
} |
|
//printf("Completed file, extracted %d features\n", (int)features.size()); |
|
} |
|
|
|
/* |
|
void loadPCAFeatures(const FileNode &fn, std::vector<IplImage*>& patches, CvSize patch_size) |
|
{ |
|
FileNodeIterator begin = fn.begin(); |
|
for (FileNodeIterator i = fn.begin(); i != fn.end(); i++) |
|
{ |
|
IplImage *img = reinterpret_cast<IplImage*> ((*i).readObj()); |
|
extractPatches (img, patches, patch_size); |
|
cvReleaseImage(&img); |
|
} |
|
} |
|
*/ |
|
|
|
void loadPCAFeatures(const char* path, const char* images_list, std::vector<IplImage*>& patches, CvSize patch_size) |
|
{ |
|
char images_filename[1024]; |
|
sprintf(images_filename, "%s/%s", path, images_list); |
|
FILE *pFile = fopen(images_filename, "r"); |
|
if (pFile == 0) |
|
{ |
|
printf("Cannot open images list file %s\n", images_filename); |
|
return; |
|
} |
|
while (!feof(pFile)) |
|
{ |
|
char imagename[1024]; |
|
if (fscanf(pFile, "%s", imagename) <= 0) |
|
{ |
|
break; |
|
} |
|
|
|
char filename[1024]; |
|
sprintf(filename, "%s/%s", path, imagename); |
|
|
|
//printf("Reading image %s...", filename); |
|
IplImage img; |
|
#ifdef HAVE_OPENCV_HIGHGUI |
|
Mat img2 = cv::imread(filename, IMREAD_GRAYSCALE); |
|
img = img2; |
|
#else |
|
CV_Error(CV_StsNotImplemented, "OpenCV has been compiled without image I/O support"); |
|
#endif |
|
//printf("done\n"); |
|
|
|
extractPatches (&img, patches, patch_size); |
|
} |
|
fclose(pFile); |
|
} |
|
|
|
void generatePCAFeatures(const char* path, const char* img_filename, FileStorage& fs, const char* postfix, |
|
CvSize patch_size, CvMat** avg, CvMat** eigenvectors) |
|
{ |
|
std::vector<IplImage*> patches; |
|
loadPCAFeatures(path, img_filename, patches, patch_size); |
|
calcPCAFeatures(patches, fs, postfix, avg, eigenvectors); |
|
} |
|
|
|
/* |
|
void generatePCAFeatures(const FileNode &fn, const char* postfix, |
|
CvSize patch_size, CvMat** avg, CvMat** eigenvectors) |
|
{ |
|
std::vector<IplImage*> patches; |
|
loadPCAFeatures(fn, patches, patch_size); |
|
calcPCAFeatures(patches, fs, postfix, avg, eigenvectors); |
|
} |
|
|
|
|
|
void OneWayDescriptorBase::GeneratePCA(const FileNode &fn, int pose_count) |
|
{ |
|
generatePCAFeatures(fn, "hr", m_patch_size, &m_pca_hr_avg, &m_pca_hr_eigenvectors); |
|
generatePCAFeatures(fn, "lr", cvSize(m_patch_size.width / 2, m_patch_size.height / 2), |
|
&m_pca_avg, &m_pca_eigenvectors); |
|
|
|
|
|
OneWayDescriptorBase descriptors(m_patch_size, pose_count); |
|
descriptors.SetPCAHigh(m_pca_hr_avg, m_pca_hr_eigenvectors); |
|
descriptors.SetPCALow(m_pca_avg, m_pca_eigenvectors); |
|
|
|
printf("Calculating %d PCA descriptors (you can grab a coffee, this will take a while)...\n", |
|
descriptors.GetPCADimHigh()); |
|
descriptors.InitializePoseTransforms(); |
|
descriptors.CreatePCADescriptors(); |
|
descriptors.SavePCADescriptors(*fs); |
|
} |
|
*/ |
|
|
|
void OneWayDescriptorBase::GeneratePCA(const char* img_path, const char* images_list, int pose_count) |
|
{ |
|
char pca_filename[1024]; |
|
sprintf(pca_filename, "%s/%s", img_path, GetPCAFilename().c_str()); |
|
FileStorage fs = FileStorage(pca_filename, FileStorage::WRITE); |
|
|
|
generatePCAFeatures(img_path, images_list, fs, "hr", m_patch_size, &m_pca_hr_avg, &m_pca_hr_eigenvectors); |
|
generatePCAFeatures(img_path, images_list, fs, "lr", cvSize(m_patch_size.width / 2, m_patch_size.height / 2), |
|
&m_pca_avg, &m_pca_eigenvectors); |
|
|
|
OneWayDescriptorBase descriptors(m_patch_size, pose_count); |
|
descriptors.SetPCAHigh(m_pca_hr_avg, m_pca_hr_eigenvectors); |
|
descriptors.SetPCALow(m_pca_avg, m_pca_eigenvectors); |
|
|
|
printf("Calculating %d PCA descriptors (you can grab a coffee, this will take a while)...\n", |
|
descriptors.GetPCADimHigh()); |
|
descriptors.InitializePoseTransforms(); |
|
descriptors.CreatePCADescriptors(); |
|
descriptors.SavePCADescriptors(*fs); |
|
|
|
fs.release(); |
|
} |
|
|
|
void OneWayDescriptorBase::Write (FileStorage &fs) const |
|
{ |
|
fs << "poseCount" << m_pose_count; |
|
fs << "patchWidth" << m_patch_size.width; |
|
fs << "patchHeight" << m_patch_size.height; |
|
fs << "minScale" << scale_min; |
|
fs << "maxScale" << scale_max; |
|
fs << "stepScale" << scale_step; |
|
fs << "pyrLevels" << m_pyr_levels; |
|
fs << "pcaDimHigh" << m_pca_dim_high; |
|
fs << "pcaDimLow" << m_pca_dim_low; |
|
|
|
SavePCAall (fs); |
|
} |
|
|
|
void OneWayDescriptorBase::SavePCAall (FileStorage &fs) const |
|
{ |
|
savePCAFeatures(fs, "hr", m_pca_hr_avg, m_pca_hr_eigenvectors); |
|
savePCAFeatures(fs, "lr", m_pca_avg, m_pca_eigenvectors); |
|
SavePCADescriptors(*fs); |
|
} |
|
|
|
void OneWayDescriptorBase::SavePCADescriptors(const char* filename) |
|
{ |
|
CvMemStorage* storage = cvCreateMemStorage(); |
|
CvFileStorage* fs = cvOpenFileStorage(filename, storage, CV_STORAGE_WRITE); |
|
|
|
SavePCADescriptors (fs); |
|
|
|
cvReleaseMemStorage(&storage); |
|
cvReleaseFileStorage(&fs); |
|
} |
|
|
|
void OneWayDescriptorBase::SavePCADescriptors(CvFileStorage *fs) const |
|
{ |
|
cvWriteInt(fs, "pca_components_number", m_pca_dim_high); |
|
cvWriteComment( |
|
fs, |
|
"The first component is the average Vector, so the total number of components is <pca components number> + 1", |
|
0); |
|
cvWriteInt(fs, "patch_width", m_patch_size.width); |
|
cvWriteInt(fs, "patch_height", m_patch_size.height); |
|
|
|
// pack the affine transforms into a single CvMat and write them |
|
CvMat* poses = cvCreateMat(m_pose_count, 4, CV_32FC1); |
|
for (int i = 0; i < m_pose_count; i++) |
|
{ |
|
cvmSet(poses, i, 0, m_poses[i].phi); |
|
cvmSet(poses, i, 1, m_poses[i].theta); |
|
cvmSet(poses, i, 2, m_poses[i].lambda1); |
|
cvmSet(poses, i, 3, m_poses[i].lambda2); |
|
} |
|
cvWrite(fs, "affine_poses", poses); |
|
cvReleaseMat(&poses); |
|
|
|
for (int i = 0; i < m_pca_dim_high + 1; i++) |
|
{ |
|
char buf[1024]; |
|
sprintf(buf, "descriptor_for_pca_component_%d", i); |
|
m_pca_descriptors[i].Write(fs, buf); |
|
} |
|
} |
|
|
|
|
|
void OneWayDescriptorBase::Allocate(int train_feature_count) |
|
{ |
|
m_train_feature_count = train_feature_count; |
|
m_descriptors = new OneWayDescriptor[m_train_feature_count]; |
|
for(int i = 0; i < m_train_feature_count; i++) |
|
{ |
|
m_descriptors[i].SetPCADimHigh(m_pca_dim_high); |
|
m_descriptors[i].SetPCADimLow(m_pca_dim_low); |
|
} |
|
} |
|
|
|
void OneWayDescriptorBase::InitializeDescriptors(IplImage* train_image, const std::vector<KeyPoint>& features, |
|
const char* feature_label, int desc_start_idx) |
|
{ |
|
for(int i = 0; i < (int)features.size(); i++) |
|
{ |
|
InitializeDescriptor(desc_start_idx + i, train_image, features[i], feature_label); |
|
|
|
} |
|
cvResetImageROI(train_image); |
|
|
|
#if defined(_KDTREE) |
|
ConvertDescriptorsArrayToTree(); |
|
#endif |
|
} |
|
|
|
void OneWayDescriptorBase::CreateDescriptorsFromImage(IplImage* src, const std::vector<KeyPoint>& features) |
|
{ |
|
m_train_feature_count = (int)features.size(); |
|
|
|
m_descriptors = new OneWayDescriptor[m_train_feature_count]; |
|
|
|
InitializeDescriptors(src, features); |
|
|
|
} |
|
|
|
#if defined(_KDTREE) |
|
void OneWayDescriptorBase::ConvertDescriptorsArrayToTree() |
|
{ |
|
int n = this->GetDescriptorCount(); |
|
if (n<1) |
|
return; |
|
int pca_dim_low = this->GetDescriptor(0)->GetPCADimLow(); |
|
|
|
//if (!m_pca_descriptors_matrix) |
|
// m_pca_descriptors_matrix = new ::cvflann::Matrix<float>(n*m_pose_count,pca_dim_low); |
|
//else |
|
//{ |
|
// if ((m_pca_descriptors_matrix->cols != pca_dim_low)&&(m_pca_descriptors_matrix->rows != n*m_pose_count)) |
|
// { |
|
// delete m_pca_descriptors_matrix; |
|
// m_pca_descriptors_matrix = new ::cvflann::Matrix<float>(n*m_pose_count,pca_dim_low); |
|
// } |
|
//} |
|
|
|
m_pca_descriptors_matrix = cvCreateMat(n*m_pose_count,pca_dim_low,CV_32FC1); |
|
for (int i=0;i<n;i++) |
|
{ |
|
CvMat** pca_coeffs = m_descriptors[i].GetPCACoeffs(); |
|
for (int j = 0;j<m_pose_count;j++) |
|
{ |
|
for (int k=0;k<pca_dim_low;k++) |
|
{ |
|
m_pca_descriptors_matrix->data.fl[(i*m_pose_count+j)*m_pca_dim_low + k] = pca_coeffs[j]->data.fl[k]; |
|
} |
|
} |
|
} |
|
cv::Mat pca_descriptors_mat(m_pca_descriptors_matrix,false); |
|
|
|
//::cvflann::KDTreeIndexParams params; |
|
//params.trees = 1; |
|
//m_pca_descriptors_tree = new KDTree(pca_descriptors_mat); |
|
m_pca_descriptors_tree = new cv::flann::Index(pca_descriptors_mat,cv::flann::KDTreeIndexParams(1)); |
|
//cvReleaseMat(&m_pca_descriptors_matrix); |
|
//m_pca_descriptors_tree->buildIndex(); |
|
} |
|
#endif |
|
|
|
void OneWayDescriptorObject::Allocate(int train_feature_count, int object_feature_count) |
|
{ |
|
OneWayDescriptorBase::Allocate(train_feature_count); |
|
m_object_feature_count = object_feature_count; |
|
|
|
m_part_id = new int[m_object_feature_count]; |
|
} |
|
|
|
|
|
void OneWayDescriptorObject::InitializeObjectDescriptors(IplImage* train_image, const std::vector<KeyPoint>& features, |
|
const char* feature_label, int desc_start_idx, float scale, int is_background) |
|
{ |
|
InitializeDescriptors(train_image, features, feature_label, desc_start_idx); |
|
|
|
for(int i = 0; i < (int)features.size(); i++) |
|
{ |
|
CvPoint center = features[i].pt; |
|
|
|
if(!is_background) |
|
{ |
|
// remember descriptor part id |
|
CvPoint center_scaled = cvPoint(round(center.x*scale), round(center.y*scale)); |
|
m_part_id[i + desc_start_idx] = MatchPointToPart(center_scaled); |
|
} |
|
} |
|
cvResetImageROI(train_image); |
|
} |
|
|
|
int OneWayDescriptorObject::IsDescriptorObject(int desc_idx) const |
|
{ |
|
return desc_idx < m_object_feature_count ? 1 : 0; |
|
} |
|
|
|
int OneWayDescriptorObject::MatchPointToPart(CvPoint pt) const |
|
{ |
|
int idx = -1; |
|
const int max_dist = 10; |
|
for(int i = 0; i < (int)m_train_features.size(); i++) |
|
{ |
|
if(norm(Point2f(pt) - m_train_features[i].pt) < max_dist) |
|
{ |
|
idx = i; |
|
break; |
|
} |
|
} |
|
|
|
return idx; |
|
} |
|
|
|
int OneWayDescriptorObject::GetDescriptorPart(int desc_idx) const |
|
{ |
|
// return MatchPointToPart(GetDescriptor(desc_idx)->GetCenter()); |
|
return desc_idx < m_object_feature_count ? m_part_id[desc_idx] : -1; |
|
} |
|
|
|
OneWayDescriptorObject::OneWayDescriptorObject(CvSize patch_size, int pose_count, const char* train_path, |
|
const char* pca_config, const char* pca_hr_config, const char* pca_desc_config, int pyr_levels) : |
|
OneWayDescriptorBase(patch_size, pose_count, train_path, pca_config, pca_hr_config, pca_desc_config, pyr_levels) |
|
{ |
|
m_part_id = 0; |
|
} |
|
|
|
OneWayDescriptorObject::OneWayDescriptorObject(CvSize patch_size, int pose_count, const String &pca_filename, |
|
const String &train_path, const String &images_list, float _scale_min, float _scale_max, float _scale_step, int pyr_levels) : |
|
OneWayDescriptorBase(patch_size, pose_count, pca_filename, train_path, images_list, _scale_min, _scale_max, _scale_step, pyr_levels) |
|
{ |
|
m_part_id = 0; |
|
} |
|
|
|
OneWayDescriptorObject::~OneWayDescriptorObject() |
|
{ |
|
if (m_part_id) |
|
delete []m_part_id; |
|
} |
|
|
|
std::vector<KeyPoint> OneWayDescriptorObject::_GetLabeledFeatures() const |
|
{ |
|
std::vector<KeyPoint> features; |
|
for(size_t i = 0; i < m_train_features.size(); i++) |
|
{ |
|
features.push_back(m_train_features[i]); |
|
} |
|
|
|
return features; |
|
} |
|
|
|
void eigenvector2image(CvMat* eigenvector, IplImage* img) |
|
{ |
|
CvRect roi = cvGetImageROI(img); |
|
if(img->depth == 32) |
|
{ |
|
for(int y = 0; y < roi.height; y++) |
|
{ |
|
for(int x = 0; x < roi.width; x++) |
|
{ |
|
float val = (float)cvmGet(eigenvector, 0, roi.width*y + x); |
|
*((float*)(img->imageData + (roi.y + y)*img->widthStep) + roi.x + x) = val; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
for(int y = 0; y < roi.height; y++) |
|
{ |
|
for(int x = 0; x < roi.width; x++) |
|
{ |
|
float val = (float)cvmGet(eigenvector, 0, roi.width*y + x); |
|
img->imageData[(roi.y + y)*img->widthStep + roi.x + x] = (unsigned char)val; |
|
} |
|
} |
|
} |
|
} |
|
|
|
void readPCAFeatures(const char* filename, CvMat** avg, CvMat** eigenvectors, const char* postfix) |
|
{ |
|
FileStorage fs = FileStorage(filename, FileStorage::READ); |
|
if (!fs.isOpened ()) |
|
{ |
|
printf("Cannot open file %s! Exiting!", filename); |
|
} |
|
|
|
readPCAFeatures (fs.root (), avg, eigenvectors, postfix); |
|
fs.release (); |
|
} |
|
|
|
void readPCAFeatures(const FileNode &fn, CvMat** avg, CvMat** eigenvectors, const char* postfix) |
|
{ |
|
String str = String ("avg") + postfix; |
|
CvMat* _avg = reinterpret_cast<CvMat*> (fn[str].readObj()); |
|
if (_avg != 0) |
|
{ |
|
*avg = cvCloneMat(_avg); |
|
cvReleaseMat(&_avg); |
|
} |
|
|
|
str = String ("eigenvectors") + postfix; |
|
CvMat* _eigenvectors = reinterpret_cast<CvMat*> (fn[str].readObj()); |
|
if (_eigenvectors != 0) |
|
{ |
|
*eigenvectors = cvCloneMat(_eigenvectors); |
|
cvReleaseMat(&_eigenvectors); |
|
} |
|
} |
|
|
|
/****************************************************************************************\ |
|
* OneWayDescriptorMatcher * |
|
\****************************************************************************************/ |
|
|
|
OneWayDescriptorMatcher::Params::Params( int _poseCount, Size _patchSize, String _pcaFilename, |
|
String _trainPath, String _trainImagesList, |
|
float _minScale, float _maxScale, float _stepScale ) : |
|
poseCount(_poseCount), patchSize(_patchSize), pcaFilename(_pcaFilename), |
|
trainPath(_trainPath), trainImagesList(_trainImagesList), |
|
minScale(_minScale), maxScale(_maxScale), stepScale(_stepScale) |
|
{} |
|
|
|
|
|
OneWayDescriptorMatcher::OneWayDescriptorMatcher( const Params& _params) |
|
{ |
|
initialize(_params); |
|
} |
|
|
|
OneWayDescriptorMatcher::~OneWayDescriptorMatcher() |
|
{} |
|
|
|
void OneWayDescriptorMatcher::initialize( const Params& _params, const Ptr<OneWayDescriptorBase>& _base ) |
|
{ |
|
clear(); |
|
|
|
if( !_base ) |
|
base = _base; |
|
|
|
params = _params; |
|
} |
|
|
|
void OneWayDescriptorMatcher::clear() |
|
{ |
|
GenericDescriptorMatcher::clear(); |
|
|
|
prevTrainCount = 0; |
|
if( base ) |
|
base->clear(); |
|
} |
|
|
|
void OneWayDescriptorMatcher::train() |
|
{ |
|
if( !base || prevTrainCount < (int)trainPointCollection.keypointCount() ) |
|
{ |
|
base.reset( |
|
new OneWayDescriptorObject( params.patchSize, params.poseCount, params.pcaFilename, |
|
params.trainPath, params.trainImagesList, params.minScale, params.maxScale, params.stepScale )); |
|
|
|
base->Allocate( (int)trainPointCollection.keypointCount() ); |
|
prevTrainCount = (int)trainPointCollection.keypointCount(); |
|
|
|
const std::vector<std::vector<KeyPoint> >& points = trainPointCollection.getKeypoints(); |
|
int count = 0; |
|
for( size_t i = 0; i < points.size(); i++ ) |
|
{ |
|
IplImage _image = trainPointCollection.getImage((int)i); |
|
for( size_t j = 0; j < points[i].size(); j++ ) |
|
base->InitializeDescriptor( count++, &_image, points[i][j], "" ); |
|
} |
|
|
|
#if defined(_KDTREE) |
|
base->ConvertDescriptorsArrayToTree(); |
|
#endif |
|
} |
|
} |
|
|
|
bool OneWayDescriptorMatcher::isMaskSupported() |
|
{ |
|
return false; |
|
} |
|
|
|
void OneWayDescriptorMatcher::knnMatchImpl( const Mat& queryImage, std::vector<KeyPoint>& queryKeypoints, |
|
std::vector<std::vector<DMatch> >& matches, int knn, |
|
const std::vector<Mat>& /*masks*/, bool /*compactResult*/ ) |
|
{ |
|
train(); |
|
|
|
CV_Assert( knn == 1 ); // knn > 1 unsupported because of bug in OneWayDescriptorBase for this case |
|
|
|
matches.resize( queryKeypoints.size() ); |
|
IplImage _qimage = queryImage; |
|
for( size_t i = 0; i < queryKeypoints.size(); i++ ) |
|
{ |
|
int descIdx = -1, poseIdx = -1; |
|
float distance; |
|
base->FindDescriptor( &_qimage, queryKeypoints[i].pt, descIdx, poseIdx, distance ); |
|
matches[i].push_back( DMatch((int)i, descIdx, distance) ); |
|
} |
|
} |
|
|
|
void OneWayDescriptorMatcher::radiusMatchImpl( const Mat& queryImage, std::vector<KeyPoint>& queryKeypoints, |
|
std::vector<std::vector<DMatch> >& matches, float maxDistance, |
|
const std::vector<Mat>& /*masks*/, bool /*compactResult*/ ) |
|
{ |
|
train(); |
|
|
|
matches.resize( queryKeypoints.size() ); |
|
IplImage _qimage = queryImage; |
|
for( size_t i = 0; i < queryKeypoints.size(); i++ ) |
|
{ |
|
int descIdx = -1, poseIdx = -1; |
|
float distance; |
|
base->FindDescriptor( &_qimage, queryKeypoints[i].pt, descIdx, poseIdx, distance ); |
|
if( distance < maxDistance ) |
|
matches[i].push_back( DMatch((int)i, descIdx, distance) ); |
|
} |
|
} |
|
|
|
void OneWayDescriptorMatcher::read( const FileNode &fn ) |
|
{ |
|
base.reset( |
|
new OneWayDescriptorObject( params.patchSize, params.poseCount, String (), String (), String (), |
|
params.minScale, params.maxScale, params.stepScale )); |
|
base->Read (fn); |
|
} |
|
|
|
void OneWayDescriptorMatcher::write( FileStorage& fs ) const |
|
{ |
|
base->Write (fs); |
|
} |
|
|
|
bool OneWayDescriptorMatcher::empty() const |
|
{ |
|
return !base || base->empty(); |
|
} |
|
|
|
Ptr<GenericDescriptorMatcher> OneWayDescriptorMatcher::clone( bool emptyTrainData ) const |
|
{ |
|
Ptr<OneWayDescriptorMatcher> matcher = makePtr<OneWayDescriptorMatcher>( params ); |
|
|
|
if( !emptyTrainData ) |
|
{ |
|
CV_Error( CV_StsNotImplemented, "deep clone functionality is not implemented, because " |
|
"OneWayDescriptorBase has not copy constructor or clone method "); |
|
|
|
//matcher->base; |
|
matcher->params = params; |
|
matcher->prevTrainCount = prevTrainCount; |
|
matcher->trainPointCollection = trainPointCollection; |
|
} |
|
return matcher; |
|
} |
|
}
|
|
|