Skip to content

Instantly share code, notes, and snippets.

@ethanrublee
Created May 15, 2016 07:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ethanrublee/50d47a18b378a7906b6f186e664fd6e9 to your computer and use it in GitHub Desktop.
Save ethanrublee/50d47a18b378a7906b6f186e664fd6e9 to your computer and use it in GitHub Desktop.
Basic implementation of the BRIEF descriptor.
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// Author: Ethan Rublee <ethan.rublee@gmail.com>
// Date: May 15th, 2016
//
// Description: Basic implementation of the BRIEF descriptor, and
// demonstration of matching features in the current frame to the
// previous frame from a cv::VideoCapture device.
#include <array>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/imgproc.hpp>
// Image must be of type CV_8UC1
// Point must not be within 33 pixels of the boarder of the image.
// Descriptor must 1 row, and <= 64 cols, and be CV_8UC1
inline void BRIEFDescriptor(const cv::Mat& image, cv::Point point,
cv::Mat desc) {
// import numpy
// x=numpy.random.normal(loc=0.0, scale=10.0, size=(512,4)).round()
// l=set([(r[0],r[1],r[2],r[3]) for r in x])
// assert len(l) == 512
// print 'static const int kOffsets[512][4] = {'
// print ','.join(["{%d, %d, %d, %d}"%r for r in l])
// print '};'
static const int kOffsets[512][4] = {{0, 9, 6, -19},
{-7, -18, -5, 9},
{-8, 6, -15, 1},
{-6, 17, 4, 13},
{0, -9, -13, 1},
{-12, 7, -18, -3},
{2, -15, 4, -10},
{-2, 13, -2, 1},
{-4, 8, 10, 5},
{12, 2, 6, 12},
{5, 7, 2, 3},
{-6, -3, -16, -9},
{16, -8, -8, 4},
{-3, -7, -27, -19},
{0, 2, 5, 8},
{-10, -3, 2, 3},
{-16, 15, -10, 3},
{9, -17, -7, -6},
{9, 3, -8, -1},
{4, -16, 6, -2},
{2, 10, -8, -2},
{5, 14, -9, -6},
{10, 10, -3, 9},
{4, -10, -6, -1},
{-15, -15, 7, -4},
{-9, 12, -10, 8},
{5, -11, 0, 0},
{-4, -19, -10, 2},
{7, 0, 6, 8},
{-12, 14, -15, -5},
{8, 2, -2, 2},
{-18, 13, 7, -5},
{-1, -23, -13, -16},
{19, -7, -2, -4},
{-5, 13, -16, 4},
{-16, 2, 2, 1},
{11, -21, -24, 17},
{3, 12, -13, -12},
{3, 5, -14, -2},
{8, 4, -9, 9},
{15, -12, -8, 9},
{-1, -2, 8, 7},
{-6, -13, 5, 6},
{1, 20, 28, -2},
{14, -3, 11, 3},
{1, 6, -16, 10},
{5, 3, 18, -10},
{18, -7, 2, 5},
{4, 2, -2, 0},
{2, 1, 1, -2},
{0, 10, -3, -1},
{6, -17, -13, 18},
{1, -4, -2, 6},
{-8, -2, 17, -7},
{18, 4, -8, 11},
{4, -9, 6, 19},
{6, 6, -5, 10},
{-2, -2, -11, -2},
{0, 2, 3, 5},
{16, -6, 13, -26},
{-1, -7, 7, 0},
{-3, 5, 13, -10},
{1, -5, -22, 6},
{-14, -6, -12, -14},
{-5, -8, 11, -5},
{3, 3, 23, 6},
{-15, 2, -10, -10},
{-11, -13, 1, 0},
{-6, 14, -2, 12},
{1, -7, -2, 5},
{-4, -17, 8, 10},
{-2, 3, 4, 7},
{13, -13, -11, 2},
{10, -3, 13, 2},
{-2, -7, -4, 13},
{-6, 6, -4, -1},
{4, 12, 11, -1},
{-12, -5, -8, 12},
{0, -1, 17, 1},
{3, 1, 19, 3},
{6, -13, -4, -6},
{5, 16, -24, 5},
{2, 9, -1, 7},
{5, -8, -2, 7},
{-10, 13, 4, 6},
{-6, 17, -12, 3},
{-14, 17, 10, 10},
{-20, 4, 7, 2},
{-10, -4, -5, -4},
{0, -11, -19, -15},
{-9, 4, 17, -16},
{1, -3, 13, 0},
{-2, 11, -10, -9},
{-14, 2, -14, -3},
{6, -6, 7, 1},
{-27, 8, -13, 8},
{4, 4, 0, 11},
{0, -4, 17, 6},
{19, -6, -4, 7},
{9, 5, 2, -9},
{-7, -7, 14, -1},
{5, -5, -8, 2},
{-2, -25, -18, 13},
{0, 12, 4, -2},
{-4, 0, 17, 8},
{-10, 0, 7, 29},
{6, 13, -7, -8},
{13, 15, 5, 2},
{2, 4, 10, 10},
{-14, 3, 13, 8},
{4, 23, 9, -3},
{3, 13, -16, -1},
{-6, 17, -6, 12},
{2, 3, -3, 19},
{7, 9, 12, -21},
{4, 1, 0, -2},
{0, 3, -4, -3},
{-5, 2, -7, 7},
{-14, 14, -6, 25},
{-9, -11, 4, 5},
{15, -4, 3, 1},
{-8, 15, -17, 2},
{16, 7, -7, 5},
{2, -22, 3, -9},
{-6, -12, -2, -10},
{9, -14, 14, 2},
{0, -7, -2, 12},
{13, 1, -11, -7},
{-8, 16, -12, 0},
{7, 10, -1, -2},
{-10, -8, 4, 28},
{6, 11, -2, -14},
{-11, -9, 11, 7},
{8, -9, 10, 4},
{-1, 20, 3, -11},
{-13, -13, 6, -3},
{-2, -18, -13, -3},
{-8, 9, -3, -8},
{-2, -4, -11, -9},
{6, 25, 16, -8},
{-17, -1, 4, 5},
{-6, 1, 8, 7},
{7, -16, 17, 18},
{-10, 11, 21, 1},
{8, -4, -6, -10},
{12, 4, -1, -4},
{-2, -8, 12, 0},
{1, -8, -4, 2},
{2, -7, 1, -2},
{-5, 22, 4, 9},
{9, -6, -9, 12},
{0, 14, 5, -11},
{-9, -3, -10, -1},
{-15, -5, 1, 10},
{7, 9, 2, 18},
{-3, -13, -2, 9},
{11, 4, 8, -5},
{21, 11, 8, -11},
{-2, -5, -17, -8},
{9, 2, -6, 2},
{-11, -7, -5, -6},
{17, -12, 4, 3},
{-3, -5, 9, -10},
{6, -9, 23, -2},
{-6, -3, 20, -23},
{-25, -21, -1, 7},
{-6, -8, -13, 0},
{-3, -4, -7, -9},
{-4, 9, 1, 6},
{5, -14, -2, 4},
{2, 3, -10, -10},
{0, 5, -11, -8},
{1, 1, -1, 3},
{-7, -16, -13, 3},
{4, 6, 0, 21},
{-13, 2, 20, -7},
{1, 13, 2, 4},
{-3, -6, 17, 3},
{5, -17, -24, -11},
{5, 12, -8, 4},
{4, -1, 0, 3},
{6, 14, -7, -3},
{-1, -4, -9, -2},
{9, 1, 11, 9},
{-10, -9, 0, 7},
{-2, -3, 19, -6},
{-9, 6, 4, 2},
{21, -2, 14, 11},
{13, 14, -11, -14},
{10, 10, -18, 15},
{8, -19, 10, -6},
{16, 14, 17, 4},
{-2, 1, 10, 8},
{2, 5, -3, 12},
{14, -6, -15, -4},
{-11, 17, 5, 9},
{2, -9, -7, -4},
{-16, 9, 1, -3},
{-4, -12, 17, 7},
{11, -2, 3, -6},
{-10, -1, 18, -6},
{-20, -7, 12, -2},
{-3, 1, -18, -2},
{5, -4, -3, 13},
{-6, -8, 2, 17},
{-5, -5, -13, 17},
{3, 2, 0, -4},
{9, -3, -11, 11},
{-9, -14, 23, 2},
{2, -10, -14, 15},
{-2, -1, 0, 11},
{-8, -24, -9, 2},
{17, -1, -7, 3},
{4, 10, -6, 9},
{10, 8, 21, 6},
{13, -18, -3, -4},
{0, 23, -7, 0},
{9, -3, 12, 11},
{13, 7, -15, 3},
{11, 3, 14, -6},
{-8, 12, -4, -4},
{-2, 6, -1, -15},
{-6, 17, 10, 19},
{7, -11, 9, 2},
{-1, 12, -6, -6},
{14, 4, -9, -1},
{-2, -1, -17, 6},
{-4, -8, -7, 1},
{-6, 4, 1, 8},
{0, -2, 0, -13},
{-7, 12, -3, -1},
{3, -4, 7, 0},
{11, -10, -2, -3},
{18, -10, 2, -4},
{-17, -5, 8, -14},
{-1, -1, -7, -7},
{8, -25, -12, 3},
{-15, 11, -9, 2},
{-21, 25, -9, -6},
{3, 13, -1, -2},
{9, -2, -5, -1},
{-7, -13, 17, 8},
{4, 14, 1, 5},
{-6, -3, 0, 15},
{-11, 13, 7, 16},
{-5, -2, -7, 1},
{3, -2, 0, 18},
{10, 13, -4, -8},
{-12, -23, -5, 4},
{-2, 0, -6, 3},
{-10, 0, -1, 4},
{-5, 1, -3, -11},
{-11, -20, 1, 11},
{-2, 14, 15, -9},
{5, -6, 1, 0},
{1, 2, -9, -11},
{12, -4, -6, 6},
{3, -9, -2, 8},
{-17, -1, -9, -1},
{-3, 2, 1, 9},
{19, -6, 7, -16},
{10, 1, 18, -5},
{1, -6, 5, 2},
{-3, 5, -9, 0},
{-14, 4, -13, 9},
{2, -11, 1, 0},
{14, -12, 12, 11},
{-5, -1, -2, 2},
{4, -7, -10, 12},
{-2, -13, -2, -4},
{-10, -15, 13, 10},
{-1, -9, 2, 7},
{0, 5, 2, 5},
{7, -6, -11, 1},
{-2, 9, 6, -14},
{6, 7, 15, -7},
{9, 10, -11, 1},
{11, 17, 13, -11},
{1, -3, -22, 11},
{-12, 6, -14, 5},
{-4, 8, -1, 24},
{2, 3, 6, 7},
{-11, 1, -12, 7},
{0, 5, -4, 4},
{-17, 12, -6, -3},
{-7, 6, -8, 1},
{-7, -5, 5, 11},
{-8, -3, 15, 1},
{-2, 9, -4, -14},
{7, -19, 1, 11},
{0, -1, -14, -7},
{4, 12, -8, 9},
{5, -15, -11, 2},
{-14, 2, 2, -8},
{-6, -9, 6, -6},
{13, -3, -5, 12},
{5, -14, -2, -24},
{-8, 13, -8, -3},
{1, 10, 2, -3},
{-17, 1, -23, -12},
{-25, -1, 12, 17},
{-6, 1, -5, -4},
{-13, -5, -2, 10},
{13, 17, 4, -15},
{-2, -7, 2, 4},
{0, -9, 0, 8},
{0, 3, -14, 9},
{-4, 8, 8, 3},
{-5, -11, -6, 3},
{-4, -5, -6, 2},
{-18, 9, 0, 1},
{15, 1, 22, -16},
{0, -3, -6, -5},
{9, 15, 5, -6},
{17, -11, 3, 4},
{1, 7, 9, 22},
{-8, -11, 6, -5},
{5, 17, -8, 5},
{-4, -13, -9, 2},
{-2, 27, 17, -1},
{-9, -10, 8, -7},
{3, 9, 12, -9},
{-15, -7, -12, 17},
{5, 19, 1, -11},
{-2, -19, -5, 20},
{-11, 6, 7, 9},
{-7, -11, 2, -22},
{4, 11, 3, 1},
{3, -9, 16, 5},
{-18, 3, -6, 10},
{-3, -15, 6, 6},
{-7, -11, -18, 0},
{1, 11, -3, -5},
{-6, 8, -15, -7},
{-7, -4, 1, 7},
{2, -8, -8, -2},
{-8, 15, 7, -11},
{4, -3, 4, -14},
{2, -10, 11, 7},
{-2, -5, 13, -6},
{7, -6, -18, -7},
{-10, 15, 7, 16},
{3, 8, 2, -2},
{-11, 13, 0, 8},
{-2, -6, 9, 10},
{-4, 10, 2, 4},
{3, -3, -17, -23},
{-15, 6, 8, -19},
{9, -5, 2, -12},
{-12, -2, 1, 9},
{2, -5, -10, 17},
{12, -10, 12, 5},
{2, 0, 12, -16},
{1, -2, -7, 13},
{8, -9, -15, 1},
{18, 7, -5, -9},
{30, 8, -19, -17},
{2, 4, 5, -6},
{12, -12, 4, 12},
{-3, -16, 7, -7},
{-3, -8, 8, 11},
{14, 16, 3, -1},
{-8, 5, 10, 12},
{0, -13, 13, -8},
{-6, -1, 9, -3},
{6, 0, -22, -15},
{-1, -4, -8, -5},
{-9, -10, 10, 12},
{-10, -29, -7, -15},
{1, 4, -14, 1},
{-4, 25, 19, 5},
{2, -3, -1, -10},
{4, 13, 3, 21},
{9, 3, 12, -16},
{4, 10, 6, -14},
{11, -15, 17, 4},
{2, 7, 12, 9},
{-2, -6, 14, 8},
{-10, 17, -3, 7},
{6, -1, -3, -15},
{9, 0, -4, 31},
{10, -12, 18, 6},
{2, -3, -9, -23},
{19, -5, 1, -13},
{-5, -7, -6, 1},
{5, -11, 1, -3},
{-22, 12, 18, 10},
{1, 4, 0, -6},
{-3, 27, 21, 17},
{-17, -5, -16, 5},
{9, 19, 10, 3},
{-5, 2, -16, -7},
{14, -12, 10, 11},
{12, 7, 9, 3},
{-6, -11, -26, -1},
{-6, 24, 16, -5},
{2, 16, 11, -24},
{-16, -3, -23, -3},
{1, -4, 0, 8},
{-11, 7, -8, -11},
{7, 6, 7, -4},
{13, 11, -1, -11},
{-11, 7, 23, 5},
{-6, -26, -8, 2},
{-1, 0, 16, -10},
{10, 8, 3, 13},
{4, -16, -8, -1},
{3, 1, 3, -23},
{11, 0, -5, -7},
{17, -2, 12, -2},
{4, 1, -9, 13},
{-1, 8, -11, -1},
{-4, -15, 13, -9},
{-6, -10, 2, -12},
{-12, 1, -8, 12},
{-5, 2, -2, -5},
{23, -8, 2, -13},
{5, 5, -6, -1},
{4, 3, -5, 1},
{5, -25, -7, -17},
{-17, -13, 15, 4},
{-16, -14, -4, 19},
{2, 5, 11, 1},
{7, 1, -1, -2},
{-8, -17, 0, 1},
{12, -13, 11, 8},
{1, -12, 0, 9},
{-13, 12, 5, 14},
{1, -9, 7, 6},
{-4, 12, -10, 0},
{4, -8, 3, 0},
{-3, 1, 20, 8},
{1, 12, 6, -13},
{-15, -7, -14, -6},
{-6, 3, -17, 15},
{2, 11, 3, -6},
{9, -8, -1, -10},
{-7, 5, 7, 3},
{-3, 0, 3, -3},
{22, -1, 5, 5},
{-12, 1, -2, -7},
{6, 0, -16, -9},
{-12, 4, -11, -10},
{-13, 8, -9, -21},
{20, 1, -14, 9},
{-3, -8, 0, -11},
{1, -8, -1, 5},
{15, -10, 3, -13},
{-2, 3, -8, -12},
{2, -2, 5, -7},
{5, 1, 16, -16},
{13, -2, -3, 0},
{-4, -15, 0, -13},
{-3, -7, 7, -16},
{10, -13, -15, -10},
{-11, 11, -4, -2},
{5, 6, 1, 5},
{-1, -6, -15, 4},
{7, 12, 4, -1},
{2, 1, -4, 1},
{11, 11, 1, -18},
{-13, 11, -9, -9},
{10, -13, 26, 15},
{-2, -14, -5, -10},
{1, -4, -13, -12},
{-1, -14, 3, 1},
{-27, 8, 0, 18},
{-7, 2, 18, -8},
{-2, -5, 15, -7},
{13, 7, 1, 6},
{2, 9, -4, 0},
{-11, 12, 0, -12},
{-4, 1, 16, -16},
{13, -1, -2, 9},
{5, 16, -12, 0},
{-10, -9, -4, -19},
{4, 5, -1, -19},
{-4, -13, 21, 14},
{-12, 11, 7, -2},
{6, -7, 11, -6},
{3, 3, 2, -2},
{-1, 7, 10, -10},
{-15, 3, 11, 4},
{-8, 10, 8, -19},
{6, 2, -11, -4},
{18, -7, 15, -5},
{16, 13, 12, 3},
{32, -4, -3, -9},
{5, 1, -19, 3},
{-9, -7, 17, 8},
{17, 1, -2, 5},
{-4, -12, 14, 6},
{1, 22, 1, 5},
{8, 9, 6, 11},
{8, 3, -5, 15},
{0, -12, 11, -8},
{-14, -3, -2, 0},
{-2, -3, 1, 1},
{8, -12, 1, 2},
{0, -11, -14, -10},
{-9, -16, 4, -11},
{9, -15, -4, 8},
{-13, -3, -10, -3},
{3, 2, 3, -7},
{-8, 2, 18, 0},
{0, 8, -6, -4},
{12, -13, 7, 18},
{-14, 3, -10, -1},
{6, 7, -3, 4},
{-6, 7, -11, 4},
{5, -14, 2, 5},
{-17, -7, 17, 12}};
static const int kOffMax = 33;
static bool kCheckBounds = [&]() {
for (const auto& offset : kOffsets) {
CV_Assert(std::abs(offset[0]) < kOffMax);
CV_Assert(std::abs(offset[1]) < kOffMax);
CV_Assert(std::abs(offset[2]) < kOffMax);
CV_Assert(std::abs(offset[3]) < kOffMax);
}
return true;
}();
CV_Assert(kCheckBounds);
CV_Assert(point.x - kOffMax >= 0);
CV_Assert(point.y - kOffMax >= 0);
CV_Assert(point.x + kOffMax < image.cols);
CV_Assert(point.y + kOffMax < image.rows);
CV_Assert(CV_8UC1 == image.type());
CV_Assert(desc.rows == 1);
CV_Assert(desc.cols <= 64);
desc.setTo(0);
for (uint16_t i = 0; i < desc.cols * 8; ++i) {
const auto& offset = kOffsets[i];
uint8_t j = i % 8;
desc.at<uint8_t>(0, i / 8) |=
uint8_t(image.at<uint8_t>(point.y + offset[0], point.x + offset[1]) <
image.at<uint8_t>(point.y + offset[2], point.x + offset[3]))
<< j;
}
}
int main() {
cv::VideoCapture capture(0);
auto features = cv::AgastFeatureDetector::create();
std::vector<cv::KeyPoint> last_keypoints, curr_keypoints;
cv::Mat last_descriptors, curr_descriptors;
cv::Mat last_image, gray, blurred;
cv::BFMatcher::BFMatcher matcher(cv::NORM_HAMMING, true);
std::vector<cv::DMatch> matches;
while (true) {
cv::Mat image;
capture >> image;
std::swap(last_keypoints, curr_keypoints);
std::swap(last_descriptors, curr_descriptors);
curr_keypoints.clear();
cv::cvtColor(image, gray, CV_RGB2GRAY);
cv::GaussianBlur(gray, blurred, cv::Size(7, 7), 2, 2,
cv::BORDER_REFLECT_101);
features->detect(gray, curr_keypoints);
curr_descriptors.create(curr_keypoints.size(), 64, CV_8UC1);
cv::Rect bounds(33, 33, image.cols - 33 * 2, image.rows - 33 * 2);
for (size_t i = 0; i < curr_keypoints.size(); ++i) {
const auto& kp = curr_keypoints[i];
cv::Point pt(kp.pt.x, kp.pt.y);
if (bounds.contains(pt)) {
BRIEFDescriptor(blurred, pt, curr_descriptors.row(i));
}
}
if (curr_descriptors.empty() || last_descriptors.empty()) {
last_image = image;
continue;
}
matches.clear();
matcher.match(curr_descriptors, last_descriptors, matches);
cv::Mat match_image;
cv::drawMatches(image, curr_keypoints, last_image, last_keypoints, matches,
match_image);
last_image = image;
cv::imshow("image", match_image);
cv::waitKey(20);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment