// File: /workspace/github_c_makefile_star2_O2/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), %r15
movaps %xmm0, (%r15)
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(%r15)
cvtps2pd 0x210(%rsp), %xmm0
leaq 0x20(%rsp), %rbx
movaps %xmm0, (%rbx)
leaq 0x150(%rsp), %r13
leaq 0x190(%rsp), %r12
leaq 0x170(%rsp), %rbp
movq %r13, %rdi
movq %r12, %rsi
movq %rbp, %rdx
movq %r15, %rcx
callq 0x9690
movapd (%r13), %xmm0
unpcklpd %xmm0, %xmm0            # xmm0 = xmm0[0,0]
mulpd (%r12), %xmm0
movsd 0x18(%r13), %xmm1
unpcklpd %xmm1, %xmm1            # xmm1 = xmm1[0,0]
mulpd 0x10(%r12), %xmm1
movapd %xmm0, (%r15)
movapd %xmm1, 0x10(%r15)
movsd (%rbp), %xmm1
movsd 0x8(%rbp), %xmm0
callq 0x9730
movsd %xmm0, 0x8(%rsp)
leaq 0x104(%r14), %r12
movsd (%r13), %xmm2
movsd 0x18(%r13), %xmm3
subq $0x8, %rsp
leaq 0x20(%rsp), %rsi
leaq 0x18(%rsp), %rdx
pushq $0x14
popq %r8
movsd 0x1f6b3(%rip), %xmm0    # 0x2d1f8
movsd 0x1f6eb(%rip), %xmm1    # 0x2d238
movq %r14, %rdi
movq %r12, %rcx
movq %r15, %r9
pushq %rbx
callq 0xc952
addq $0x10, %rsp
testl %eax, %eax
je 0xdb74
movq (%rsp), %rax
andq $0x0, (%rax)
xorl %r15d, %r15d
jmp 0xde7d
movsd 0x18(%rsp), %xmm0
mulsd %xmm0, %xmm0
movsd 0x1f6b2(%rip), %xmm3    # 0x2d238
movapd %xmm3, %xmm1
subsd %xmm0, %xmm1
xorpd %xmm2, %xmm2
maxsd %xmm2, %xmm1
sqrtsd %xmm1, %xmm0
movsd 0x10(%rsp), %xmm1
mulsd %xmm1, %xmm1
subsd %xmm1, %xmm3
maxsd %xmm2, %xmm3
sqrtsd %xmm3, %xmm1
movsd 0x1f690(%rip), %xmm2    # 0x2d248
divsd %xmm2, %xmm0
divsd %xmm2, %xmm1
pushq $0x29
popq %r13
movq %r12, %rdi
movq %r13, %rsi
movq %r12, %rdx
movq %r13, %rcx
movq %r13, %r8
movq %r13, %r9
callq 0x97d0
leaq 0x1b48(%r14), %rdi
leaq 0x358c(%r14), %rsi
pushq $0x1
popq %r15
movq %r15, %rdx
movq %r13, %rcx
movq %r12, %r8
movq %r13, %r9
pushq %r13
pushq %r13
callq 0x9140
popq %rax
popq %rcx
leaq 0x30(%rsp), %rdi
movl $0x120, %edx            # imm = 0x120
xorl %esi, %esi
callq 0x9420
movq $-0x1a44, %rcx          # imm = 0xE5BC
movsd 0x1f62c(%rip), %xmm0    # 0x2d250
pushq $0x24
popq %rsi
movq (%rsp), %r11
movsd 0x8(%rsp), %xmm8
movsd 0x1f5fe(%rip), %xmm5    # 0x2d238
testq %rcx, %rcx
je 0xdce1
cvtss2sd 0x358c(%r14,%rcx), %xmm3
cvtss2sd 0x4fd0(%r14,%rcx), %xmm1
cvtss2sd 0x6a14(%r14,%rcx), %xmm2
mulsd %xmm3, %xmm2
divsd %xmm0, %xmm1
cvttsd2si %xmm1, %rdi
cvtsi2sd %rdi, %xmm3
cmpneqpd %xmm1, %xmm3
xorpd %xmm4, %xmm4
cmpnlepd %xmm1, %xmm4
andpd %xmm3, %xmm4
movq %xmm4, %r8
leaq (%rdi,%r8), %rax
cvtsi2sd %rax, %xmm3
subsd %xmm3, %xmm1
movapd %xmm5, %xmm3
subsd %xmm1, %xmm3
addq %rsi, %rax
xorl %edx, %edx
divq %rsi
movl %edx, %eax
mulsd %xmm2, %xmm3
addsd 0x30(%rsp,%rax,8), %xmm3
movsd %xmm3, 0x30(%rsp,%rax,8)
leaq (%rdi,%r8), %rax
addq $0x25, %rax
xorl %edx, %edx
divq %rsi
movl %edx, %eax
mulsd %xmm2, %xmm1
addsd 0x30(%rsp,%rax,8), %xmm1
movsd %xmm1, 0x30(%rsp,%rax,8)
addq $0x4, %rcx
jmp 0xdc3a
xorl %eax, %eax
movsd 0x1f4fd(%rip), %xmm1    # 0x2d1e8
cmpq $0x6, %rax
je 0xdd51
movsd 0x30(%rsp), %xmm2
movsd 0x148(%rsp), %xmm3
movq %r15, %rcx
movapd %xmm2, %xmm5
cmpq $0x24, %rcx
je 0xdd32
movapd %xmm5, %xmm4
addsd %xmm5, %xmm3
movsd 0x30(%rsp,%rcx,8), %xmm5
addsd %xmm5, %xmm3
divsd %xmm1, %xmm3
movsd %xmm3, 0x28(%rsp,%rcx,8)
incq %rcx
movapd %xmm4, %xmm3
jmp 0xdd07
addsd 0x148(%rsp), %xmm3
addsd %xmm3, %xmm2
divsd %xmm1, %xmm2
movsd %xmm2, 0x148(%rsp)
incq %rax
jmp 0xdceb
xorpd %xmm1, %xmm1
xorl %eax, %eax
cmpq $0x24, %rax
je 0xdd68
maxsd 0x30(%rsp,%rax,8), %xmm1
incq %rax
jmp 0xdd57
andq $0x0, (%r11)
mulsd 0x1f4bc(%rip), %xmm1    # 0x2d230
leaq 0x80(%r14), %r15
xorl %ecx, %ecx
movb $0x24, %dl
pushq $0x23
popq %rdi
movsd 0x1f466(%rip), %xmm2    # 0x2d1f0
movsd 0x1f4c6(%rip), %xmm3    # 0x2d258
xorl %r8d, %r8d
leal 0x25(%r8), %esi
movzbl %sil, %eax
divb %dl
cmpq $0x24, %r8
je 0xde68
movq %r8, %r9
movsd 0x30(%rsp,%r8,8), %xmm4
movq %r8, %r10
subq $0x1, %r10
cmovbq %rdi, %r10
incq %r8
incb %sil
ucomisd %xmm1, %xmm4
jbe 0xdd99
movsd 0x30(%rsp,%r10,8), %xmm5
ucomisd %xmm5, %xmm4
jbe 0xdd99
movzbl %al, %eax
imull $-0x24, %eax, %eax
movzbl %al, %eax
addl %r9d, %eax
addl $0x25, %eax
movzbl %al, %eax
movsd 0x30(%rsp,%rax,8), %xmm6
ucomisd %xmm6, %xmm4
jbe 0xdd99
movapd %xmm6, %xmm7
subsd %xmm5, %xmm7
mulsd %xmm2, %xmm7
addsd %xmm6, %xmm5
movapd %xmm4, %xmm6
addsd %xmm4, %xmm6
subsd %xmm6, %xmm5
leaq -0x1(%r8), %rax
cvtsi2sd %rax, %xmm6
divsd %xmm5, %xmm7
addsd %xmm7, %xmm6
mulsd %xmm0, %xmm6
addsd %xmm8, %xmm6
cmpl $0x0, 0x78(%r14)
movapd %xmm6, %xmm5
addsd %xmm3, %xmm5
je 0xde3e
movapd %xmm5, %xmm6
movq %rcx, %rax
shlq $0x4, %rax
movsd %xmm6, (%r15,%rax)
movsd %xmm4, 0x8(%r15,%rax)
leaq 0x1(%rcx), %rsi
movq %rsi, (%r11)
cmpq $0x3, %rcx
movq %rsi, %rcx
jb 0xdd95
jmp 0xde6b
movq %rcx, %rsi
leaq 0x20(%rip), %rcx        # 0xde92
pushq $0x10
popq %rdx
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