edgessubpix参数说明_EdgesSubPix.cpp

#include "EdgesSubPix.h"

#include

#include

using namespace cv;

using namespace std;

const double scale = 128.0; // sum of half Canny filter is 128

static void getCannyKernel(OutputArray _d, double alpha)

{

int r = cvRound(alpha * 3);

int ksize = 2 * r + 1;

_d.create(ksize, 1, CV_16S, -1, true);

Mat k = _d.getMat();

vector kerF(ksize, 0.0f);

kerF[r] = 0.0f;

double a2 = alpha * alpha;

float sum = 0.0f;

for (int x = 1; x <= r; ++x)

{

float v = (float)(-x * std::exp(-x * x / (2 * a2)));

sum += v;

kerF[r + x] = v;

kerF[r - x] = -v;

}

float scale = 128 / sum;

for (int i = 0; i < ksize; ++i)

{

kerF[i] *= scale;

}

Mat temp(ksize, 1, CV_32F, &kerF[0]);

temp.convertTo(k, CV_16S);

}

// non-maximum supression and hysteresis

static void postCannyFilter(const Mat &src, Mat &dx, Mat &dy, int low, int high, Mat &dst)

{

ptrdiff_t mapstep = src.cols + 2;

AutoBuffer buffer((src.cols + 2)*(src.rows + 2) + mapstep * 3 * sizeof(int));

// L2Gradient comparison with square

high = high * high;

low = low * low;

int* mag_buf[3];

mag_buf[0] = (int*)(uchar*)buffer;

mag_buf[1] = mag_buf[0] + mapstep;

mag_buf[2] = mag_buf[1] + mapstep;

memset(mag_buf[0], 0, mapstep*sizeof(int));

uchar* map = (uchar*)(mag_buf[2] + mapstep);

memset(map, 1, mapstep);

memset(map + mapstep*(src.rows + 1), 1, mapstep);

int maxsize = std::max(1 << 10, src.cols * src.rows / 10);

std::vector stack(maxsize);

uchar **stack_top = &stack[0];

uchar **stack_bottom = &stack[0];

/* sector numbers

(Top-Left Origin)

1 2 3

* * *

* * *

0*******0

* * *

* * *

3 2 1

*/

#define CANNY_PUSH(d) *(d) = uchar(2), *stack_top++ = (d)

#define CANNY_POP(d) (d) = *--stack_top

#if CV_SSE2

bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);

#endif

// calculate magnitude and angle of gradient, perform non-maxima suppression.

// fill the map with one of the following values:

// 0 - the pixel might belong to an edge

// 1 - the pixel can not belong to an edge

// 2 - the pixel does belong to an edge

for (int i = 0; i <= src.rows; i++)

{

int* _norm = mag_buf[(i > 0) + 1] + 1;

if (i < src.rows)

{

short* _dx = dx.ptr(i);

short* _dy = dy.ptr(i);

int j = 0, width = src.cols;

#if CV_SSE2

if (haveSSE2)

{

for (; j <= width - 8; j += 8)

{

__m128i v_dx = _mm_loadu_si128((const __m128i *)(_dx + j));

__m128i v_dy = _mm_loadu_si128((const __m128i *)(_dy + j));

__m128i v_dx_ml = _mm_mullo_epi16(v_dx, v_dx), v_dx_mh = _mm_mulhi_epi16(v_dx, v_dx);

__m128i v_dy_ml = _mm_mullo_epi16(v_dy, v_dy), v_dy_mh = _mm_mulhi_epi16(v_dy, v_dy);

__m128i v_norm = _mm_add_epi32(_mm_unpacklo_epi16(v_dx_ml, v_dx_mh), _mm_unpacklo_epi16(v_dy_ml, v_dy_mh));

_mm_storeu_si128((__m128i *)(_norm + j), v_norm);

v_norm = _mm_add_epi32(_mm_unpackhi_epi16(v_dx_ml, v_dx_mh), _mm_unpackhi_epi16(v_dy_ml, v_dy_mh));

_mm_storeu_si128((__m128i *)(_norm + j + 4), v_norm);

}

}

#elif CV_NEON

for (; j <= width - 8; j += 8)

{

int16x8_t v_dx = vld1q_s16(_dx + j), v_dy = vld1q_s16(_dy + j);

int16x4_t v_dxp = vget_low_s16(v_dx), v_dyp = vget_low_s16(v_dy);

int32x4_t v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);

vst1q_s32(_norm + j, v_dst);

v_dxp = vget_high_s16(v_dx), v_dyp = vget_high_s16(v_dy);

v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);

vst1q_s32(_norm + j + 4, v_dst);

}

#endif

for (; j < width; ++j)

_norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j];

_norm[-1] = _norm[src.cols] = 0;

}

else

memset(_norm - 1, 0, /* cn* */mapstep*sizeof(int));

// at the very beginning we do not have a complete ring

// buffer of 3 magnitude rows for non-maxima suppression

if (i == 0)

continue;

uchar* _map = map + mapstep*i + 1;

_map[-1] = _map[src.cols] = 1;

int* _mag = mag_buf[1] + 1; // take the central row

ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1];

ptrdiff_t magstep2 = mag_buf[0] - mag_buf[1];

const short* _x = dx.ptr(i - 1);

const short* _y = dy.ptr(i - 1);

if ((stack_top - stack_bottom) + src.cols > maxsize)

{

int sz = (int)(stack_top - stack_bottom);

maxsize = std::max(maxsize * 3 / 2, sz + src.cols);

stack.resize(maxsize);

stack_bottom = &stack[0];

stack_top = stack_bottom + sz;

}

int prev_flag = 0;

for (int j = 0; j < src.cols; j++)

{

#define CANNY_SHIFT 15

const int TG22 = (int)(0.4142135623730950488016887242097*(1 << CANNY_SHIFT) + 0.5);

int m = _mag[j];

if (m > low)

{

int xs = _x[j];

int ys = _y[j];

int x = std::abs(xs);

int y = std::abs(ys) << CANNY_SHIFT;

int tg22x = x * TG22;

if (y < tg22x)

{

if (m > _mag[j - 1] && m >= _mag[j + 1]) goto __ocv_canny_push;

}

else

{

int tg67x = tg22x + (x << (CANNY_SHIFT + 1));

if (y > tg67x)

{

if (m > _mag[j + magstep2] && m >= _mag[j + magstep1]) goto __ocv_canny_push;

}

else

{

int s = (xs ^ ys) < 0 ? -1 : 1;

if (m > _mag[j + magstep2 - s] && m > _mag[j + magstep1 + s]) goto __ocv_canny_push;

}

}

}

prev_flag = 0;

_map[j] = uchar(1);

continue;

__ocv_canny_push:

if (!prev_flag && m > high && _map[j - mapstep] != 2)

{

CANNY_PUSH(_map + j);

prev_flag = 1;

}

else

_map[j] = 0;

}

// scroll the ring buffer

_mag = mag_buf[0];

mag_buf[0] = mag_buf[1];

mag_buf[1] = mag_buf[2];

mag_buf[2] = _mag;

}

// now track the edges (hysteresis thresholding)

while (stack_top > stack_bottom)

{

uchar* m;

if ((stack_top - stack_bottom) + 8 > maxsize)

{

int sz = (int)(stack_top - stack_bottom);

maxsize = maxsize * 3 / 2;

stack.resize(maxsize);

stack_bottom = &stack[0];

stack_top = stack_bottom + sz;

}

CANNY_POP(m);

if (!m[-1]) CANNY_PUSH(m - 1);

if (!m[1]) CANNY_PUSH(m + 1);

if (!m[-mapstep - 1]) CANNY_PUSH(m - mapstep - 1);

if (!m[-mapstep]) CANNY_PUSH(m - mapstep);

if (!m[-mapstep + 1]) CANNY_PUSH(m - mapstep + 1);

if (!m[mapstep - 1]) CANNY_PUSH(m + mapstep - 1);

if (!m[mapstep]) CANNY_PUSH(m + mapstep);

if (!m[mapstep + 1]) CANNY_PUSH(m + mapstep + 1);

}

// the final pass, form the final image

const uchar* pmap = map + mapstep + 1;

uchar* pdst = dst.ptr();

for (int i = 0; i < src.rows; i++, pmap += mapstep, pdst += dst.step)

{

for (int j = 0; j < src.cols; j++)

pdst[j] = (uchar)-(pmap[j] >> 1);

}

}

static inline double getAmplitude(Mat &dx, Mat &dy, int i, int j)

{

Point2d mag(dx.at(i, j), dy.at(i, j));

return norm(mag);

}

static inline void getMagNeighbourhood(Mat &dx, Mat &dy, Point &p, int w, int h, vector &mag)

{

int top = p.y - 1 >= 0 ? p.y - 1 : p.y;

int down = p.y + 1 < h ? p.y + 1 : p.y;

int left = p.x - 1 >= 0 ? p.x - 1 : p.x;

int right = p.x + 1 < w ? p.x + 1 : p.x;

mag[0] = getAmplitude(dx, dy, top, left);

mag[1] = getAmplitude(dx, dy, top, p.x);

mag[2] = getAmplitude(dx, dy, top, right);

mag[3] = getAmplitude(dx, dy, p.y, left);

mag[4] = getAmplitude(dx, dy, p.y, p.x);

mag[5] = getAmplitude(dx, dy, p.y, right);

mag[6] = getAmplitude(dx, dy, down, left);

mag[7] = getAmplitude(dx, dy, down, p.x);

mag[8] = getAmplitude(dx, dy, down, right);

}

static inline void get2ndFacetModelIn3x3(vector &mag, vector &a)

{

a[0] = (-mag[0] + 2.0 * mag[1] - mag[2] + 2.0 * mag[3] + 5.0 * mag[4] + 2.0 * mag[5] - mag[6] + 2.0 * mag[7] - mag[8]) / 9.0;

a[1] = (-mag[0] + mag[2] - mag[3] + mag[5] - mag[6] + mag[8]) / 6.0;

a[2] = (mag[6] + mag[7] + mag[8] - mag[0] - mag[1] - mag[2]) / 6.0;

a[3] = (mag[0] - 2.0 * mag[1] + mag[2] + mag[3] - 2.0 * mag[4] + mag[5] + mag[6] - 2.0 * mag[7] + mag[8]) / 6.0;

a[4] = (-mag[0] + mag[2] + mag[6] - mag[8]) / 4.0;

a[5] = (mag[0] + mag[1] + mag[2] - 2.0 * (mag[3] + mag[4] + mag[5]) + mag[6] + mag[7] + mag[8]) / 6.0;

}

/*

Compute the eigenvalues and eigenvectors of the Hessian matrix given by

dfdrr, dfdrc, and dfdcc, and sort them in descending order according to

their absolute values.

*/

static inline void eigenvals(vector &a, double eigval[2], double eigvec[2][2])

{

// derivatives

// fx = a[1], fy = a[2]

// fxy = a[4]

// fxx = 2 * a[3]

// fyy = 2 * a[5]

double dfdrc = a[4];

double dfdcc = a[3] * 2.0;

double dfdrr = a[5] * 2.0;

double theta, t, c, s, e1, e2, n1, n2; /* , phi; */

/* Compute the eigenvalues and eigenvectors of the Hessian matrix. */

if (dfdrc != 0.0) {

theta = 0.5*(dfdcc - dfdrr) / dfdrc;

t = 1.0 / (fabs(theta) + sqrt(theta*theta + 1.0));

if (theta < 0.0) t = -t;

c = 1.0 / sqrt(t*t + 1.0);

s = t*c;

e1 = dfdrr - t*dfdrc;

e2 = dfdcc + t*dfdrc;

}

else {

c = 1.0;

s = 0.0;

e1 = dfdrr;

e2 = dfdcc;

}

n1 = c;

n2 = -s;

/* If the absolute value of an eigenvalue is larger than the other, put that

eigenvalue into first position. If both are of equal absolute value, put

the negative one first. */

if (fabs(e1) > fabs(e2)) {

eigval[0] = e1;

eigval[1] = e2;

eigvec[0][0] = n1;

eigvec[0][1] = n2;

eigvec[1][0] = -n2;

eigvec[1][1] = n1;

}

else if (fabs(e1) < fabs(e2)) {

eigval[0] = e2;

eigval[1] = e1;

eigvec[0][0] = -n2;

eigvec[0][1] = n1;

eigvec[1][0] = n1;

eigvec[1][1] = n2;

}

else {

if (e1 < e2) {

eigval[0] = e1;

eigval[1] = e2;

eigvec[0][0] = n1;

eigvec[0][1] = n2;

eigvec[1][0] = -n2;

eigvec[1][1] = n1;

}

else {

eigval[0] = e2;

eigval[1] = e1;

eigvec[0][0] = -n2;

eigvec[0][1] = n1;

eigvec[1][0] = n1;

eigvec[1][1] = n2;

}

}

}

static inline double vector2angle(double x, double y)

{

double a = std::atan2(y, x);

return a >= 0.0 ? a : a + CV_2PI;

}

void extractSubPixPoints(Mat &dx, Mat &dy, vector > &contoursInPixel, vector &contours)

{

int w = dx.cols;

int h = dx.rows;

contours.resize(contoursInPixel.size());

for (size_t i = 0; i < contoursInPixel.size(); ++i)

{

vector &icontour = contoursInPixel[i];

Contour &contour = contours[i];

contour.points.resize(icontour.size());

contour.response.resize(icontour.size());

contour.direction.resize(icontour.size());

#if defined(_OPENMP) && defined(NDEBUG)

#pragma omp parallel for

#endif

for (int j = 0; j < (int)icontour.size(); ++j)

{

vector magNeighbour(9);

getMagNeighbourhood(dx, dy, icontour[j], w, h, magNeighbour);

vector a(9);

get2ndFacetModelIn3x3(magNeighbour, a);

// Hessian eigen vector

double eigvec[2][2], eigval[2];

eigenvals(a, eigval, eigvec);

double t = 0.0;

double ny = eigvec[0][0];

double nx = eigvec[0][1];

if (eigval[0] < 0.0)

{

double rx = a[1], ry = a[2], rxy = a[4], rxx = a[3] * 2.0, ryy = a[5] * 2.0;

t = -(rx * nx + ry * ny) / (rxx * nx * nx + 2.0 * rxy * nx * ny + ryy * ny * ny);

}

double px = nx * t;

double py = ny * t;

float x = (float)icontour[j].x;

float y = (float)icontour[j].y;

if (fabs(px) <= 0.5 && fabs(py) <= 0.5)

{

x += (float)px;

y += (float)py;

}

contour.points[j] = Point2f(x, y);

contour.response[j] = (float)(a[0] / scale);

contour.direction[j] = (float)vector2angle(ny, nx);

}

}

}

//---------------------------------------------------------------------

// INTERFACE FUNCTION

//---------------------------------------------------------------------

void EdgesSubPix(Mat &gray, double alpha, int low, int high,

vector &contours, OutputArray hierarchy, int mode)

{

Mat blur;

GaussianBlur(gray, blur, Size(0, 0), alpha, alpha);

Mat d;

getCannyKernel(d, alpha);

Mat one = Mat::ones(Size(1, 1), CV_16S);

Mat dx, dy;

sepFilter2D(blur, dx, CV_16S, d, one);

sepFilter2D(blur, dy, CV_16S, one, d);

// non-maximum supression & hysteresis threshold

Mat edge = Mat::zeros(gray.size(), CV_8UC1);

int lowThresh = cvRound(scale * low);

int highThresh = cvRound(scale * high);

postCannyFilter(gray, dx, dy, lowThresh, highThresh, edge);

// contours in pixel precision

vector > contoursInPixel;

findContours(edge, contoursInPixel, hierarchy, mode, CHAIN_APPROX_NONE);

// subpixel position extraction with steger's method and facet model 2nd polynominal in 3x3 neighbourhood

extractSubPixPoints(dx, dy, contoursInPixel, contours);

}

void EdgesSubPix(Mat &gray, double alpha, int low, int high, vector &contours)

{

vector hierarchy;

EdgesSubPix(gray, alpha, low, high, contours, hierarchy, RETR_LIST);

}

一键复制

编辑

Web IDE

原始数据

按行查看

历史

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值