|
|
|
@ -81,435 +81,7 @@ protected: |
|
|
|
|
PixelTestFn test_fn_; |
|
|
|
|
int half_ssd_size_; |
|
|
|
|
bool rotationInvariance_; |
|
|
|
|
//std::vector<int> sampling_points_;
|
|
|
|
|
void setTriplets(); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Ptr<LATCHDescriptorExtractor> LATCHDescriptorExtractor::create(int bytes, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
return makePtr<LATCHDescriptorExtractorImpl>(bytes, rotationInvariance, half_ssd_size); |
|
|
|
|
} |
|
|
|
|
void CacluateSums(int count, const std::vector<int> &points, bool rotationInvariance, const Mat &grayImage, const KeyPoint &pt, int &suma, int &sumc, float cos_theta, float sin_theta, int half_ssd_size); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests1(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 1; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests2(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 2; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests4(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 4; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests8(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 8; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests16(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 16; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests32(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 32; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests64(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 64; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CacluateSums(int count, const std::vector<int> &points, bool rotationInvariance, const Mat &grayImage, const KeyPoint &pt, int &suma, int &sumc, float cos_theta, float sin_theta, int half_ssd_size) |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
int ax = points[count]; |
|
|
|
|
int ay = points[count + 1]; |
|
|
|
|
|
|
|
|
|
int bx = points[count + 2]; |
|
|
|
|
int by = points[count + 3]; |
|
|
|
|
|
|
|
|
|
int cx = points[count + 4]; |
|
|
|
|
int cy = points[count + 5]; |
|
|
|
|
|
|
|
|
|
int ax2 = ax; |
|
|
|
|
int ay2 = ay; |
|
|
|
|
int bx2 = bx; |
|
|
|
|
int by2 = by; |
|
|
|
|
int cx2 = cx; |
|
|
|
|
int cy2 = cy; |
|
|
|
|
|
|
|
|
|
if (rotationInvariance){ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ax2 =(int)(((float)ax)*cos_theta - ((float)ay)*sin_theta); |
|
|
|
|
ay2 = (int)(((float)ax)*sin_theta + ((float)ay)*cos_theta); |
|
|
|
|
bx2 = (int)(((float)bx)*cos_theta - ((float)by)*sin_theta); |
|
|
|
|
by2 = (int)(((float)bx)*sin_theta + ((float)by)*cos_theta); |
|
|
|
|
cx2 = (int)(((float)cx)*cos_theta - ((float)cy)*sin_theta); |
|
|
|
|
cy2 = (int)(((float)cx)*sin_theta + ((float)cy)*cos_theta); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ax2 > 24) |
|
|
|
|
ax2 = 24; |
|
|
|
|
if (ax2<-24) |
|
|
|
|
ax2 = -24; |
|
|
|
|
|
|
|
|
|
if (ay2>24) |
|
|
|
|
ay2 = 24; |
|
|
|
|
if (ay2<-24) |
|
|
|
|
ay2 = -24; |
|
|
|
|
|
|
|
|
|
if (bx2>24) |
|
|
|
|
bx2 = 24; |
|
|
|
|
if (bx2<-24) |
|
|
|
|
bx2 = -24; |
|
|
|
|
|
|
|
|
|
if (by2>24) |
|
|
|
|
by2 = 24; |
|
|
|
|
if (by2<-24) |
|
|
|
|
by2 = -24; |
|
|
|
|
|
|
|
|
|
if (cx2>24) |
|
|
|
|
cx2 = 24; |
|
|
|
|
if (cx2<-24) |
|
|
|
|
cx2 = -24; |
|
|
|
|
|
|
|
|
|
if (cy2>24) |
|
|
|
|
cy2 = 24; |
|
|
|
|
if (cy2 < -24) |
|
|
|
|
cy2 = -24; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ax2 += (int)(pt.pt.x + 0.5); |
|
|
|
|
ay2 += (int)(pt.pt.y + 0.5); |
|
|
|
|
|
|
|
|
|
bx2 += (int)(pt.pt.x + 0.5); |
|
|
|
|
by2 += (int)(pt.pt.y + 0.5); |
|
|
|
|
|
|
|
|
|
cx2 += (int)(pt.pt.x + 0.5); |
|
|
|
|
cy2 += (int)(pt.pt.y + 0.5); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int K = half_ssd_size; |
|
|
|
|
for (int iy = -K; iy <= K; iy++) |
|
|
|
|
{ |
|
|
|
|
const uchar * Mi_a = grayImage.ptr<uchar>(ay2 + iy); |
|
|
|
|
const uchar * Mi_b = grayImage.ptr<uchar>(by2 + iy); |
|
|
|
|
const uchar * Mi_c = grayImage.ptr<uchar>(cy2 + iy); |
|
|
|
|
|
|
|
|
|
for (int ix = -K; ix <= K; ix++) |
|
|
|
|
{ |
|
|
|
|
double difa = Mi_a[ax2 + ix] - Mi_b[bx2 + ix]; |
|
|
|
|
suma += (int)((difa)*(difa)); |
|
|
|
|
|
|
|
|
|
double difc = Mi_c[cx2 + ix] - Mi_b[bx2 + ix]; |
|
|
|
|
sumc += (int)((difc)*(difc)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LATCHDescriptorExtractorImpl::LATCHDescriptorExtractorImpl(int bytes, bool rotationInvariance, int half_ssd_size) : |
|
|
|
|
bytes_(bytes), test_fn_(NULL), rotationInvariance_(rotationInvariance), half_ssd_size_(half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
switch (bytes) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
test_fn_ = pixelTests1; |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
test_fn_ = pixelTests2; |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
test_fn_ = pixelTests4; |
|
|
|
|
break; |
|
|
|
|
case 8: |
|
|
|
|
test_fn_ = pixelTests8; |
|
|
|
|
break; |
|
|
|
|
case 16: |
|
|
|
|
test_fn_ = pixelTests16; |
|
|
|
|
break; |
|
|
|
|
case 32: |
|
|
|
|
test_fn_ = pixelTests32; |
|
|
|
|
break; |
|
|
|
|
case 64: |
|
|
|
|
test_fn_ = pixelTests64; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
CV_Error(Error::StsBadArg, "descriptorSize must be 1,2, 4, 8, 16, 32, or 64"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setTriplets(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LATCHDescriptorExtractorImpl::descriptorSize() const |
|
|
|
|
{ |
|
|
|
|
return bytes_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LATCHDescriptorExtractorImpl::descriptorType() const |
|
|
|
|
{ |
|
|
|
|
return CV_8UC1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LATCHDescriptorExtractorImpl::defaultNorm() const |
|
|
|
|
{ |
|
|
|
|
return NORM_HAMMING; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LATCHDescriptorExtractorImpl::read(const FileNode& fn) |
|
|
|
|
{ |
|
|
|
|
int dSize = fn["descriptorSize"]; |
|
|
|
|
switch (dSize) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
test_fn_ = pixelTests1; |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
test_fn_ = pixelTests2; |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
test_fn_ = pixelTests4; |
|
|
|
|
break; |
|
|
|
|
case 8: |
|
|
|
|
test_fn_ = pixelTests8; |
|
|
|
|
break; |
|
|
|
|
case 16: |
|
|
|
|
test_fn_ = pixelTests16; |
|
|
|
|
break; |
|
|
|
|
case 32: |
|
|
|
|
test_fn_ = pixelTests32; |
|
|
|
|
break; |
|
|
|
|
case 64: |
|
|
|
|
test_fn_ = pixelTests64; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
CV_Error(Error::StsBadArg, "descriptorSize must be 1,2, 4, 8, 16, 32, or 64"); |
|
|
|
|
} |
|
|
|
|
bytes_ = dSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LATCHDescriptorExtractorImpl::write(FileStorage& fs) const |
|
|
|
|
{ |
|
|
|
|
fs << "descriptorSize" << bytes_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LATCHDescriptorExtractorImpl::compute(InputArray image, |
|
|
|
|
std::vector<KeyPoint>& keypoints, |
|
|
|
|
OutputArray descriptors) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
Mat grayImage; |
|
|
|
|
GaussianBlur(image, grayImage, cv::Size(3, 3), 2, 2); |
|
|
|
|
|
|
|
|
|
if (image.type() != CV_8U) cvtColor(image, grayImage, COLOR_BGR2GRAY); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Remove keypoints very close to the border
|
|
|
|
|
KeyPointsFilter::runByImageBorder(keypoints, image.size(), PATCH_SIZE / 2 + half_ssd_size_); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
descriptors.create((int)keypoints.size(), bytes_, CV_8U); |
|
|
|
|
|
|
|
|
|
test_fn_(grayImage, keypoints, descriptors, sampling_points_, rotationInvariance_, half_ssd_size_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static std::vector<int> sampling_points_ { 13, -6, 19, 19, 23, -4, |
|
|
|
|
std::vector<int> sampling_points_ { 13, -6, 19, 19, 23, -4, |
|
|
|
|
4, 16, 24, -11, 4, -21, |
|
|
|
|
22, -14, -2, -20, 23, 5, |
|
|
|
|
17, -10, 2, 10, 14, -18, |
|
|
|
@ -1022,8 +594,432 @@ static std::vector<int> sampling_points_ { 13, -6, 19, 19, 23, -4, |
|
|
|
|
-19, 20, -11, -2, -20, -24, |
|
|
|
|
11, -12, 5, -21, -2, -13 |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
Ptr<LATCHDescriptorExtractor> LATCHDescriptorExtractor::create(int bytes, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
return makePtr<LATCHDescriptorExtractorImpl>(bytes, rotationInvariance, half_ssd_size); |
|
|
|
|
} |
|
|
|
|
void CacluateSums(int count, const std::vector<int> &points, bool rotationInvariance, const Mat &grayImage, const KeyPoint &pt, int &suma, int &sumc, float cos_theta, float sin_theta, int half_ssd_size); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests1(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 1; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests2(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 2; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests4(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 4; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests8(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 8; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests16(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 16; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests32(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 32; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pixelTests64(const Mat& grayImage, const std::vector<KeyPoint>& keypoints, OutputArray& _descriptors, const std::vector<int> &points, bool rotationInvariance, int half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
Mat descriptors = _descriptors.getMat(); |
|
|
|
|
for (int i = 0; i < (int)keypoints.size(); ++i) |
|
|
|
|
{ |
|
|
|
|
uchar* desc = descriptors.ptr(i); |
|
|
|
|
const KeyPoint& pt = keypoints[i]; |
|
|
|
|
int count = 0; |
|
|
|
|
|
|
|
|
|
//handling keypoint orientation
|
|
|
|
|
float angle = pt.angle; |
|
|
|
|
angle *= (float)(CV_PI / 180.f); |
|
|
|
|
float cos_theta = cos(angle); |
|
|
|
|
float sin_theta = sin(angle); |
|
|
|
|
for (int ix = 0; ix < 64; ix++){ |
|
|
|
|
desc[ix] = 0; |
|
|
|
|
for (int j = 7; j >= 0; j--){ |
|
|
|
|
|
|
|
|
|
int suma = 0; |
|
|
|
|
int sumc = 0; |
|
|
|
|
|
|
|
|
|
CacluateSums(count, points, rotationInvariance, grayImage, pt, suma, sumc, cos_theta, sin_theta, half_ssd_size); |
|
|
|
|
desc[ix] += (uchar)((suma < sumc) << j); |
|
|
|
|
|
|
|
|
|
count += 6; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void CacluateSums(int count, const std::vector<int> &points, bool rotationInvariance, const Mat &grayImage, const KeyPoint &pt, int &suma, int &sumc, float cos_theta, float sin_theta, int half_ssd_size) |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
int ax = points[count]; |
|
|
|
|
int ay = points[count + 1]; |
|
|
|
|
|
|
|
|
|
int bx = points[count + 2]; |
|
|
|
|
int by = points[count + 3]; |
|
|
|
|
|
|
|
|
|
int cx = points[count + 4]; |
|
|
|
|
int cy = points[count + 5]; |
|
|
|
|
|
|
|
|
|
int ax2 = ax; |
|
|
|
|
int ay2 = ay; |
|
|
|
|
int bx2 = bx; |
|
|
|
|
int by2 = by; |
|
|
|
|
int cx2 = cx; |
|
|
|
|
int cy2 = cy; |
|
|
|
|
|
|
|
|
|
if (rotationInvariance){ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ax2 =(int)(((float)ax)*cos_theta - ((float)ay)*sin_theta); |
|
|
|
|
ay2 = (int)(((float)ax)*sin_theta + ((float)ay)*cos_theta); |
|
|
|
|
bx2 = (int)(((float)bx)*cos_theta - ((float)by)*sin_theta); |
|
|
|
|
by2 = (int)(((float)bx)*sin_theta + ((float)by)*cos_theta); |
|
|
|
|
cx2 = (int)(((float)cx)*cos_theta - ((float)cy)*sin_theta); |
|
|
|
|
cy2 = (int)(((float)cx)*sin_theta + ((float)cy)*cos_theta); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ax2 > 24) |
|
|
|
|
ax2 = 24; |
|
|
|
|
if (ax2<-24) |
|
|
|
|
ax2 = -24; |
|
|
|
|
|
|
|
|
|
if (ay2>24) |
|
|
|
|
ay2 = 24; |
|
|
|
|
if (ay2<-24) |
|
|
|
|
ay2 = -24; |
|
|
|
|
|
|
|
|
|
if (bx2>24) |
|
|
|
|
bx2 = 24; |
|
|
|
|
if (bx2<-24) |
|
|
|
|
bx2 = -24; |
|
|
|
|
|
|
|
|
|
if (by2>24) |
|
|
|
|
by2 = 24; |
|
|
|
|
if (by2<-24) |
|
|
|
|
by2 = -24; |
|
|
|
|
|
|
|
|
|
if (cx2>24) |
|
|
|
|
cx2 = 24; |
|
|
|
|
if (cx2<-24) |
|
|
|
|
cx2 = -24; |
|
|
|
|
|
|
|
|
|
if (cy2>24) |
|
|
|
|
cy2 = 24; |
|
|
|
|
if (cy2 < -24) |
|
|
|
|
cy2 = -24; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ax2 += (int)(pt.pt.x + 0.5); |
|
|
|
|
ay2 += (int)(pt.pt.y + 0.5); |
|
|
|
|
|
|
|
|
|
bx2 += (int)(pt.pt.x + 0.5); |
|
|
|
|
by2 += (int)(pt.pt.y + 0.5); |
|
|
|
|
|
|
|
|
|
cx2 += (int)(pt.pt.x + 0.5); |
|
|
|
|
cy2 += (int)(pt.pt.y + 0.5); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int K = half_ssd_size; |
|
|
|
|
for (int iy = -K; iy <= K; iy++) |
|
|
|
|
{ |
|
|
|
|
const uchar * Mi_a = grayImage.ptr<uchar>(ay2 + iy); |
|
|
|
|
const uchar * Mi_b = grayImage.ptr<uchar>(by2 + iy); |
|
|
|
|
const uchar * Mi_c = grayImage.ptr<uchar>(cy2 + iy); |
|
|
|
|
|
|
|
|
|
for (int ix = -K; ix <= K; ix++) |
|
|
|
|
{ |
|
|
|
|
double difa = Mi_a[ax2 + ix] - Mi_b[bx2 + ix]; |
|
|
|
|
suma += (int)((difa)*(difa)); |
|
|
|
|
|
|
|
|
|
double difc = Mi_c[cx2 + ix] - Mi_b[bx2 + ix]; |
|
|
|
|
sumc += (int)((difc)*(difc)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LATCHDescriptorExtractorImpl::LATCHDescriptorExtractorImpl(int bytes, bool rotationInvariance, int half_ssd_size) : |
|
|
|
|
bytes_(bytes), test_fn_(NULL), rotationInvariance_(rotationInvariance), half_ssd_size_(half_ssd_size) |
|
|
|
|
{ |
|
|
|
|
switch (bytes) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
test_fn_ = pixelTests1; |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
test_fn_ = pixelTests2; |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
test_fn_ = pixelTests4; |
|
|
|
|
break; |
|
|
|
|
case 8: |
|
|
|
|
test_fn_ = pixelTests8; |
|
|
|
|
break; |
|
|
|
|
case 16: |
|
|
|
|
test_fn_ = pixelTests16; |
|
|
|
|
break; |
|
|
|
|
case 32: |
|
|
|
|
test_fn_ = pixelTests32; |
|
|
|
|
break; |
|
|
|
|
case 64: |
|
|
|
|
test_fn_ = pixelTests64; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
CV_Error(Error::StsBadArg, "descriptorSize must be 1,2, 4, 8, 16, 32, or 64"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setTriplets(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LATCHDescriptorExtractorImpl::descriptorSize() const |
|
|
|
|
{ |
|
|
|
|
return bytes_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LATCHDescriptorExtractorImpl::descriptorType() const |
|
|
|
|
{ |
|
|
|
|
return CV_8UC1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int LATCHDescriptorExtractorImpl::defaultNorm() const |
|
|
|
|
{ |
|
|
|
|
return NORM_HAMMING; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LATCHDescriptorExtractorImpl::read(const FileNode& fn) |
|
|
|
|
{ |
|
|
|
|
int dSize = fn["descriptorSize"]; |
|
|
|
|
switch (dSize) |
|
|
|
|
{ |
|
|
|
|
case 1: |
|
|
|
|
test_fn_ = pixelTests1; |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
test_fn_ = pixelTests2; |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
test_fn_ = pixelTests4; |
|
|
|
|
break; |
|
|
|
|
case 8: |
|
|
|
|
test_fn_ = pixelTests8; |
|
|
|
|
break; |
|
|
|
|
case 16: |
|
|
|
|
test_fn_ = pixelTests16; |
|
|
|
|
break; |
|
|
|
|
case 32: |
|
|
|
|
test_fn_ = pixelTests32; |
|
|
|
|
break; |
|
|
|
|
case 64: |
|
|
|
|
test_fn_ = pixelTests64; |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
CV_Error(Error::StsBadArg, "descriptorSize must be 1,2, 4, 8, 16, 32, or 64"); |
|
|
|
|
} |
|
|
|
|
bytes_ = dSize; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LATCHDescriptorExtractorImpl::write(FileStorage& fs) const |
|
|
|
|
{ |
|
|
|
|
fs << "descriptorSize" << bytes_; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void LATCHDescriptorExtractorImpl::compute(InputArray image, |
|
|
|
|
std::vector<KeyPoint>& keypoints, |
|
|
|
|
OutputArray descriptors) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
Mat grayImage; |
|
|
|
|
GaussianBlur(image, grayImage, cv::Size(3, 3), 2, 2); |
|
|
|
|
|
|
|
|
|
if (image.type() != CV_8U) cvtColor(image, grayImage, COLOR_BGR2GRAY); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Remove keypoints very close to the border
|
|
|
|
|
KeyPointsFilter::runByImageBorder(keypoints, image.size(), PATCH_SIZE / 2 + half_ssd_size_); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
descriptors.create((int)keypoints.size(), bytes_, CV_8U); |
|
|
|
|
|
|
|
|
|
test_fn_(grayImage, keypoints, descriptors, sampling_points_, rotationInvariance_, half_ssd_size_); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
} // namespace cv
|
|
|
|
|