A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/codeplaysoftware/visioncpp/wiki/Example:-Harris-Corner-Detection below:

Harris Corner Detection · codeplaysoftware/visioncpp Wiki · GitHub

Implementing Harris Corner Detector in VisionCpp

VisionCpp is a powerful tool to write Computer Vision algorithms for high performance computing. One really famous algorithm which has many applications is the Harris Corner detector [1]. Corners are important keypoints in a image. Those points can be used to detect objects, classify images, create panoramic scenes and generate 3D reconstruction.

The Harris Corner detector is based on the derivatives of the image. Below we show briefly what are the formulae to implement the Harris Corner detector:

![Harris Corner Detection formula] (https://raw.githubusercontent.com/wiki/codeplaysoftware/visioncpp/images/harris_formula.gif)

Where:

After computing the Matrix M, a score can be calculated for each window, to determine if it can possibly contain a corner using the formula below. Where det in the determinant of a matrix and trace is the sum of the diagonal elements.

This algorithm is applied to each pixel, so it is possible to use the features of VisionCpp to implement it in parallel.

Let's go step by step how to implement the algorithm in VisionCpp (The full file which implements the Harris Corner Detector can be seen here).

// selecting CPU as OpenCL-accelerator device
auto dev = visioncpp::make_device<visioncpp::backend::sycl, visioncpp::device::cpu>();
// path to load the image using opencv
cv::Mat input = cv::imread(argv[1]);
 
// defining the image size constants
constexpr size_t COLS = 512;
constexpr size_t ROWS = 512;
 
// creating a pointer to store the results
std::shared_ptr<unsigned char> output(new unsigned char[COLS * ROWS],[](unsigned char* dataMem) { delete[] dataMem; });
 
// initialize an output image from OpenCV for displaying results
cv::Mat outputImage(ROWS, COLS, CV_8UC1, output.get());
// the node which gets the input data from OpenCV
auto in = visioncpp::terminal<pixel::U8C3, COLS, ROWS, memory_type::Buffer2D>(input.data);
 
// the node which gets the output data
auto out = visioncpp::terminal<pixel::U8C1, COLS, ROWS, memory_type::Buffer2D>(output.get());
// convert to Float
auto frgb = visioncpp::point_operation<visioncpp::OP_U8C3ToF32C3>(in);
 
// convert to gray scale
auto fgray = visioncpp::point_operation<visioncpp::OP_RGBToGRAY>(frgb);
/// \brief this functor implements a convolution for a custom filter
struct Filter2D {
  /// \param nbr - input image
  /// \param fltr - custom filter
  template <typename T1, typename T2>
  float operator()(T1& nbr, T2& fltr) {
    int hs_c = (fltr.cols / 2);
    int hs_r = (fltr.rows / 2);
    float out = 0;
    for (int i2 = -hs_c, i = 0; i2 <= hs_c; i2++, i++)
      for (int j2 = -hs_r, j = 0; j2 <= hs_r; j2++, j++)
        out += (nbr.at(nbr.I_c + i2, nbr.I_r + j2) * fltr.at(i, j));
    return out;
  }
};
// initializing the mask memories on host
float sobel_x[9] = {-1.0f, 0.0f, 1.0f, -2.0f, 0.0f, 2.0f, -1.0f, 0.0f, 1.0f};
float sobel_y[9] = {-1.0f, -2.0f, -1.0f, 0.0, 0.0f, 0.0f, 1.0f, 2.0f, 1.0f};
 
// initializing the node which store the masks on the device
auto px_filter = visioncpp::terminal<float, 3, 3, memory_type::Buffer2D, scope::Constant>(sobel_x);
auto py_filter = visioncpp::terminal<float, 3, 3, memory_type::Buffer2D, scope::Constant>(sobel_y);
// applying derivative in x direction
auto px = visioncpp::neighbour_operation<Filter2D>(fgray, px_filter);
// applying derivative in y direction
auto py = visioncpp::neighbour_operation<Filter2D>(fgray, py_filter);
// operator created to perform a power of 2 of the image
struct PowerOf2 {
  template <typename T>
  float operator()(T t) {
    return t * t;
  }
};
 
// operator for element-wise multiplication between two images
struct Mul {
  template <typename T1, typename T2>
  float operator()(T1 t1, T2 t2) {
    return t1 * t2;
  }
};
 
// operator to add two images
struct Add {
  template <typename T1, typename T2>
  float operator()(T1 t1, T2 t2) {
    return t1 + t2;
  }
};
 
// operator to subtract two images
struct Sub {
  template <typename T1, typename T2>
  float operator()(T1 t1, T2 t2) {
    return t1 - t2;
  }
};
auto px2 = visioncpp::point_operation<PowerOf2>(px);
auto py2 = visioncpp::point_operation<PowerOf2>(py);
auto pxy = visioncpp::point_operation<Mul>(px, py);
// breaking the tree before convolution for a better use of shared memory
auto kpx2 = visioncpp::schedule<policy::Fuse, SM, SM, SM, SM>(px2);
auto kpy2 = visioncpp::schedule<policy::Fuse, SM, SM, SM, SM>(py2);
auto kpxy = visioncpp::schedule<policy::Fuse, SM, SM, SM, SM>(pxy);
 
// Summing neighbours
float sum_mask[9] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
auto sum_mask_node = visioncpp::terminal<float, 3, 3, memory_type::Buffer2D,scope::Constant>(sum_mask);
 
auto sumpx2 = visioncpp::neighbour_operation<Filter2D>(kpx2, sum_mask_node);
auto sumpy2 = visioncpp::neighbour_operation<Filter2D>(kpy2, sum_mask_node);
auto sumpxy = visioncpp::neighbour_operation<Filter2D>(kpxy, sum_mask_node);
 
// breaking the tree after convolution
auto ksumpx2 = visioncpp::schedule<policy::Fuse, SM, SM, SM, SM>(sumpx2);
auto ksumpy2 = visioncpp::schedule<policy::Fuse, SM, SM, SM, SM>(sumpy2);
auto ksumpxy = visioncpp::schedule<policy::Fuse, SM, SM, SM, SM>(sumpxy);

// applying the formula det(M)-k*(trace(M)^2)
// det(M) = (ksumpx2*ksumpy2 - ksumpxy*ksumpxy)
auto mul1 = visioncpp::point_operation<Mul>(ksumpx2, ksumpy2);
auto mul2 = visioncpp::point_operation<PowerOf2>(ksumpxy);
auto det = visioncpp::point_operation<Sub>(mul1, mul2);
 
// trace(M) = ksumpx2 + ksumpy2
auto trace = visioncpp::point_operation<Add>(ksumpx2, ksumpy2);
 
// trace(M)^2
auto trace2 = visioncpp::point_operation<PowerOf2>(trace);
 
// k*(trace(M)^2)
auto k_node = visioncpp::terminal<float, memory_type::Const>(k_param);
auto ktrace2 = visioncpp::point_operation<Mul>(trace2, k_node);
 
// harris = det(M)-k*(trace(M)^2)
auto harris = visioncpp::point_operation<Sub>(det, ktrace2);
// apply a threshold
// threshold parameter for the Harris
float threshold = 4.0f;
auto thresh_node = visioncpp::terminal<float, memory_type::Const>(static_cast<float>(threshold));
auto harrisTresh = visioncpp::point_operation<Thresh>(harris, thresh_node);
 
// convert to unsigned char for displaying purposes
auto display = visioncpp::point_operation<FloatToU8C1>(harrisTresh);
// assign to the output
auto k = visioncpp::assign(out, display);
// execute expression tree
visioncpp::execute<policy::Fuse, 32, 32, 16, 16>(k, q);
// display result
cv::imshow("Harris", outputImage);

VisionCpp is a computer vision framework which allows the user to create their own operators for developing high-level applications. Like many computer vision algorithms, the Harris Corner detector can be implemented as an operation that can be applied to each pixel in parallel. The tree-based model enables fusion of kernels by the compiler to produce highly-optimized kernels to be executed on OpenCL-accelerated platforms, enabling the creation of high-performance applications for computer vision.

[1] Harris, C., and M. Stephens. "A Combined Corner and Edge Detector." PDF. Proceedings of the 4th Alvey Vision Conference. pp. 147–151.

[2] https://commons.wikimedia.org/wiki/File:ExperimentalChessbaseChessBoard.png


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4