// File: /workspace/github_c_makefile_star2_O3/zpole[P]IICV/vl/covdet.c
// Function: vl_covdet_extract_orientations_for_frame
VlCovDetFeatureOrientation *
vl_covdet_extract_orientations_for_frame (VlCovDet * self,
                                          vl_size * numOrientations,
                                          VlFrameOrientedEllipse frame)
{
  int err ;
  vl_index k, i ;
  vl_index iter ;

  double extent = VL_COVDET_AA_PATCH_EXTENT ;
  vl_size resolution = VL_COVDET_AA_PATCH_RESOLUTION ;
  vl_size side = 2 * resolution + 1  ;

  vl_size const numBins = VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS ;
  double hist [VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS] ;
  double const binExtent = 2 * VL_PI / VL_COVDET_OR_NUM_ORIENTATION_HISTOGAM_BINS ;
  double const peakRelativeSize = VL_COVDET_OR_ADDITIONAL_PEAKS_RELATIVE_SIZE ;
  double maxPeakValue ;

  double A [2*2] = {frame.a11, frame.a21, frame.a12, frame.a22} ;
  double T [2] = {frame.x, frame.y} ;
  double U [2*2] ;
  double V [2*2] ;
  double D [2*2] ;
  double sigma1, sigma2 ;
  double sigmaD = 1.0 ;
  double theta0 ;

  assert(self);
  assert(numOrientations) ;

  /*
   The goal is to estimate a rotation R(theta) such that the patch given
   by the transformation A R(theta) has the strongest average
   gradient pointing right (or down for transposed conventions).

   To compensate for tha anisotropic smoothing due to warping,
   A is decomposed as A = U D V' and the patch is warped by
   U D only, meaning that the matrix R_(theta) will be estimated instead,
   where:

      A R(theta) = U D V' R(theta) = U D R_(theta)

   such that R(theta) = V R(theta). That is an extra rotation of
   theta0 = atan2(V(2,1),V(1,1)).
   */

  /* axis aligned anisotropic smoothing for easier compensation */
  vl_svd2(D, U, V, A) ;

  A[0] = U[0] * D[0] ;
  A[1] = U[1] * D[0] ;
  A[2] = U[2] * D[3] ;
  A[3] = U[3] * D[3] ;

  theta0 = atan2(V[1],V[0]) ;

  err = vl_covdet_extract_patch_helper(self,
                                       &sigma1, &sigma2,
                                       self->aaPatch,
                                       resolution,
                                       extent,
                                       sigmaD,
                                       A, T, D[0], D[3]) ;

  if (err) {
    *numOrientations = 0 ;
    return NULL ;
  }

  if (1) {
    double deltaSigma1 = sqrt(VL_MAX(sigmaD*sigmaD - sigma1*sigma1,0)) ;
    double deltaSigma2 = sqrt(VL_MAX(sigmaD*sigmaD - sigma2*sigma2,0)) ;
    double stephat = extent / resolution ;
    vl_imsmooth_f(self->aaPatch, side,
                  self->aaPatch, side, side, side,
                  deltaSigma1 / stephat, deltaSigma2 / stephat) ;
  }

  /* histogram of oriented gradients */
  vl_imgradient_polar_f (self->aaPatchX, self->aaPatchY, 1, side,
                         self->aaPatch, side, side, side) ;

  memset (hist, 0, sizeof(double) * numBins) ;

  for (k = 0 ; k < (signed)(side*side) ; ++k) {
    double modulus = self->aaPatchX[k] ;
    double angle = self->aaPatchY[k] ;
    double weight = self->aaMask[k] ;

    double x = angle / binExtent ;
    vl_index bin = vl_floor_d(x) ;
    double w2 = x - bin ;
    double w1 = 1.0 - w2 ;

    hist[(bin + numBins) % numBins] += w1 * (modulus * weight) ;
    hist[(bin + numBins + 1) % numBins] += w2 * (modulus * weight) ;
  }

  /* smooth histogram */
  for (iter = 0; iter < 6; iter ++) {
    double prev = hist [numBins - 1] ;
    double first = hist [0] ;
    vl_index i ;
    for (i = 0; i < (signed)numBins - 1; ++i) {
      double curr = (prev + hist[i] + hist[(i + 1) % numBins]) / 3.0 ;
      prev = hist[i] ;
      hist[i] = curr ;
    }
    hist[i] = (prev + hist[i] + first) / 3.0 ;
  }

  /* find the histogram maximum */
  maxPeakValue = 0 ;
  for (i = 0 ; i < (signed)numBins ; ++i) {
    maxPeakValue = VL_MAX (maxPeakValue, hist[i]) ;
  }

  /* find peaks within 80% from max */
  *numOrientations = 0 ;
  for(i = 0 ; i < (signed)numBins ; ++i) {
    double h0 = hist [i] ;
    double hm = hist [(i - 1 + numBins) % numBins] ;
    double hp = hist [(i + 1 + numBins) % numBins] ;

    /* is this a peak? */
    if (h0 > peakRelativeSize * maxPeakValue && h0 > hm && h0 > hp) {
      /* quadratic interpolation */
      double di = - 0.5 * (hp - hm) / (hp + hm - 2 * h0) ;
      double th = binExtent * (i + di) + theta0 ;
      if (self->transposed) {
        /* the axis to the right is y, measure orientations from this */
        th = th - VL_PI/2 ;
      }
      self->orientations[*numOrientations].angle = th ;
      self->orientations[*numOrientations].score = h0 ;
      *numOrientations += 1 ;
      //VL_PRINTF("%d %g\n", *numOrientations, th) ;

      if (*numOrientations >= VL_COVDET_MAX_NUM_ORIENTATIONS) break ;
    }
  }

  /* sort the orientations by decreasing scores */
  qsort(self->orientations,
        *numOrientations,
        sizeof(VlCovDetFeatureOrientation),
        _vl_covdet_compare_orientations_descending) ;

  return self->orientations ;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1d8, %rsp            # imm = 0x1D8
movq %rsi, (%rsp)
movq %rdi, %r14
movups 0x218(%rsp), %xmm0
movss 0x220(%rsp), %xmm1
movlhps %xmm0, %xmm1            # xmm1 = xmm1[0],xmm0[0]
shufps $0xe2, %xmm0, %xmm1     # xmm1 = xmm1[2,0],xmm0[2,3]
cvtps2pd %xmm1, %xmm0
leaq 0x1b0(%rsp), %r12
movaps %xmm0, (%r12)
movaps 0x210(%rsp), %xmm0
movss 0x224(%rsp), %xmm1
shufps $0xf4, %xmm0, %xmm1     # xmm1 = xmm1[0,1],xmm0[3,3]
shufps $0xf2, %xmm0, %xmm1     # xmm1 = xmm1[2,0],xmm0[3,3]
cvtps2pd %xmm1, %xmm0
movaps %xmm0, 0x10(%r12)
cvtps2pd 0x210(%rsp), %xmm0
leaq 0x20(%rsp), %rbx
movaps %xmm0, (%rbx)
leaq 0x150(%rsp), %r13
leaq 0x190(%rsp), %r15
leaq 0x170(%rsp), %rbp
movq %r13, %rdi
movq %r15, %rsi
movq %rbp, %rdx
movq %r12, %rcx
callq 0x9650
movapd (%r13), %xmm0
unpcklpd %xmm0, %xmm0            # xmm0 = xmm0[0,0]
mulpd (%r15), %xmm0
movsd 0x18(%r13), %xmm1
unpcklpd %xmm1, %xmm1            # xmm1 = xmm1[0,0]
mulpd 0x10(%r15), %xmm1
movapd %xmm0, (%r12)
movapd %xmm1, 0x10(%r12)
movsd (%rbp), %xmm1
movsd 0x8(%rbp), %xmm0
callq 0x96e0
movsd %xmm0, 0x8(%rsp)
leaq 0x104(%r14), %r15
movsd (%r13), %xmm2
movsd 0x18(%r13), %xmm3
subq $0x8, %rsp
leaq 0x20(%rsp), %rsi
leaq 0x18(%rsp), %rdx
movsd 0x23e2e(%rip), %xmm0    # 0x32230
movsd 0x23e66(%rip), %xmm1    # 0x32270
movl $0x14, %r8d
movq %r14, %rdi
movq %r15, %rcx
movq %r12, %r9
pushq %rbx
callq 0xd0fe
addq $0x10, %rsp
testl %eax, %eax
je 0xe43a
movq (%rsp), %rax
movq $0x0, (%rax)
xorl %r15d, %r15d
jmp 0xe78a
movq (%rsp), %r12
movsd 0x18(%rsp), %xmm0
mulsd %xmm0, %xmm0
movsd 0x23e20(%rip), %xmm3    # 0x32270
movapd %xmm3, %xmm1
subsd %xmm0, %xmm1
xorpd %xmm2, %xmm2
maxsd %xmm2, %xmm1
xorps %xmm0, %xmm0
sqrtsd %xmm1, %xmm0
movsd 0x10(%rsp), %xmm1
mulsd %xmm1, %xmm1
subsd %xmm1, %xmm3
maxsd %xmm2, %xmm3
xorps %xmm1, %xmm1
sqrtsd %xmm3, %xmm1
movsd 0x23df8(%rip), %xmm2    # 0x32280
divsd %xmm2, %xmm0
divsd %xmm2, %xmm1
movl $0x29, %ebx
movl $0x29, %esi
movl $0x29, %ecx
movl $0x29, %r8d
movl $0x29, %r9d
movq %r15, %rdi
movq %r15, %rdx
callq 0x9770
leaq 0x1b48(%r14), %rdi
leaq 0x358c(%r14), %rsi
movl $0x1, %edx
movl $0x29, %ecx
movl $0x29, %r9d
movq %r15, %r8
pushq %rbx
pushq %rbx
callq 0x9140
addq $0x10, %rsp
leaq 0x30(%rsp), %rdi
movl $0x120, %edx            # imm = 0x120
xorl %esi, %esi
callq 0x9400
movsd 0x23d75(%rip), %xmm5    # 0x32270
movq $-0x1a44, %rsi          # imm = 0xE5BC
movsd 0x23d7e(%rip), %xmm0    # 0x32288
movabsq $-0x1c71c71c71c71c71, %rdi # imm = 0xE38E38E38E38E38F
xorps %xmm3, %xmm3
cvtss2sd 0x358c(%r14,%rsi), %xmm3
xorps %xmm1, %xmm1
cvtss2sd 0x4fd0(%r14,%rsi), %xmm1
divsd %xmm0, %xmm1
cvttsd2si %xmm1, %r8
xorps %xmm2, %xmm2
cvtsi2sd %r8, %xmm2
cmpneqpd %xmm1, %xmm2
xorpd %xmm4, %xmm4
cmpnlepd %xmm1, %xmm4
andpd %xmm2, %xmm4
xorps %xmm2, %xmm2
cvtss2sd 0x6a14(%r14,%rsi), %xmm2
movq %xmm4, %r9
leaq (%r8,%r9), %rax
xorps %xmm4, %xmm4
cvtsi2sd %rax, %xmm4
mulsd %xmm3, %xmm2
subsd %xmm4, %xmm1
movapd %xmm5, %xmm3
subsd %xmm1, %xmm3
leaq (%r8,%r9), %rcx
addq $0x24, %rcx
movq %rcx, %rax
mulq %rdi
shrq $0x5, %rdx
shll $0x2, %edx
leal (%rdx,%rdx,8), %eax
subl %eax, %ecx
mulsd %xmm2, %xmm3
addsd 0x30(%rsp,%rcx,8), %xmm3
movsd %xmm3, 0x30(%rsp,%rcx,8)
leaq (%r8,%r9), %rcx
addq $0x25, %rcx
movq %rcx, %rax
mulq %rdi
shrq $0x5, %rdx
shll $0x2, %edx
leal (%rdx,%rdx,8), %eax
subl %eax, %ecx
mulsd %xmm2, %xmm1
addsd 0x30(%rsp,%rcx,8), %xmm1
movsd %xmm1, 0x30(%rsp,%rcx,8)
addq $0x4, %rsi
jne 0xe514
movsd 0x148(%rsp), %xmm2
xorl %eax, %eax
movsd 0x23c30(%rip), %xmm1    # 0x32220
movq %r12, %r9
movsd 0x8(%rsp), %xmm8
movl $0x1, %ecx
movsd 0x30(%rsp), %xmm3
movapd %xmm3, %xmm4
movapd %xmm2, %xmm5
movapd %xmm4, %xmm2
addsd %xmm4, %xmm5
movsd 0x30(%rsp,%rcx,8), %xmm4
addsd %xmm4, %xmm5
divsd %xmm1, %xmm5
movsd %xmm5, 0x28(%rsp,%rcx,8)
incq %rcx
cmpq $0x24, %rcx
jne 0xe609
addsd 0x148(%rsp), %xmm2
addsd %xmm2, %xmm3
divsd %xmm1, %xmm3
movsd %xmm3, 0x148(%rsp)
incq %rax
movapd %xmm3, %xmm2
cmpq $0x6, %rax
jne 0xe5fa
xorpd %xmm1, %xmm1
xorl %eax, %eax
maxsd 0x30(%rsp,%rax,8), %xmm1
incq %rax
cmpq $0x24, %rax
jne 0xe65f
movq $0x0, (%r9)
mulsd 0x23beb(%rip), %xmm1    # 0x32268
leaq 0x80(%r14), %r15
xorl %esi, %esi
movl $0x23, %eax
movsd 0x23b95(%rip), %xmm2    # 0x32228
movsd 0x23bf5(%rip), %xmm3    # 0x32290
xorl %ecx, %ecx
leal 0x25(%rcx), %edx
movsd 0x30(%rsp,%rcx,8), %xmm4
movq %rcx, %rdi
subq $0x1, %rdi
cmovbq %rax, %rdi
ucomisd %xmm1, %xmm4
jbe 0xe6ec
movsd 0x30(%rsp,%rdi,8), %xmm5
ucomisd %xmm5, %xmm4
jbe 0xe6ec
movzbl %dl, %edi
imull $0x39, %edi, %edi
shrl $0x9, %edi
andl $-0x4, %edi
leal (%rdi,%rdi,8), %edi
movl %ecx, %r8d
subl %edi, %r8d
addl $0x25, %r8d
movzbl %r8b, %edi
movsd 0x30(%rsp,%rdi,8), %xmm6
ucomisd %xmm6, %xmm4
ja 0xe6fd
incq %rcx
leaq -0x1(%rcx), %rdi
incb %dl
cmpq $0x23, %rdi
jb 0xe6a0
jmp 0xe776
movapd %xmm6, %xmm7
subsd %xmm5, %xmm7
mulsd %xmm2, %xmm7
addsd %xmm6, %xmm5
movapd %xmm4, %xmm6
addsd %xmm4, %xmm6
subsd %xmm6, %xmm5
xorps %xmm6, %xmm6
cvtsi2sd %rcx, %xmm6
divsd %xmm5, %xmm7
addsd %xmm7, %xmm6
mulsd %xmm0, %xmm6
addsd %xmm8, %xmm6
cmpl $0x0, 0x78(%r14)
movapd %xmm6, %xmm5
addsd %xmm3, %xmm5
je 0xe745
movapd %xmm5, %xmm6
movq %rsi, %rdx
shlq $0x4, %rdx
movsd %xmm6, (%r15,%rdx)
movsd %xmm4, 0x8(%r15,%rdx)
incq %rsi
movq %rsi, (%r9)
cmpq $0x3, %rsi
ja 0xe776
leaq 0x1(%rcx), %rdx
cmpq $0x23, %rcx
movq %rdx, %rcx
jb 0xe69d
leaq 0x22(%rip), %rcx        # 0xe79f
movl $0x10, %edx
movq %r15, %rdi
callq 0x9190
movq %r15, %rax
addq $0x1d8, %rsp            # imm = 0x1D8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq