25 : conv1a(torch::
nn::Conv2dOptions( 1,
c1, 3).
stride(1).padding(1)),
26 conv1b(torch::
nn::Conv2dOptions(
c1,
c1, 3).
stride(1).padding(1)),
28 conv2a(torch::
nn::Conv2dOptions(
c1,
c2, 3).
stride(1).padding(1)),
29 conv2b(torch::
nn::Conv2dOptions(
c2,
c2, 3).
stride(1).padding(1)),
31 conv3a(torch::
nn::Conv2dOptions(
c2,
c3, 3).
stride(1).padding(1)),
32 conv3b(torch::
nn::Conv2dOptions(
c3,
c3, 3).
stride(1).padding(1)),
34 conv4a(torch::
nn::Conv2dOptions(
c3,
c4, 3).
stride(1).padding(1)),
35 conv4b(torch::
nn::Conv2dOptions(
c4,
c4, 3).
stride(1).padding(1)),
37 convPa(torch::
nn::Conv2dOptions(
c4,
c5, 3).
stride(1).padding(1)),
38 convPb(torch::
nn::Conv2dOptions(
c5, 65, 1).
stride(1).padding(0)),
40 convDa(torch::
nn::Conv2dOptions(
c4,
c5, 3).
stride(1).padding(1)),
41 convDb(torch::
nn::Conv2dOptions(
c5,
d1, 1).
stride(1).padding(0))
44 register_module(
"conv1a",
conv1a);
45 register_module(
"conv1b",
conv1b);
47 register_module(
"conv2a",
conv2a);
48 register_module(
"conv2b",
conv2b);
50 register_module(
"conv3a",
conv3a);
51 register_module(
"conv3b",
conv3b);
53 register_module(
"conv4a",
conv4a);
54 register_module(
"conv4b",
conv4b);
56 register_module(
"convPa",
convPa);
57 register_module(
"convPb",
convPb);
59 register_module(
"convDa",
convDa);
60 register_module(
"convDb",
convDb);
67 x = torch::max_pool2d(
x, 2, 2);
71 x = torch::max_pool2d(
x, 2, 2);
75 x = torch::max_pool2d(
x, 2, 2);
80 auto cPa = torch::relu(
convPa->forward(
x));
81 auto semi =
convPb->forward(cPa);
83 auto cDa = torch::relu(
convDa->forward(
x));
86 auto dn = torch::norm(
desc, 2, 1);
87 desc =
desc.div(torch::unsqueeze(dn, 1));
89 semi = torch::softmax(semi, 1);
90 semi = semi.slice(1, 0, 64);
91 semi = semi.permute({0, 2, 3, 1});
94 int Hc = semi.size(1);
95 int Wc = semi.size(2);
96 semi = semi.contiguous().view({-1, Hc, Wc, 8, 8});
97 semi = semi.permute({0, 1, 3, 2, 4});
98 semi = semi.contiguous().view({-1, Hc * 8, Wc * 8});
101 std::vector<torch::Tensor>
ret;
111 minDistance_(minDistance),
114 UDEBUG(
"modelPath=%s thr=%f nms=%d cuda=%d", modelPath.c_str(), threshold, nms?1:0, cuda?1:0);
115 if(modelPath.empty())
117 UERROR(
"Model's path is empty!");
123 UERROR(
"Model's path \"%s\" doesn't exist!",
path.c_str());
126 model_ = std::make_shared<SuperPoint>();
129 if(cuda && !torch::cuda::is_available())
131 UWARN(
"Cuda option is enabled but torch doesn't have cuda support on this platform, using CPU instead.");
133 cuda_ = cuda && torch::cuda::is_available();
134 torch::Device
device(
cuda_?torch::kCUDA:torch::kCPU);
149 torch::NoGradGuard no_grad_guard;
150 auto x = torch::from_blob(
img.data, {1, 1, img.rows, img.cols}, torch::kByte);
151 x =
x.to(torch::kFloat) / 255;
153 torch::Device
device(
cuda_?torch::kCUDA:torch::kCPU);
154 x =
x.set_requires_grad(
false);
157 auto scores =
out[0];
163 auto options_r1 = torch::nn::functional::MaxPool2dFuncOptions(3).stride(1).padding(1);
165 auto zeros = torch::zeros_like(scores);
166 auto max_mask = scores == torch::nn::functional::max_pool2d(scores,
options);
167 auto max_mask_r1 = scores == torch::nn::functional::max_pool2d(scores, options_r1);
168 for(
size_t i=0;
i<2;
i++)
170 auto supp_mask = torch::nn::functional::max_pool2d(max_mask.to(torch::kF32),
options) > 0;
171 auto supp_scores = torch::where(supp_mask, zeros, scores);
172 auto new_max_mask = supp_scores == torch::nn::functional::max_pool2d(supp_scores,
options);
173 max_mask = max_mask | (new_max_mask & (~supp_mask) & max_mask_r1);
175 prob_ = torch::where(max_mask, scores, zeros).squeeze(0);
179 prob_ = scores.squeeze(0);
183 kpts = torch::nonzero(kpts);
186 auto kpts_cpu = kpts.to(torch::kCPU);
187 auto prob_cpu =
prob_.to(torch::kCPU);
189 std::vector<cv::KeyPoint> keypoints;
190 for(
int i=0;
i<kpts_cpu.size(0);
i++)
192 if(
mask.empty() ||
mask.at<
unsigned char>(kpts_cpu[
i][0].item<
int>(), kpts_cpu[
i][1].item<
int>()) != 0)
194 float response = prob_cpu[kpts_cpu[
i][0]][kpts_cpu[
i][1]].item<
float>();
195 keypoints.emplace_back(cv::KeyPoint(kpts_cpu[
i][1].item<float>(), kpts_cpu[
i][0].item<float>(), 8, -1, response));
204 UERROR(
"No model is loaded!");
205 return std::vector<cv::KeyPoint>();
213 UERROR(
"SPDetector has been reset before extracting the descriptors! detect() should be called before compute().");
216 if(keypoints.empty())
222 cv::Mat kpt_mat(keypoints.size(), 2, CV_32F);
227 for (
size_t i = 0;
i < keypoints.size();
i++) {
228 kpt_mat.at<
float>(
i, 0) = (
float)keypoints[
i].pt.y -
s/2 + 0.5;
229 kpt_mat.at<
float>(
i, 1) = (
float)keypoints[
i].pt.x -
s/2 + 0.5;
232 auto fkpts = torch::from_blob(kpt_mat.data, {(long int)keypoints.size(), 2}, torch::kFloat);
237 torch::Device
device(
cuda_?torch::kCUDA:torch::kCPU);
238 auto grid = torch::zeros({1, 1, fkpts.size(0), 2}).to(
device);
239 grid[0][0].slice(1, 0, 1) = 2.0 * fkpts.slice(1, 1, 2) / (
w*
s -
s/2 - 0.5) - 1;
240 grid[0][0].slice(1, 1, 2) = 2.0 * fkpts.slice(1, 0, 1) / (
h*
s -
s/2 - 0.5) - 1;
242 auto desc = torch::grid_sampler(
desc_, grid, 0, 0,
true);
247 desc =
desc.transpose(0, 1).contiguous();
252 cv::Mat desc_mat(cv::Size(
desc.size(1),
desc.size(0)), CV_32FC1,
desc.data_ptr<
float>());
254 return desc_mat.clone();
258 UERROR(
"No model is loaded!");