|
a |
|
b/src/manual_registration.cpp |
|
|
1 |
#include <Rcpp.h> |
|
|
2 |
|
|
|
3 |
// OpenCV |
|
|
4 |
#include <opencv2/opencv.hpp> |
|
|
5 |
#include "opencv2/xfeatures2d.hpp" |
|
|
6 |
#include "opencv2/features2d.hpp" |
|
|
7 |
#include "opencv2/shape/shape_transformer.hpp" |
|
|
8 |
// #include <opencv2/imgproc.hpp> |
|
|
9 |
|
|
|
10 |
// Auxiliary |
|
|
11 |
#include "auxiliary.h" |
|
|
12 |
|
|
|
13 |
// Namespaces |
|
|
14 |
using namespace Rcpp; |
|
|
15 |
using namespace std; |
|
|
16 |
using namespace cv; |
|
|
17 |
using namespace cv::xfeatures2d; |
|
|
18 |
|
|
|
19 |
// align images with TPS algorithm |
|
|
20 |
void alignImagesTPS(Mat &im1, Mat &im2, Mat &im1Reg, Rcpp::List &keypoints, |
|
|
21 |
Rcpp::NumericMatrix query_landmark, Rcpp::NumericMatrix reference_landmark) |
|
|
22 |
{ |
|
|
23 |
|
|
|
24 |
// seed |
|
|
25 |
cv::setRNGSeed(0); |
|
|
26 |
RNG rng(12345); |
|
|
27 |
Scalar value; |
|
|
28 |
|
|
|
29 |
// Get landmarks as Point2f |
|
|
30 |
std::vector<cv::Point2f> query_mat = numericMatrixToPoint2f(query_landmark); |
|
|
31 |
std::vector<cv::Point2f> ref_mat = numericMatrixToPoint2f(reference_landmark); |
|
|
32 |
|
|
|
33 |
// get matches |
|
|
34 |
std::vector<cv::DMatch> matches; |
|
|
35 |
for (unsigned int i = 0; i < ref_mat.size(); i++) |
|
|
36 |
matches.push_back(cv::DMatch(i, i, 0)); |
|
|
37 |
|
|
|
38 |
// calculate transformation |
|
|
39 |
Ptr<ThinPlateSplineShapeTransformer> tps = cv::createThinPlateSplineShapeTransformer(0); |
|
|
40 |
tps->estimateTransformation(ref_mat, query_mat, matches); |
|
|
41 |
|
|
|
42 |
// save keypoints |
|
|
43 |
keypoints[0] = point2fToNumericMatrix(ref_mat); |
|
|
44 |
keypoints[1] = point2fToNumericMatrix(query_mat); |
|
|
45 |
|
|
|
46 |
// determine extension limits for both images |
|
|
47 |
int y_max = max(im1.rows, im2.rows); |
|
|
48 |
int x_max = max(im1.cols, im2.cols); |
|
|
49 |
|
|
|
50 |
// extend images |
|
|
51 |
cv::copyMakeBorder(im1, im1, 0.0, (int) (y_max - im1.rows), 0.0, (x_max - im1.cols), cv::BORDER_CONSTANT, Scalar(0, 0, 0)); |
|
|
52 |
|
|
|
53 |
// transform image |
|
|
54 |
tps->warpImage(im1, im1Reg); |
|
|
55 |
|
|
|
56 |
// resize image |
|
|
57 |
cv::Mat im1Reg_cropped = im1Reg(cv::Range(0,im2.size().height), cv::Range(0,im2.size().width)); |
|
|
58 |
im1Reg = im1Reg_cropped.clone(); |
|
|
59 |
} |
|
|
60 |
|
|
|
61 |
// align images with affine transformation with TPS algorithm |
|
|
62 |
void alignImagesAffineTPS(Mat &im1, Mat &im2, Mat &im1Reg, Mat &h, Rcpp::List &keypoints, |
|
|
63 |
Rcpp::NumericMatrix query_landmark, Rcpp::NumericMatrix reference_landmark) |
|
|
64 |
{ |
|
|
65 |
|
|
|
66 |
// seed |
|
|
67 |
cv::setRNGSeed(0); |
|
|
68 |
RNG rng(12345); |
|
|
69 |
Scalar value; |
|
|
70 |
|
|
|
71 |
// Get landmarks as Point2f |
|
|
72 |
std::vector<cv::Point2f> query_mat = numericMatrixToPoint2f(query_landmark); |
|
|
73 |
std::vector<cv::Point2f> ref_mat = numericMatrixToPoint2f(reference_landmark); |
|
|
74 |
|
|
|
75 |
// get matches |
|
|
76 |
std::vector<cv::DMatch> matches; |
|
|
77 |
for (unsigned int i = 0; i < ref_mat.size(); i++) |
|
|
78 |
matches.push_back(cv::DMatch(i, i, 0)); |
|
|
79 |
|
|
|
80 |
// calculate homography transformation |
|
|
81 |
Mat im1Affine; |
|
|
82 |
// h = estimateAffine2D(query_mat, ref_mat); |
|
|
83 |
h = findHomography(query_mat, ref_mat); |
|
|
84 |
cv::warpPerspective(im1, im1Affine, h, im2.size()); |
|
|
85 |
// cv::warpAffine(im1, im1Affine, h, im2.size()); |
|
|
86 |
std::vector<cv::Point2f> query_reg; |
|
|
87 |
cv::perspectiveTransform(query_mat, query_reg, h); |
|
|
88 |
|
|
|
89 |
// calculate TPS transformation |
|
|
90 |
Ptr<ThinPlateSplineShapeTransformer> tps = cv::createThinPlateSplineShapeTransformer(0); |
|
|
91 |
tps->estimateTransformation(ref_mat, query_reg, matches); |
|
|
92 |
|
|
|
93 |
// save keypoints |
|
|
94 |
keypoints[0] = point2fToNumericMatrix(ref_mat); |
|
|
95 |
keypoints[1] = point2fToNumericMatrix(query_reg); |
|
|
96 |
|
|
|
97 |
// determine extension limits for both images |
|
|
98 |
int y_max = max(im1Affine.rows, im2.rows); |
|
|
99 |
int x_max = max(im1Affine.cols, im2.cols); |
|
|
100 |
|
|
|
101 |
// extend images |
|
|
102 |
cv::copyMakeBorder(im1Affine, im1Affine, 0.0, (int) (y_max - im1Affine.rows), 0.0, (x_max - im1Affine.cols), cv::BORDER_CONSTANT, Scalar(0, 0, 0)); |
|
|
103 |
|
|
|
104 |
// transform image |
|
|
105 |
tps->warpImage(im1Affine, im1Reg); |
|
|
106 |
|
|
|
107 |
// resize image |
|
|
108 |
cv::Mat im1Reg_cropped = im1Reg(cv::Range(0,im2.size().height), cv::Range(0,im2.size().width)); |
|
|
109 |
im1Reg = im1Reg_cropped.clone(); |
|
|
110 |
} |
|
|
111 |
|
|
|
112 |
// [[Rcpp::export]] |
|
|
113 |
Rcpp::List manual_registeration_rawvector(Rcpp::RawVector ref_image, Rcpp::RawVector query_image, |
|
|
114 |
Rcpp::NumericMatrix reference_landmark, Rcpp::NumericMatrix query_landmark, |
|
|
115 |
const int width1, const int height1, |
|
|
116 |
const int width2, const int height2, |
|
|
117 |
Rcpp::String method) |
|
|
118 |
{ |
|
|
119 |
// Return data |
|
|
120 |
Rcpp::List out(2); |
|
|
121 |
Rcpp::List out_trans(2); |
|
|
122 |
Rcpp::List keypoints(2); |
|
|
123 |
Mat imReg, h; |
|
|
124 |
|
|
|
125 |
// Read reference image |
|
|
126 |
cv::Mat imReference = imageToMat(ref_image, width1, height1); |
|
|
127 |
|
|
|
128 |
// Read image to be aligned |
|
|
129 |
cv::Mat im = imageToMat(query_image, width2, height2); |
|
|
130 |
|
|
|
131 |
|
|
|
132 |
// Homography + Non-rigid (TPS) |
|
|
133 |
if(strcmp(method.get_cstring(), "Homography + Non-Rigid") == 0){ |
|
|
134 |
alignImagesAffineTPS(im, imReference, imReg, |
|
|
135 |
h, keypoints, |
|
|
136 |
query_landmark, reference_landmark); |
|
|
137 |
} |
|
|
138 |
|
|
|
139 |
// Non-rigid (TPS) only |
|
|
140 |
if(strcmp(method.get_cstring(), "Non-Rigid") == 0){ |
|
|
141 |
alignImagesTPS(im, imReference, imReg, |
|
|
142 |
keypoints, |
|
|
143 |
query_landmark, reference_landmark); |
|
|
144 |
} |
|
|
145 |
|
|
|
146 |
// transformation matrix, can be either a matrix, set of keypoints or both |
|
|
147 |
out_trans[0] = matToNumericMatrix(h.clone()); |
|
|
148 |
out_trans[1] = keypoints; |
|
|
149 |
out[0] = out_trans; |
|
|
150 |
|
|
|
151 |
// registered image |
|
|
152 |
out[1] = matToImage(imReg.clone()); |
|
|
153 |
|
|
|
154 |
return out; |
|
|
155 |
} |