// File: /workspace/github_c_makefile_star2_O1/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, %rbx
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), %rax
movaps %xmm0, (%rax)
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 0x24eb0(%rip), %xmm0    # 0x33220
movsd 0x24ee8(%rip), %xmm1    # 0x33260
movl $0x14, %r8d
movq %r14, %rdi
movq %r15, %rcx
movq %r12, %r9
leaq 0x28(%rsp), %rax
pushq %rax
callq 0xd08b
addq $0x10, %rsp
testl %eax, %eax
je 0xe3a9
movq $0x0, (%rbx)
xorl %r15d, %r15d
jmp 0xe743
movsd 0x18(%rsp), %xmm1
mulsd %xmm1, %xmm1
movsd 0x24ea5(%rip), %xmm2    # 0x33260
movapd %xmm2, %xmm0
subsd %xmm1, %xmm0
xorpd %xmm4, %xmm4
maxsd %xmm4, %xmm0
ucomisd %xmm4, %xmm0
jb 0xe3da
xorps %xmm3, %xmm3
sqrtsd %xmm0, %xmm3
jmp 0xe3ef
callq 0x9990
xorpd %xmm4, %xmm4
movsd 0x24e75(%rip), %xmm2    # 0x33260
movapd %xmm0, %xmm3
movsd 0x10(%rsp), %xmm1
mulsd %xmm1, %xmm1
movapd %xmm2, %xmm0
subsd %xmm1, %xmm0
maxsd %xmm4, %xmm0
ucomisd %xmm4, %xmm0
jb 0xe414
xorps %xmm1, %xmm1
sqrtsd %xmm0, %xmm1
jmp 0xe427
movsd %xmm3, (%rsp)
callq 0x9990
movsd (%rsp), %xmm3
movapd %xmm0, %xmm1
movsd 0x24e41(%rip), %xmm0    # 0x33270
divsd %xmm0, %xmm3
divsd %xmm0, %xmm1
movl $0x29, %r12d
movl $0x29, %esi
movl $0x29, %ecx
movl $0x29, %r8d
movl $0x29, %r9d
movq %r15, %rdi
movq %r15, %rdx
movapd %xmm3, %xmm0
callq 0x9770
leaq 0x1b48(%r14), %rdi
leaq 0x358c(%r14), %rsi
movl $0x1, %edx
movl $0x29, %ecx
movl $0x29, %r9d
movq %r15, %r8
pushq %r12
pushq %r12
callq 0x9140
addq $0x10, %rsp
leaq 0x30(%rsp), %rdi
movl $0x120, %edx            # imm = 0x120
xorl %esi, %esi
callq 0x9400
movq $-0x1a44, %rsi          # imm = 0xE5BC
movsd 0x24dc8(%rip), %xmm0    # 0x33278
movabsq $-0x1c71c71c71c71c71, %r8 # imm = 0xE38E38E38E38E38F
movsd 0x24d9e(%rip), %xmm5    # 0x33260
xorps %xmm3, %xmm3
cvtss2sd 0x358c(%r14,%rsi), %xmm3
xorps %xmm1, %xmm1
cvtss2sd 0x4fd0(%r14,%rsi), %xmm1
divsd %xmm0, %xmm1
cvttsd2si %xmm1, %rdi
xorps %xmm2, %xmm2
cvtsi2sd %rdi, %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 (%rdi,%r9), %rax
xorps %xmm4, %xmm4
cvtsi2sd %rax, %xmm4
mulsd %xmm3, %xmm2
subsd %xmm4, %xmm1
movapd %xmm5, %xmm3
subsd %xmm1, %xmm3
leaq (%rdi,%r9), %rcx
addq $0x24, %rcx
movq %rcx, %rax
mulq %r8
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 (%rdi,%r9), %rcx
addq $0x25, %rcx
movq %rcx, %rax
mulq %r8
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 0xe4c2
xorl %eax, %eax
movsd 0x24c7b(%rip), %xmm1    # 0x33210
movsd 0x8(%rsp), %xmm8
movsd 0x30(%rsp), %xmm2
movsd 0x148(%rsp), %xmm3
xorl %ecx, %ecx
movapd %xmm3, %xmm4
movsd 0x30(%rsp,%rcx,8), %xmm3
addsd %xmm3, %xmm4
addsd 0x38(%rsp,%rcx,8), %xmm4
divsd %xmm1, %xmm4
movsd %xmm4, 0x30(%rsp,%rcx,8)
leaq 0x1(%rcx), %rdx
movq %rdx, %rcx
cmpq $0x23, %rdx
jne 0xe5ad
addsd 0x148(%rsp), %xmm3
addsd %xmm3, %xmm2
divsd %xmm1, %xmm2
movsd %xmm2, 0x148(%rsp)
incq %rax
cmpq $0x6, %rax
jne 0xe59c
xorpd %xmm1, %xmm1
xorl %eax, %eax
maxsd 0x30(%rsp,%rax,8), %xmm1
incq %rax
cmpq $0x24, %rax
jne 0xe601
movq $0x0, (%rbx)
mulsd 0x24c39(%rip), %xmm1    # 0x33258
leaq 0x80(%r14), %r15
movl $0x23, %ecx
movl $0x25, %esi
xorl %r9d, %r9d
movsd 0x24bdd(%rip), %xmm2    # 0x33218
movsd 0x24c3d(%rip), %xmm3    # 0x33280
movq %rcx, %rax
mulq %r8
movq %rdx, %rdi
movq %rsi, %rax
mulq %r8
movsd 0x30(%rsp,%r9,8), %xmm4
ucomisd %xmm1, %xmm4
jbe 0xe718
andq $-0x20, %rdi
leaq (%rdi,%rdi,8), %rdi
leaq (%rsp,%r9,8), %rax
addq $0x30, %rax
movq %rax, %r10
subq %rdi, %r10
movsd 0x118(%r10), %xmm5
ucomisd %xmm5, %xmm4
jbe 0xe718
andq $-0x20, %rdx
leaq (%rdx,%rdx,8), %rdx
subq %rdx, %rax
movsd 0x128(%rax), %xmm6
ucomisd %xmm6, %xmm4
jbe 0xe718
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 %r9, %xmm6
divsd %xmm5, %xmm7
addsd %xmm7, %xmm6
mulsd %xmm0, %xmm6
addsd %xmm8, %xmm6
cmpl $0x0, 0x78(%r14)
movapd %xmm6, %xmm5
addsd %xmm3, %xmm5
je 0xe6ed
movapd %xmm5, %xmm6
movq (%rbx), %rax
movq %rax, %rdx
shlq $0x4, %rdx
movsd %xmm6, (%r15,%rdx)
movsd %xmm4, 0x8(%r15,%rdx)
incq %rax
movq %rax, (%rbx)
cmpq $0x3, %rax
ja 0xe72c
cmpq $0x23, %r9
jb 0xe71e
jmp 0xe72c
cmpq $0x22, %r9
ja 0xe72c
incq %rcx
incq %rsi
incq %r9
jmp 0xe643
movq (%rbx), %rsi
leaq 0x22(%rip), %rcx        # 0xe758
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