1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
44 * one_way_descriptor.cpp
47 * Created by Victor Eruhimov on 4/19/09.
48 * Copyright 2009 Argus Corp. All rights reserved.
58 static const float pi = (float)CV_PI;
60 static void readPCAFeatures(const char* filename, CvMat** avg, CvMat** eigenvectors);
61 static void eigenvector2image(CvMat* eigenvector, IplImage* img);
63 inline CvRect resize_rect(CvRect rect, float alpha)
65 return cvRect(rect.x + cvRound((float)(0.5*(1 - alpha)*rect.width)), rect.y + cvRound((float)(0.5*(1 - alpha)*rect.height)),
66 cvRound(rect.width*alpha), cvRound(rect.height*alpha));
69 inline CvRect fit_rect_roi_fixedsize(CvRect rect, CvRect roi)
72 fit.x = MAX(fit.x, roi.x);
73 fit.y = MAX(fit.y, roi.y);
74 fit.x = MIN(fit.x, roi.x + roi.width - fit.width - 1);
75 fit.y = MIN(fit.y, roi.y + roi.height - fit.height - 1);
79 inline CvRect fit_rect_fixedsize(CvRect rect, IplImage* img)
81 CvRect roi = cvGetImageROI(img);
82 return fit_rect_roi_fixedsize(rect, roi);
86 // AffinePose: defines a parameterized affine transformation of an image patch.
87 // An image patch is rotated on angle phi (in degrees), then scaled lambda1 times
88 // along horizontal and lambda2 times along vertical direction, and then rotated again
89 // on angle (theta - phi).
99 // AffineTransformPatch: generates an affine transformed image patch.
100 // - src: source image (roi is supported)
101 // - dst: output image. ROI of dst image should be 2 times smaller than ROI of src.
102 // - pose: parameters of an affine transformation
103 void AffineTransformPatch(IplImage* src, IplImage* dst, AffinePose pose);
105 // GenerateAffineTransformFromPose: generates an affine transformation matrix from AffinePose instance
106 // - size: the size of image patch
107 // - pose: affine transformation
108 // - transform: 2x3 transformation matrix
109 void GenerateAffineTransformFromPose(Size size, AffinePose pose, CvMat* transform);
111 // Generates a random affine pose
112 AffinePose GenRandomAffinePose();
114 const static int num_mean_components = 500;
115 const static float noise_intensity = 0.15f;
118 CvMat* ConvertImageToMatrix(IplImage* patch)
120 CvRect roi = cvGetImageROI(patch);
121 CvMat* mat = cvCreateMat(1, roi.width*roi.height, CV_32FC1);
123 if(patch->depth == 32)
125 for(int y = 0; y < roi.height; y++)
127 for(int x = 0; x < roi.width; x++)
129 mat->data.fl[y*roi.width + x] = *((float*)(patch->imageData + (y + roi.y)*patch->widthStep) + x + roi.x);
133 else if(patch->depth == 8)
135 for(int y = 0; y < roi.height; y++)
137 for(int x = 0; x < roi.width; x++)
139 mat->data.fl[y*roi.width + x] = (float)(unsigned char)patch->imageData[(y + roi.y)*patch->widthStep + x + roi.x];
145 printf("Image depth %d is not supported\n", patch->depth);
152 const OneWayDescriptor* OneWayDescriptorBase::GetDescriptor(int desc_idx) const
154 return &m_descriptors[desc_idx];
157 OneWayDescriptorBase::OneWayDescriptorBase(Size patch_size, int pose_count, const char* train_path,
158 const char* pca_config, const char* pca_hr_config,
159 const char* pca_desc_config, int pyr_levels,
160 int pca_dim_high, int pca_dim_low) : m_pca_dim_high(pca_dim_high), m_pca_dim_low(pca_dim_low)
162 m_patch_size = patch_size;
163 m_pose_count = pose_count;
164 m_pyr_levels = pyr_levels;
169 m_pca_eigenvectors = 0;
171 m_pca_hr_eigenvectors = 0;
172 m_pca_descriptors = 0;
176 if(train_path == 0 || strlen(train_path) == 0)
181 char pca_config_filename[1024];
182 sprintf(pca_config_filename, "%s/%s", train_path, pca_config);
183 readPCAFeatures(pca_config_filename, &m_pca_avg, &m_pca_eigenvectors);
184 if(pca_hr_config && strlen(pca_hr_config) > 0)
186 char pca_hr_config_filename[1024];
187 sprintf(pca_hr_config_filename, "%s/%s", train_path, pca_hr_config);
188 readPCAFeatures(pca_hr_config_filename, &m_pca_hr_avg, &m_pca_hr_eigenvectors);
191 m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1];
192 if(pca_desc_config && strlen(pca_desc_config) > 0)
195 char pca_desc_config_filename[1024];
196 sprintf(pca_desc_config_filename, "%s/%s", train_path, pca_desc_config);
197 LoadPCADescriptors(pca_desc_config_filename);
201 printf("Initializing the descriptors...\n");
202 InitializePoseTransforms();
203 CreatePCADescriptors();
204 SavePCADescriptors("pca_descriptors.yml");
206 // SavePCADescriptors("./pca_descriptors.yml");
210 OneWayDescriptorBase::~OneWayDescriptorBase()
212 cvReleaseMat(&m_pca_avg);
213 cvReleaseMat(&m_pca_eigenvectors);
215 if(m_pca_hr_eigenvectors)
217 delete[] m_pca_descriptors;
218 cvReleaseMat(&m_pca_hr_avg);
219 cvReleaseMat(&m_pca_hr_eigenvectors);
223 delete []m_descriptors;
230 for(int i = 0; i < m_pose_count; i++)
232 cvReleaseMat(&m_transforms[i]);
234 delete []m_transforms;
237 void OneWayDescriptorBase::InitializePoses()
239 m_poses = new AffinePose[m_pose_count];
240 for(int i = 0; i < m_pose_count; i++)
242 m_poses[i] = GenRandomAffinePose();
246 void OneWayDescriptorBase::InitializeTransformsFromPoses()
248 m_transforms = new CvMat*[m_pose_count];
249 for(int i = 0; i < m_pose_count; i++)
251 m_transforms[i] = cvCreateMat(2, 3, CV_32FC1);
252 GenerateAffineTransformFromPose(cvSize(m_patch_size.width*2, m_patch_size.height*2), m_poses[i], m_transforms[i]);
256 void OneWayDescriptorBase::InitializePoseTransforms()
259 InitializeTransformsFromPoses();
262 void OneWayDescriptorBase::InitializeDescriptor(int desc_idx, IplImage* train_image, const char* feature_label)
264 m_descriptors[desc_idx].SetPCADimHigh(m_pca_dim_high);
265 m_descriptors[desc_idx].SetPCADimLow(m_pca_dim_low);
267 if(!m_pca_hr_eigenvectors)
269 m_descriptors[desc_idx].Initialize(m_pose_count, train_image, feature_label);
273 m_descriptors[desc_idx].InitializeFast(m_pose_count, train_image, feature_label,
274 m_pca_hr_avg, m_pca_hr_eigenvectors, m_pca_descriptors);
279 m_descriptors[desc_idx].InitializePCACoeffs(m_pca_avg, m_pca_eigenvectors);
283 void OneWayDescriptorBase::FindDescriptor(IplImage* src, Point2f pt, int& desc_idx, int& pose_idx, float& distance) const
285 CvRect roi = cvRect(cvRound(pt.x - m_patch_size.width/4),
286 cvRound(pt.y - m_patch_size.height/4),
287 m_patch_size.width/2, m_patch_size.height/2);
288 cvSetImageROI(src, roi);
290 FindDescriptor(src, desc_idx, pose_idx, distance);
292 cvResetImageROI(src);
295 void OneWayDescriptorBase::FindDescriptor(IplImage* patch, int& desc_idx, int& pose_idx, float& distance) const
298 findOneWayDescriptor(m_train_feature_count, m_descriptors, patch, desc_idx, pose_idx, distance, m_pca_avg, m_pca_eigenvectors);
300 const float scale_min = 0.8f;
301 const float scale_max = 1.2f;
302 const float scale_step = 1.1f;
304 findOneWayDescriptor(m_train_feature_count, m_descriptors, patch,
305 scale_min, scale_max, scale_step, desc_idx, pose_idx, distance, scale,
306 m_pca_avg, m_pca_eigenvectors);
310 void OneWayDescriptorBase::SetPCAHigh(CvMat* avg, CvMat* eigenvectors)
312 m_pca_hr_avg = cvCloneMat(avg);
313 m_pca_hr_eigenvectors = cvCloneMat(eigenvectors);
316 void OneWayDescriptorBase::SetPCALow(CvMat* avg, CvMat* eigenvectors)
318 m_pca_avg = cvCloneMat(avg);
319 m_pca_eigenvectors = cvCloneMat(eigenvectors);
322 void OneWayDescriptorBase::AllocatePCADescriptors()
324 m_pca_descriptors = new OneWayDescriptor[m_pca_dim_high + 1];
325 for(int i = 0; i < m_pca_dim_high + 1; i++)
327 m_pca_descriptors[i].SetPCADimHigh(m_pca_dim_high);
328 m_pca_descriptors[i].SetPCADimLow(m_pca_dim_low);
332 void OneWayDescriptorBase::CreatePCADescriptors()
334 if(m_pca_descriptors == 0)
336 AllocatePCADescriptors();
338 IplImage* frontal = cvCreateImage(m_patch_size, IPL_DEPTH_32F, 1);
340 eigenvector2image(m_pca_hr_avg, frontal);
341 m_pca_descriptors[0].SetTransforms(m_poses, m_transforms);
342 m_pca_descriptors[0].Initialize(m_pose_count, frontal, "", 0);
344 for(int j = 0; j < m_pca_dim_high; j++)
347 cvGetSubRect(m_pca_hr_eigenvectors, &eigenvector, cvRect(0, j, m_pca_hr_eigenvectors->cols, 1));
348 eigenvector2image(&eigenvector, frontal);
350 m_pca_descriptors[j + 1].SetTransforms(m_poses, m_transforms);
351 m_pca_descriptors[j + 1].Initialize(m_pose_count, frontal, "", 0);
353 printf("Created descriptor for PCA component %d\n", j);
356 cvReleaseImage(&frontal);
360 int OneWayDescriptorBase::LoadPCADescriptors(const char* filename)
362 CvMemStorage* storage = cvCreateMemStorage();
363 CvFileStorage* fs = cvOpenFileStorage(filename, storage, CV_STORAGE_READ);
366 CvFileNode* node = cvGetFileNodeByName(fs, 0, "affine poses");
369 CvMat* poses = (CvMat*)cvRead(fs, node);
370 if(poses->rows != m_pose_count)
372 printf("Inconsistency in the number of poses between the class instance and the file! Exiting...\n");
373 cvReleaseMat(&poses);
374 cvReleaseFileStorage(&fs);
375 cvReleaseMemStorage(&storage);
382 m_poses = new AffinePose[m_pose_count];
383 for(int i = 0; i < m_pose_count; i++)
385 m_poses[i].phi = (float)cvmGet(poses, i, 0);
386 m_poses[i].theta = (float)cvmGet(poses, i, 1);
387 m_poses[i].lambda1 = (float)cvmGet(poses, i, 2);
388 m_poses[i].lambda2 = (float)cvmGet(poses, i, 3);
390 cvReleaseMat(&poses);
392 // now initialize pose transforms
393 InitializeTransformsFromPoses();
396 node = cvGetFileNodeByName(fs, 0, "pca components number");
400 m_pca_dim_high = cvReadInt(node);
401 if(m_pca_descriptors)
403 delete []m_pca_descriptors;
405 AllocatePCADescriptors();
406 for(int i = 0; i < m_pca_dim_high + 1; i++)
408 m_pca_descriptors[i].Allocate(m_pose_count, m_patch_size, 1);
409 m_pca_descriptors[i].SetTransforms(m_poses, m_transforms);
411 sprintf(buf, "descriptor for pca component %d", i);
412 m_pca_descriptors[i].ReadByName(fs, 0, buf);
415 cvReleaseFileStorage(&fs);
416 cvReleaseMemStorage(&storage);
421 void OneWayDescriptorBase::SavePCADescriptors(const char* filename)
423 CvMemStorage* storage = cvCreateMemStorage();
424 CvFileStorage* fs = cvOpenFileStorage(filename, storage, CV_STORAGE_WRITE);
426 cvWriteInt(fs, "pca components number", m_pca_dim_high);
427 cvWriteComment(fs, "The first component is the average vector, so the total number of components is <pca components number> + 1", 0);
428 cvWriteInt(fs, "patch width", m_patch_size.width);
429 cvWriteInt(fs, "patch height", m_patch_size.height);
431 // pack the affine transforms into a single CvMat and write them
432 CvMat* poses = cvCreateMat(m_pose_count, 4, CV_32FC1);
433 for(int i = 0; i < m_pose_count; i++)
435 cvmSet(poses, i, 0, m_poses[i].phi);
436 cvmSet(poses, i, 1, m_poses[i].theta);
437 cvmSet(poses, i, 2, m_poses[i].lambda1);
438 cvmSet(poses, i, 3, m_poses[i].lambda2);
440 cvWrite(fs, "affine poses", poses);
441 cvReleaseMat(&poses);
443 for(int i = 0; i < m_pca_dim_high + 1; i++)
446 sprintf(buf, "descriptor for pca component %d", i);
447 m_pca_descriptors[i].Write(fs, buf);
450 cvReleaseMemStorage(&storage);
451 cvReleaseFileStorage(&fs);
454 void OneWayDescriptorBase::Allocate(int train_feature_count)
456 m_train_feature_count = train_feature_count;
457 m_descriptors = new OneWayDescriptor[m_train_feature_count];
458 for(int i = 0; i < m_train_feature_count; i++)
460 m_descriptors[i].SetPCADimHigh(m_pca_dim_high);
461 m_descriptors[i].SetPCADimLow(m_pca_dim_low);
465 void OneWayDescriptorBase::InitializeDescriptors(IplImage* train_image, const vector<KeyPoint>& features,
466 const char* feature_label, int desc_start_idx)
468 for(int i = 0; i < (int)features.size(); i++)
470 Point center = features[i].pt;
472 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);
473 cvResetImageROI(train_image);
474 roi = fit_rect_fixedsize(roi, train_image);
475 cvSetImageROI(train_image, roi);
476 // roi = cvGetImageROI(train_image);
477 if(roi.width != m_patch_size.width || roi.height != m_patch_size.height)
482 InitializeDescriptor(desc_start_idx + i, train_image, feature_label);
484 // printf("Completed feature %d\n", i);
487 cvResetImageROI(train_image);
490 void OneWayDescriptorBase::CreateDescriptorsFromImage(IplImage* src, const vector<KeyPoint>& features)
492 m_train_feature_count = (int)features.size();
494 m_descriptors = new OneWayDescriptor[m_train_feature_count];
496 InitializeDescriptors(src, features);
499 void OneWayDescriptorObject::Allocate(int train_feature_count, int object_feature_count)
501 OneWayDescriptorBase::Allocate(train_feature_count);
503 m_object_feature_count = object_feature_count;
504 m_part_id = new int[m_object_feature_count];
508 void OneWayDescriptorObject::InitializeObjectDescriptors(IplImage* train_image, const vector<KeyPoint>& features,
509 const char* feature_label, int desc_start_idx, float scale)
511 InitializeDescriptors(train_image, features, feature_label, desc_start_idx);
513 for(int i = 0; i < (int)features.size(); i++)
515 Point center = features[i].pt;
519 // remember descriptor part id
520 Point center_scaled = cvPoint(cvRound(center.x*scale), cvRound(center.y*scale));
521 m_part_id[i + desc_start_idx] = MatchPointToPart(center_scaled);
524 cvResetImageROI(train_image);
527 int OneWayDescriptorObject::IsDescriptorObject(int desc_idx) const
529 return desc_idx < m_object_feature_count ? 1 : 0;
532 int OneWayDescriptorObject::MatchPointToPart(Point pt) const
535 const float max_dist = 100.f;
536 for(int i = 0; i < (int)m_train_features.size(); i++)
538 Point2f t(m_train_features[i].pt);
539 Point2f delta(pt.x - t.x, pt.y - t.y);
540 if(delta.dot(delta) < max_dist)
550 int OneWayDescriptorObject::GetDescriptorPart(int desc_idx) const
552 // return MatchPointToPart(GetDescriptor(desc_idx)->GetCenter());
553 return m_part_id[desc_idx];
556 OneWayDescriptorObject::OneWayDescriptorObject(Size patch_size, int pose_count, const char* train_path,
557 const char* pca_config, const char* pca_hr_config, const char* pca_desc_config, int pyr_levels) :
558 OneWayDescriptorBase(patch_size, pose_count, train_path, pca_config, pca_hr_config, pca_desc_config, pyr_levels)
563 OneWayDescriptorObject::~OneWayDescriptorObject()
568 vector<KeyPoint> OneWayDescriptorObject::_GetTrainFeatures() const
570 vector<KeyPoint> features;
571 for(size_t i = 0; i < m_train_features.size(); i++)
573 features.push_back(m_train_features[i]);
579 static void eigenvector2image(CvMat* eigenvector, IplImage* img)
581 CvRect roi = cvGetImageROI(img);
584 for(int y = 0; y < roi.height; y++)
586 for(int x = 0; x < roi.width; x++)
588 float val = (float)cvmGet(eigenvector, 0, roi.width*y + x);
589 *((float*)(img->imageData + (roi.y + y)*img->widthStep) + roi.x + x) = val;
595 for(int y = 0; y < roi.height; y++)
597 for(int x = 0; x < roi.width; x++)
599 float val = (float)cvmGet(eigenvector, 0, roi.width*y + x);
600 img->imageData[(roi.y + y)*img->widthStep + roi.x + x] = (unsigned char)val;
606 static void readPCAFeatures(const char* filename, CvMat** avg, CvMat** eigenvectors)
608 CvMemStorage* storage = cvCreateMemStorage();
609 CvFileStorage* fs = cvOpenFileStorage(filename, storage, CV_STORAGE_READ);
612 printf("Cannot open file %s! Exiting!", filename);
613 cvReleaseMemStorage(&storage);
616 CvFileNode* node = cvGetFileNodeByName(fs, 0, "avg");
617 CvMat* _avg = (CvMat*)cvRead(fs, node);
618 node = cvGetFileNodeByName(fs, 0, "eigenvectors");
619 CvMat* _eigenvectors = (CvMat*)cvRead(fs, node);
621 *avg = cvCloneMat(_avg);
622 *eigenvectors = cvCloneMat(_eigenvectors);
624 cvReleaseFileStorage(&fs);
625 cvReleaseMemStorage(&storage);
628 static inline Point rect_center(CvRect rect)
630 return cvPoint(rect.x + rect.width/2, rect.y + rect.height/2);
633 void homography_transform(IplImage* frontal, IplImage* result, CvMat* homography)
635 cvWarpPerspective(frontal, result, homography);
638 AffinePose perturbate_pose(AffinePose pose, float noise)
640 // perturbate the matrix
641 float noise_mult_factor = 1 + (0.5f - float(rand())/RAND_MAX)*noise;
642 float noise_add_factor = noise_mult_factor - 1;
644 AffinePose pose_pert = pose;
645 pose_pert.phi += noise_add_factor;
646 pose_pert.theta += noise_mult_factor;
647 pose_pert.lambda1 *= noise_mult_factor;
648 pose_pert.lambda2 *= noise_mult_factor;
653 void generate_mean_patch(IplImage* frontal, IplImage* result, AffinePose pose, int pose_count, float noise)
655 IplImage* sum = cvCreateImage(cvSize(result->width, result->height), IPL_DEPTH_32F, 1);
656 IplImage* workspace = cvCloneImage(result);
657 IplImage* workspace_float = cvCloneImage(sum);
660 for(int i = 0; i < pose_count; i++)
662 AffinePose pose_pert = perturbate_pose(pose, noise);
664 AffineTransformPatch(frontal, workspace, pose_pert);
665 cvConvertScale(workspace, workspace_float);
666 cvAdd(sum, workspace_float, sum);
669 cvConvertScale(sum, result, 1.0f/pose_count);
671 cvReleaseImage(&workspace);
672 cvReleaseImage(&sum);
673 cvReleaseImage(&workspace_float);
676 void generate_mean_patch_fast(IplImage* /*frontal*/, IplImage* /*result*/, AffinePose /*pose*/,
677 CvMat* /*pca_hr_avg*/, CvMat* pca_hr_eigenvectors,
678 const OneWayDescriptor* /*pca_descriptors*/)
680 for(int i = 0; i < pca_hr_eigenvectors->cols; i++)
686 OneWayDescriptor::OneWayDescriptor()
695 OneWayDescriptor::~OneWayDescriptor()
699 for(int i = 0; i < m_pose_count; i++)
701 cvReleaseImage(&m_samples[i]);
702 cvReleaseMat(&m_pca_coeffs[i]);
705 delete []m_pca_coeffs;
709 delete []m_affine_poses;
714 void OneWayDescriptor::Allocate(int pose_count, Size size, int nChannels)
716 m_pose_count = pose_count;
717 m_samples = new IplImage* [m_pose_count];
718 m_pca_coeffs = new CvMat* [m_pose_count];
719 m_patch_size = cvSize(size.width/2, size.height/2);
723 m_affine_poses = new AffinePose[m_pose_count];
726 int length = m_pca_dim_low;//roi.width*roi.height;
727 for(int i = 0; i < m_pose_count; i++)
729 m_samples[i] = cvCreateImage(cvSize(size.width/2, size.height/2), IPL_DEPTH_32F, nChannels);
730 m_pca_coeffs[i] = cvCreateMat(1, length, CV_32FC1);
734 void cvmSet2DPoint(CvMat* matrix, int row, int col, CvPoint2D32f point)
736 cvmSet(matrix, row, col, point.x);
737 cvmSet(matrix, row, col + 1, point.y);
740 void cvmSet3DPoint(CvMat* matrix, int row, int col, CvPoint3D32f point)
742 cvmSet(matrix, row, col, point.x);
743 cvmSet(matrix, row, col + 1, point.y);
744 cvmSet(matrix, row, col + 2, point.z);
747 AffinePose GenRandomAffinePose()
749 const float scale_min = 0.8f;
750 const float scale_max = 1.2f;
752 pose.theta = float(rand())/RAND_MAX*120 - 60;
753 pose.phi = float(rand())/RAND_MAX*360;
754 pose.lambda1 = scale_min + float(rand())/RAND_MAX*(scale_max - scale_min);
755 pose.lambda2 = scale_min + float(rand())/RAND_MAX*(scale_max - scale_min);
760 void GenerateAffineTransformFromPose(Size size, AffinePose pose, CvMat* transform)
762 CvMat* temp = cvCreateMat(3, 3, CV_32FC1);
763 CvMat* final = cvCreateMat(3, 3, CV_32FC1);
764 cvmSet(temp, 2, 0, 0.0f);
765 cvmSet(temp, 2, 1, 0.0f);
766 cvmSet(temp, 2, 2, 1.0f);
769 cvGetSubRect(temp, &rotation, cvRect(0, 0, 3, 2));
771 cv2DRotationMatrix(cvPoint2D32f(size.width/2, size.height/2), pose.phi, 1.0, &rotation);
774 cvmSet(temp, 0, 0, pose.lambda1);
775 cvmSet(temp, 0, 1, 0.0f);
776 cvmSet(temp, 1, 0, 0.0f);
777 cvmSet(temp, 1, 1, pose.lambda2);
778 cvmSet(temp, 0, 2, size.width/2*(1 - pose.lambda1));
779 cvmSet(temp, 1, 2, size.height/2*(1 - pose.lambda2));
780 cvMatMul(temp, final, final);
782 cv2DRotationMatrix(cvPoint2D32f(size.width/2, size.height/2), pose.theta - pose.phi, 1.0, &rotation);
783 cvMatMul(temp, final, final);
785 cvGetSubRect(final, &rotation, cvRect(0, 0, 3, 2));
786 cvCopy(&rotation, transform);
789 cvReleaseMat(&final);
792 void AffineTransformPatch(IplImage* src, IplImage* dst, AffinePose pose)
794 CvRect src_large_roi = cvGetImageROI(src);
796 IplImage* temp = cvCreateImage(cvSize(src_large_roi.width, src_large_roi.height), IPL_DEPTH_32F, src->nChannels);
798 IplImage* temp2 = cvCloneImage(temp);
799 CvMat* rotation_phi = cvCreateMat(2, 3, CV_32FC1);
801 Size new_size = cvSize(cvRound(temp->width*pose.lambda1), cvRound(temp->height*pose.lambda2));
802 IplImage* temp3 = cvCreateImage(new_size, IPL_DEPTH_32F, src->nChannels);
804 cvConvertScale(src, temp);
805 cvResetImageROI(temp);
808 cv2DRotationMatrix(cvPoint2D32f(temp->width/2, temp->height/2), pose.phi, 1.0, rotation_phi);
809 cvWarpAffine(temp, temp2, rotation_phi);
813 cvResize(temp2, temp3);
815 cv2DRotationMatrix(cvPoint2D32f(temp3->width/2, temp3->height/2), pose.theta - pose.phi, 1.0, rotation_phi);
816 cvWarpAffine(temp3, temp, rotation_phi);
818 cvSetImageROI(temp, cvRect(temp->width/2 - src_large_roi.width/4, temp->height/2 - src_large_roi.height/4,
819 src_large_roi.width/2, src_large_roi.height/2));
820 cvConvertScale(temp, dst);
821 cvReleaseMat(&rotation_phi);
823 cvReleaseImage(&temp3);
824 cvReleaseImage(&temp2);
825 cvReleaseImage(&temp);
828 void OneWayDescriptor::GenerateSamples(int pose_count, IplImage* frontal, int norm)
832 GenerateSamplesWithTransforms(pose_count, frontal);
836 CvRect roi = cvGetImageROI(frontal);
837 IplImage* patch_8u = cvCreateImage(cvSize(roi.width/2, roi.height/2), frontal->depth, frontal->nChannels);
838 for(int i = 0; i < pose_count; i++)
842 m_affine_poses[i] = GenRandomAffinePose();
844 //AffineTransformPatch(frontal, patch_8u, m_affine_poses[i]);
845 generate_mean_patch(frontal, patch_8u, m_affine_poses[i], num_mean_components, noise_intensity);
850 float sum = (float)cvSum(patch_8u).val[0];
853 cvConvertScale(patch_8u, m_samples[i], scale);
857 cvMinMaxLoc(m_samples[i], 0, &maxval);
858 IplImage* test = cvCreateImage(cvSize(roi.width/2, roi.height/2), IPL_DEPTH_8U, 1);
859 cvConvertScale(m_samples[i], test, 255.0/maxval);
860 cvNamedWindow("1", 1);
861 cvShowImage("1", test);
865 cvReleaseImage(&patch_8u);
868 void OneWayDescriptor::GenerateSamplesFast(IplImage* frontal, CvMat* pca_hr_avg,
869 CvMat* pca_hr_eigenvectors, OneWayDescriptor* pca_descriptors)
871 CvMat* pca_coeffs = cvCreateMat(1, pca_hr_eigenvectors->cols, CV_32FC1);
873 cvMinMaxLoc(frontal, 0, &maxval);
874 CvMat* frontal_data = ConvertImageToMatrix(frontal);
876 float sum = (float)cvSum(frontal_data).val[0];
877 cvConvertScale(frontal_data, frontal_data, 1.0f/sum);
878 cvProjectPCA(frontal_data, pca_hr_avg, pca_hr_eigenvectors, pca_coeffs);
879 for(int i = 0; i < m_pose_count; i++)
881 cvSetZero(m_samples[i]);
882 for(int j = 0; j < m_pca_dim_high; j++)
884 float coeff = (float)cvmGet(pca_coeffs, 0, j);
885 IplImage* patch = pca_descriptors[j + 1].GetPatch(i);
886 cvAddWeighted(m_samples[i], 1.0, patch, coeff, 0, m_samples[i]);
889 printf("coeff%d = %f\n", j, coeff);
890 IplImage* test = cvCreateImage(cvSize(12, 12), IPL_DEPTH_8U, 1);
892 cvMinMaxLoc(patch, 0, &maxval);
893 cvConvertScale(patch, test, 255.0/maxval);
894 cvNamedWindow("1", 1);
895 cvShowImage("1", test);
900 cvAdd(pca_descriptors[0].GetPatch(i), m_samples[i], m_samples[i]);
901 float sum = (float)cvSum(m_samples[i]).val[0];
902 cvConvertScale(m_samples[i], m_samples[i], 1.0/sum);
905 IplImage* test = cvCreateImage(cvSize(12, 12), IPL_DEPTH_8U, 1);
906 /* IplImage* temp1 = cvCreateImage(cvSize(12, 12), IPL_DEPTH_32F, 1);
907 eigenvector2image(pca_hr_avg, temp1);
908 IplImage* test = cvCreateImage(cvSize(12, 12), IPL_DEPTH_8U, 1);
909 cvAdd(m_samples[i], temp1, temp1);
910 cvMinMaxLoc(temp1, 0, &maxval);
911 cvConvertScale(temp1, test, 255.0/maxval);*/
912 cvMinMaxLoc(m_samples[i], 0, &maxval);
913 cvConvertScale(m_samples[i], test, 255.0/maxval);
915 cvNamedWindow("1", 1);
916 cvShowImage("1", frontal);
917 cvNamedWindow("2", 1);
918 cvShowImage("2", test);
923 cvReleaseMat(&pca_coeffs);
924 cvReleaseMat(&frontal_data);
927 void OneWayDescriptor::SetTransforms(AffinePose* poses, CvMat** transforms)
931 delete []m_affine_poses;
934 m_affine_poses = poses;
935 m_transforms = transforms;
938 void OneWayDescriptor::Initialize(int pose_count, IplImage* frontal, const char* feature_name, int norm)
940 m_feature_name = String(feature_name);
941 CvRect roi = cvGetImageROI(frontal);
942 m_center = rect_center(roi);
944 Allocate(pose_count, cvSize(roi.width, roi.height), frontal->nChannels);
946 GenerateSamples(pose_count, frontal, norm);
949 void OneWayDescriptor::InitializeFast(int pose_count, IplImage* frontal, const char* feature_name,
950 CvMat* pca_hr_avg, CvMat* pca_hr_eigenvectors, OneWayDescriptor* pca_descriptors)
954 Initialize(pose_count, frontal, feature_name, 1);
957 m_feature_name = String(feature_name);
958 CvRect roi = cvGetImageROI(frontal);
959 m_center = rect_center(roi);
961 Allocate(pose_count, cvSize(roi.width, roi.height), frontal->nChannels);
963 GenerateSamplesFast(frontal, pca_hr_avg, pca_hr_eigenvectors, pca_descriptors);
966 void OneWayDescriptor::InitializePCACoeffs(CvMat* avg, CvMat* eigenvectors)
968 for(int i = 0; i < m_pose_count; i++)
970 ProjectPCASample(m_samples[i], avg, eigenvectors, m_pca_coeffs[i]);
974 void OneWayDescriptor::ProjectPCASample(IplImage* patch, CvMat* avg, CvMat* eigenvectors, CvMat* pca_coeffs) const
976 CvMat* patch_mat = ConvertImageToMatrix(patch);
977 // CvMat eigenvectorsr;
978 // cvGetSubRect(eigenvectors, &eigenvectorsr, cvRect(0, 0, eigenvectors->cols, pca_coeffs->cols));
979 CvMat* temp = cvCreateMat(1, eigenvectors->cols, CV_32FC1);
980 cvProjectPCA(patch_mat, avg, eigenvectors, temp);
982 cvGetSubRect(temp, &temp1, cvRect(0, 0, pca_coeffs->cols, 1));
983 cvCopy(&temp1, pca_coeffs);
986 cvReleaseMat(&patch_mat);
989 void OneWayDescriptor::EstimatePosePCA(IplImage* patch, int& pose_idx, float& distance, CvMat* avg, CvMat* eigenvectors) const
994 EstimatePose(patch, pose_idx, distance);
998 CvRect roi = cvGetImageROI(patch);
999 CvMat* pca_coeffs = cvCreateMat(1, m_pca_dim_low, CV_32FC1);
1001 IplImage* patch_32f = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_32F, 1);
1002 float sum = (float)cvSum(patch).val[0];
1003 cvConvertScale(patch, patch_32f, 1.0f/sum);
1005 ProjectPCASample(patch_32f, avg, eigenvectors, pca_coeffs);
1010 for(int i = 0; i < m_pose_count; i++)
1012 float dist = (float)cvNorm(m_pca_coeffs[i], pca_coeffs);
1020 cvReleaseMat(&pca_coeffs);
1021 cvReleaseImage(&patch_32f);
1024 void OneWayDescriptor::EstimatePose(IplImage* patch, int& pose_idx, float& distance) const
1029 CvRect roi = cvGetImageROI(patch);
1030 IplImage* patch_32f = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_32F, patch->nChannels);
1031 float sum = (float)cvSum(patch).val[0];
1032 cvConvertScale(patch, patch_32f, 1/sum);
1034 for(int i = 0; i < m_pose_count; i++)
1036 if(m_samples[i]->width != patch_32f->width || m_samples[i]->height != patch_32f->height)
1040 float dist = (float)cvNorm(m_samples[i], patch_32f);
1048 IplImage* img1 = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_8U, 1);
1049 IplImage* img2 = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_8U, 1);
1051 cvMinMaxLoc(m_samples[i], 0, &maxval);
1052 cvConvertScale(m_samples[i], img1, 255.0/maxval);
1053 cvMinMaxLoc(patch_32f, 0, &maxval);
1054 cvConvertScale(patch_32f, img2, 255.0/maxval);
1056 cvNamedWindow("1", 1);
1057 cvShowImage("1", img1);
1058 cvNamedWindow("2", 1);
1059 cvShowImage("2", img2);
1060 printf("Distance = %f\n", dist);
1065 cvReleaseImage(&patch_32f);
1068 void OneWayDescriptor::Save(const char* path)
1070 for(int i = 0; i < m_pose_count; i++)
1073 sprintf(buf, "%s/patch_%04d.jpg", path, i);
1074 IplImage* patch = cvCreateImage(cvSize(m_samples[i]->width, m_samples[i]->height), IPL_DEPTH_8U, m_samples[i]->nChannels);
1077 cvMinMaxLoc(m_samples[i], 0, &maxval);
1078 cvConvertScale(m_samples[i], patch, 255/maxval);
1080 cvSaveImage(buf, patch);
1082 cvReleaseImage(&patch);
1086 void OneWayDescriptor::Write(CvFileStorage* fs, const char* name)
1088 CvMat* mat = cvCreateMat(m_pose_count, m_samples[0]->width*m_samples[0]->height, CV_32FC1);
1090 // prepare data to write as a single matrix
1091 for(int i = 0; i < m_pose_count; i++)
1093 for(int y = 0; y < m_samples[i]->height; y++)
1095 for(int x = 0; x < m_samples[i]->width; x++)
1097 float val = *((float*)(m_samples[i]->imageData + m_samples[i]->widthStep*y) + x);
1098 cvmSet(mat, i, y*m_samples[i]->width + x, val);
1103 cvWrite(fs, name, mat);
1108 int OneWayDescriptor::ReadByName(CvFileStorage* fs, CvFileNode* parent, const char* name)
1110 CvMat* mat = (CvMat*)cvReadByName(fs, parent, name);
1117 for(int i = 0; i < m_pose_count; i++)
1119 for(int y = 0; y < m_samples[i]->height; y++)
1121 for(int x = 0; x < m_samples[i]->width; x++)
1123 float val = (float)cvmGet(mat, i, y*m_samples[i]->width + x);
1124 *((float*)(m_samples[i]->imageData + y*m_samples[i]->widthStep) + x) = val;
1133 IplImage* OneWayDescriptor::GetPatch(int index)
1135 return m_samples[index];
1138 AffinePose OneWayDescriptor::GetPose(int index) const
1140 return m_affine_poses[index];
1143 void findOneWayDescriptor(int desc_count, const OneWayDescriptor* descriptors,
1144 IplImage* patch, int& desc_idx, int& pose_idx, float& distance,
1145 CvMat* avg, CvMat* eigenvectors)
1150 for(int i = 0; i < desc_count; i++)
1153 float _distance = 0;
1156 descriptors[i].EstimatePose(patch, _pose_idx, _distance);
1158 descriptors[i].EstimatePosePCA(patch, _pose_idx, _distance, avg, eigenvectors);
1161 if(_distance < distance)
1164 pose_idx = _pose_idx;
1165 distance = _distance;
1170 void findOneWayDescriptor(int desc_count, const OneWayDescriptor* descriptors, IplImage* patch,
1171 float scale_min, float scale_max, float scale_step,
1172 int& desc_idx, int& pose_idx, float& distance, float& scale,
1173 CvMat* avg, CvMat* eigenvectors)
1175 Size patch_size = descriptors[0].GetPatchSize();
1176 IplImage* input_patch = cvCreateImage(patch_size, IPL_DEPTH_8U, 1);
1177 CvRect roi = cvGetImageROI(patch);
1178 int _desc_idx, _pose_idx;
1181 for(float cur_scale = scale_min; cur_scale < scale_max; cur_scale *= scale_step)
1183 CvRect roi_scaled = resize_rect(roi, cur_scale);
1184 cvSetImageROI(patch, roi_scaled);
1185 cvResize(patch, input_patch);
1188 if(roi.x > 244 && roi.y < 200)
1190 cvNamedWindow("1", 1);
1191 cvShowImage("1", input_patch);
1196 findOneWayDescriptor(desc_count, descriptors, input_patch, _desc_idx, _pose_idx, _distance, avg, eigenvectors);
1197 if(_distance < distance)
1199 distance = _distance;
1200 desc_idx = _desc_idx;
1201 _pose_idx = pose_idx;
1205 cvSetImageROI(patch, roi);
1207 cvReleaseImage(&input_patch);
1210 const char* OneWayDescriptor::GetFeatureName() const
1212 return m_feature_name.c_str();
1215 Point OneWayDescriptor::GetCenter() const