MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ harris_response() [1/2]

MAYAFLUX_API void MayaFlux::Kinesis::Vision::harris_response ( std::span< const float >  gray,
std::span< float >  dx,
std::span< float >  dy,
std::span< float >  tmp,
std::span< float >  ixx,
std::span< float >  iyy,
std::span< float >  ixy,
std::span< float >  sxx,
std::span< float >  syy,
std::span< float >  sxy,
std::span< float >  dst,
uint32_t  w,
uint32_t  h,
float  k,
std::span< const float >  kern 
)

Compute the Harris corner response map into caller-supplied buffers.

Writes the normalised response into dst. Intermediate buffers dx/dy/tmp/ixx/iyy/ixy/sxx/syy/sxy must each be size >= w * h and must not alias each other or gray.

Parameters
graySingle-channel float span, size w * h.
dxScratch: horizontal gradient, size >= w * h.
dyScratch: vertical gradient, size >= w * h.
tmpScratch: filter horizontal pass, size >= w * h.
ixxScratch: structure tensor Ixx, size >= w * h.
iyyScratch: structure tensor Iyy, size >= w * h.
ixyScratch: structure tensor Ixy, size >= w * h.
sxxScratch: smoothed Sxx, size >= w * h.
syyScratch: smoothed Syy, size >= w * h.
sxyScratch: smoothed Sxy, size >= w * h.
dstOutput response map, size >= w * h, values in [0, 1].
wImage width in pixels.
hImage height in pixels.
kHarris sensitivity parameter. Typical range [0.04, 0.06].
kernPrecomputed 1D Gaussian kernel for structure tensor smoothing.

Definition at line 66 of file Harris.cpp.

75{
76 const size_t n = static_cast<size_t>(w) * h;
77
78 sobel(gray, dx, dy, tmp, w, h);
79
80 {
81 const float* dx_ptr = dx.data();
82 const float* dy_ptr = dy.data();
83 float* ixx_ptr = ixx.data();
84 float* iyy_ptr = iyy.data();
85 float* ixy_ptr = ixy.data();
86
87 P::for_each(P::par_unseq,
88 std::views::iota(size_t { 0 }, n).begin(),
89 std::views::iota(size_t { 0 }, n).end(),
90 [&](size_t i) {
91 const float gx = dx_ptr[i];
92 const float gy = dy_ptr[i];
93 ixx_ptr[i] = gx * gx;
94 iyy_ptr[i] = gy * gy;
95 ixy_ptr[i] = gx * gy;
96 });
97 }
98
99 const float* h_src[3] = { ixx.data(), iyy.data(), ixy.data() };
100 float* h_dst[3] = { dx.data(), dy.data(), tmp.data() };
101 filter_horizontal_planes({ h_src, 3 }, { h_dst, 3 }, w, h, kern);
102
103 const float* v_src[3] = { dx.data(), dy.data(), tmp.data() };
104 float* v_dst[3] = { sxx.data(), syy.data(), sxy.data() };
105 filter_vertical_planes({ v_src, 3 }, { v_dst, 3 }, w, h, kern);
106
107 {
108 const float* sxx_ptr = sxx.data();
109 const float* syy_ptr = syy.data();
110 const float* sxy_ptr = sxy.data();
111 float* dst_ptr = dst.data();
112
113#ifdef MAYAFLUX_ARCH_X64
114 const __m256 k_vec = _mm256_set1_ps(k);
115 const __m256 zero = _mm256_setzero_ps();
116
117 size_t i = 0;
118 for (; i + 8 <= n; i += 8) {
119 const __m256 s0 = _mm256_loadu_ps(sxx_ptr + i);
120 const __m256 s1 = _mm256_loadu_ps(syy_ptr + i);
121 const __m256 s01 = _mm256_loadu_ps(sxy_ptr + i);
122
123 const __m256 det = _mm256_sub_ps(
124 _mm256_mul_ps(s0, s1),
125 _mm256_mul_ps(s01, s01));
126 const __m256 trace = _mm256_add_ps(s0, s1);
127 const __m256 resp = _mm256_max_ps(zero,
128 _mm256_fnmadd_ps(k_vec,
129 _mm256_mul_ps(trace, trace),
130 det));
131
132 _mm256_storeu_ps(dst_ptr + i, resp);
133 }
134 for (; i < n; ++i) {
135 const float s0 = sxx_ptr[i];
136 const float s1 = syy_ptr[i];
137 const float s01 = sxy_ptr[i];
138 const float det = s0 * s1 - s01 * s01;
139 const float trace = s0 + s1;
140 dst_ptr[i] = std::max(0.0F, det - k * trace * trace);
141 }
142
143#elif defined(MAYAFLUX_ARCH_ARM64)
144 const float32x4_t k_vec = vdupq_n_f32(k);
145 const float32x4_t zero = vdupq_n_f32(0.0F);
146
147 size_t i = 0;
148 for (; i + 4 <= n; i += 4) {
149 const float32x4_t s0 = vld1q_f32(sxx_ptr + i);
150 const float32x4_t s1 = vld1q_f32(syy_ptr + i);
151 const float32x4_t s01 = vld1q_f32(sxy_ptr + i);
152
153 const float32x4_t det = vsubq_f32(
154 vmulq_f32(s0, s1),
155 vmulq_f32(s01, s01));
156 const float32x4_t trace = vaddq_f32(s0, s1);
157 const float32x4_t resp = vmaxq_f32(zero,
158 vmlsq_f32(det, k_vec, vmulq_f32(trace, trace)));
159
160 vst1q_f32(dst_ptr + i, resp);
161 }
162 for (; i < n; ++i) {
163 const float s0 = sxx_ptr[i];
164 const float s1 = syy_ptr[i];
165 const float s01 = sxy_ptr[i];
166 const float det = s0 * s1 - s01 * s01;
167 const float trace = s0 + s1;
168 dst_ptr[i] = std::max(0.0F, det - k * trace * trace);
169 }
170
171#else
172 for (size_t i = 0; i < n; ++i) {
173 const float s0 = sxx_ptr[i];
174 const float s1 = syy_ptr[i];
175 const float s01 = sxy_ptr[i];
176 const float det = s0 * s1 - s01 * s01;
177 const float trace = s0 + s1;
178 dst_ptr[i] = std::max(0.0F, det - k * trace * trace);
179 }
180#endif
181 }
182}
uint32_t h
Definition InkPress.cpp:28
float k
void sobel(std::span< const float > gray, std::span< float > dx, std::span< float > dy, std::span< float > tmp, uint32_t w, uint32_t h)
Sobel gradient writing dx and dy into caller-supplied buffers.
Definition Gradient.cpp:66
void filter_horizontal_planes(std::span< const float *const > src, std::span< float *const > dst, uint32_t w, uint32_t h, std::span< const float > kernel)
Fused horizontal separable filter over N planes.
void filter_vertical_planes(std::span< const float *const > src, std::span< float *const > dst, uint32_t w, uint32_t h, std::span< const float > kernel)
Fused vertical separable filter over N planes.

References filter_horizontal_planes(), filter_vertical_planes(), h, k, and sobel().

+ Here is the call graph for this function: