// File: /workspace/github_c_makefile_star2_O2/zpole[P]IICV/vl/hog.c
// Function: vl_hog_extract
void
vl_hog_extract (VlHog * self, float * features)
{
  vl_index x, y ;
  vl_uindex k ;
  vl_size hogStride = self->hogWidth * self->hogHeight ;

  assert(features) ;

#define at(x,y,k) (self->hog[(x) + (y) * self->hogWidth + (k) * hogStride])
#define atNorm(x,y) (self->hogNorm[(x) + (y) * self->hogWidth])

  /*
   Compute the squared L2 norm of the unoriented version of each HOG
   cell histogram. The unoriented version is obtained by folding
   the 2*numOrientations compotnent into numOrientations only.
   */
  {
    float const * iter = self->hog ;
    for (k = 0 ; k < self->numOrientations ; ++k) {
      float * niter = self->hogNorm ;
      float * niterEnd = self->hogNorm + self->hogWidth * self->hogHeight ;
      vl_size stride = self->hogWidth*self->hogHeight*self->numOrientations ;
      while (niter != niterEnd) {
        float h1 = *iter ;
        float h2 = *(iter + stride) ;
        float h = h1 + h2 ;
        *niter += h * h ;
        niter++ ;
        iter++ ;
      }
    }
  }

  /*
   HOG block-normalisation.

   The Dalal-Triggs implementation computes a normalized descriptor for
   each block of 2x2 cells, by stacking the histograms of each cell
   into a vector and L2-normalizing and truncating the result.
   
   Each block-level descriptor is then decomposed back into cells
   and corresponding parts are stacked into cell-level descritpors.
   Each HOG cell is contained in exactly
   four 2x2 cell blocks. For example, the cell number 5 in the following
   figure is contained in blocks 1245, 2356, 4578, 5689:

   +---+---+---+
   | 1 | 2 | 3 |
   +---+---+---+
   | 4 | 5 | 6 |
   +---+---+---+
   | 7 | 8 | 9 |
   +---+---+---+

   Hence, when block-level descriptors are decomposed back
   into cells, each cell receives contributions from four blocks. So,
   if each cell started with a D-dimensional histogram, it
   ends up with a 4D dimesional descriptor vector.

   Note however that this is just a convenient way of rewriting the 
   blocks as per-cell contributions, but the block information
   is unchanged. In particular, barring boundary effects,
   in an array of H x W cells there are approximately HW blocks;
   hence the L2 norm of all the blocks stacked is approximately HW
   (because individual blocks are L2-normalized). Since this does
   not change in the final HOG descriptor,
   the L2 norm of the HOG descriptor of an image should be approximately
   the same as the area of the image divided by the
   area of a HOG cell. This can be used as a sanity check.

   The UoCTTI variant differs in some non-negligible ways. First, 
   it includes both oriented and unoriented histograms, as well
   as four components capturing texture. Second, and most importantly, 
   it merges the four chunks of block-level descirptors landing in
   each cell into one by taking their average. This makes sense
   because, ultimately, these four sub-descriptors are identical
   to the original cell histogram, just with four different normalisations
   applied.
   */
  {
    float const * iter = self->hog ;
    for (y = 0 ; y < (signed)self->hogHeight ; ++y) {
      for (x = 0 ; x < (signed)self->hogWidth ; ++x) {

        /* norm of upper-left, upper-right, ... cells */
        vl_index xm = VL_MAX(x - 1, 0) ;
        vl_index xp = VL_MIN(x + 1, (signed)self->hogWidth - 1) ;
        vl_index ym = VL_MAX(y - 1, 0) ;
        vl_index yp = VL_MIN(y + 1, (signed)self->hogHeight - 1) ;

        double norm1 = atNorm(xm,ym) ;
        double norm2 = atNorm(x,ym) ;
        double norm3 = atNorm(xp,ym) ;
        double norm4 = atNorm(xm,y) ;
        double norm5 = atNorm(x,y) ;
        double norm6 = atNorm(xp,y) ;
        double norm7 = atNorm(xm,yp) ;
        double norm8 = atNorm(x,yp) ;
        double norm9 = atNorm(xp,yp) ;

        double factor1, factor2, factor3, factor4 ;

        double t1 = 0 ;
        double t2 = 0 ;
        double t3 = 0 ;
        double t4 = 0 ;

        float * oiter = features + x + self->hogWidth * y ;

        /* each factor is the inverse of the l2 norm of one of the 2x2 blocks surrounding
           cell x,y */
#if 0
        if (self->transposed) {
          /* if the image is transposed, y and x are swapped */
          factor1 = 1.0 / VL_MAX(sqrt(norm1 + norm2 + norm4 + norm5), 1e-10) ;
          factor3 = 1.0 / VL_MAX(sqrt(norm2 + norm3 + norm5 + norm6), 1e-10) ;
          factor2 = 1.0 / VL_MAX(sqrt(norm4 + norm5 + norm7 + norm8), 1e-10) ;
          factor4 = 1.0 / VL_MAX(sqrt(norm5 + norm6 + norm8 + norm9), 1e-10) ;
        } else {
          factor1 = 1.0 / VL_MAX(sqrt(norm1 + norm2 + norm4 + norm5), 1e-10) ;
          factor2 = 1.0 / VL_MAX(sqrt(norm2 + norm3 + norm5 + norm6), 1e-10) ;
          factor3 = 1.0 / VL_MAX(sqrt(norm4 + norm5 + norm7 + norm8), 1e-10) ;
          factor4 = 1.0 / VL_MAX(sqrt(norm5 + norm6 + norm8 + norm9), 1e-10) ;
        }
#else
        /* as implemented in UOCTTI code */
        if (self->transposed) {
          /* if the image is transposed, y and x are swapped */
          factor1 = 1.0 / sqrt(norm1 + norm2 + norm4 + norm5 + 1e-4) ;
          factor3 = 1.0 / sqrt(norm2 + norm3 + norm5 + norm6 + 1e-4) ;
          factor2 = 1.0 / sqrt(norm4 + norm5 + norm7 + norm8 + 1e-4) ;
          factor4 = 1.0 / sqrt(norm5 + norm6 + norm8 + norm9 + 1e-4) ;
        } else {
          factor1 = 1.0 / sqrt(norm1 + norm2 + norm4 + norm5 + 1e-4) ;
          factor2 = 1.0 / sqrt(norm2 + norm3 + norm5 + norm6 + 1e-4) ;
          factor3 = 1.0 / sqrt(norm4 + norm5 + norm7 + norm8 + 1e-4) ;
          factor4 = 1.0 / sqrt(norm5 + norm6 + norm8 + norm9 + 1e-4) ;
        }
#endif

        for (k = 0 ; k < self->numOrientations ; ++k) {
          double ha = iter[hogStride * k] ;
          double hb = iter[hogStride * (k + self->numOrientations)] ;
          double hc ;

          double ha1 = factor1 * ha ;
          double ha2 = factor2 * ha ;
          double ha3 = factor3 * ha ;
          double ha4 = factor4 * ha ;

          double hb1 = factor1 * hb ;
          double hb2 = factor2 * hb ;
          double hb3 = factor3 * hb ;
          double hb4 = factor4 * hb ;

          double hc1 = ha1 + hb1 ;
          double hc2 = ha2 + hb2 ;
          double hc3 = ha3 + hb3 ;
          double hc4 = ha4 + hb4 ;

          ha1 = VL_MIN(0.2, ha1) ;
          ha2 = VL_MIN(0.2, ha2) ;
          ha3 = VL_MIN(0.2, ha3) ;
          ha4 = VL_MIN(0.2, ha4) ;

          hb1 = VL_MIN(0.2, hb1) ;
          hb2 = VL_MIN(0.2, hb2) ;
          hb3 = VL_MIN(0.2, hb3) ;
          hb4 = VL_MIN(0.2, hb4) ;

          hc1 = VL_MIN(0.2, hc1) ;
          hc2 = VL_MIN(0.2, hc2) ;
          hc3 = VL_MIN(0.2, hc3) ;
          hc4 = VL_MIN(0.2, hc4) ;

          t1 += hc1 ;
          t2 += hc2 ;
          t3 += hc3 ;
          t4 += hc4 ;

          switch (self->variant) {
            case VlHogVariantUoctti :
              ha = 0.5 * (ha1 + ha2 + ha3 + ha4) ;
              hb = 0.5 * (hb1 + hb2 + hb3 + hb4) ;
              hc = 0.5 * (hc1 + hc2 + hc3 + hc4) ;
              *oiter = ha ;
              *(oiter + hogStride * self->numOrientations) = hb ;
              *(oiter + 2 * hogStride * self->numOrientations) = hc ;
              break ;

            case VlHogVariantDalalTriggs :
              *oiter = hc1 ;
              *(oiter + hogStride * self->numOrientations) = hc2 ;
              *(oiter + 2 * hogStride * self->numOrientations) = hc3 ;
              *(oiter + 3 * hogStride * self->numOrientations) = hc4 ;
              break ;
          }
          oiter += hogStride ;

        } /* next orientation */

        switch (self->variant) {
          case VlHogVariantUoctti :
            oiter += 2 * hogStride * self->numOrientations ;
            *oiter = (1.0f/sqrtf(18.0f)) * t1 ; oiter += hogStride ;
            *oiter = (1.0f/sqrtf(18.0f)) * t2 ; oiter += hogStride ;
            *oiter = (1.0f/sqrtf(18.0f)) * t3 ; oiter += hogStride ;
            *oiter = (1.0f/sqrtf(18.0f)) * t4 ; oiter += hogStride ;
            break ;

          case VlHogVariantDalalTriggs :
            break ;
        }
        ++iter ;
      } /* next x */
    } /* next y */
  } /* block normalization */
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rsi, 0x40(%rsp)
movq %rdi, %r14
movq 0x58(%rdi), %r13
movq 0x60(%rdi), %rax
movq %rax, %rsi
imulq %r13, %rsi
movq 0x10(%rdi), %rcx
movq 0x48(%rdi), %r12
leaq (,%rsi,4), %rdx
movq %rsi, (%rsp)
imulq %rcx, %rsi
xorl %edi, %edi
movq %r12, %r8
cmpq %rcx, %rdi
je 0x14aed
movq 0x50(%r14), %r9
movq %rdx, %r10
testq %r10, %r10
je 0x14ae8
movss (%r8), %xmm0
addss (%r8,%rsi,4), %xmm0
mulss %xmm0, %xmm0
addss (%r9), %xmm0
movss %xmm0, (%r9)
addq $0x4, %r9
addq $0x4, %r8
addq $-0x4, %r10
jmp 0x14abc
incq %rdi
jmp 0x14ab0
movq (%rsp), %rcx
leaq (%rcx,%rcx), %rdx
movq %rdx, 0x88(%rsp)
leaq (%rcx,%rcx,2), %rdx
movq %rdx, 0x80(%rsp)
leaq (,%rcx,4), %rbp
leaq (,%rcx,8), %rcx
movq %rcx, 0x68(%rsp)
movq $0x0, 0x30(%rsp)
xorl %r9d, %r9d
cltq
cmpq %rax, %r9
jge 0x1510f
cmpq $0x2, %r9
pushq $0x1
popq %rax
cmovgeq %r9, %rax
decq %rax
movq %rax, 0x90(%rsp)
leaq 0x1(%r9), %rax
movq %rax, 0x38(%rsp)
movq $0x0, 0x48(%rsp)
movq %r12, %rdx
xorl %eax, %eax
movq %r9, 0x98(%rsp)
movslq %r13d, %rcx
cmpq %rcx, %rax
jge 0x150f8
movq %rdx, 0xb8(%rsp)
movq %r13, %rcx
shlq $0x20, %rcx
cmpq $0x2, %rax
pushq $0x1
popq %rdx
cmovgeq %rax, %rdx
leaq 0x1(%rax), %r8
movabsq $-0x100000000, %rdi     # imm = 0xFFFFFFFF00000000
addq %rdi, %rcx
sarq $0x20, %rcx
cmpq %rcx, %r8
movq %r8, 0xb0(%rsp)
cmovlq %r8, %rcx
movq 0x60(%r14), %rsi
shlq $0x20, %rsi
addq %rdi, %rsi
sarq $0x20, %rsi
movq 0x38(%rsp), %rdi
cmpq %rsi, %rdi
cmovlq %rdi, %rsi
movq 0x50(%r14), %rdi
movq %r13, %r8
imulq 0x90(%rsp), %r8
leaq (%rdi,%rdx,4), %rdx
cvtss2sd -0x4(%rdx,%r8,4), %xmm0
leaq (%rdi,%rax,4), %rax
cvtss2sd (%rax,%r8,4), %xmm4
leaq (%rdi,%rcx,4), %rcx
cvtss2sd (%rcx,%r8,4), %xmm5
movq %r13, %rdi
imulq %r9, %rdi
cvtss2sd -0x4(%rdx,%rdi,4), %xmm3
cvtss2sd (%rax,%rdi,4), %xmm1
cvtss2sd (%rcx,%rdi,4), %xmm2
movsd %xmm2, 0x10(%rsp)
imulq %r13, %rsi
cvtss2sd -0x4(%rdx,%rsi,4), %xmm2
movsd %xmm2, 0xa0(%rsp)
cvtss2sd (%rax,%rsi,4), %xmm2
movsd %xmm2, 0x50(%rsp)
cvtss2sd (%rcx,%rsi,4), %xmm2
movsd %xmm2, 0xa8(%rsp)
movl 0x18(%r14), %r15d
addsd %xmm4, %xmm0
movsd %xmm3, 0x20(%rsp)
addsd %xmm3, %xmm0
addsd %xmm1, %xmm0
addsd 0x18d0b(%rip), %xmm0    # 0x2d970
ucomisd 0x18393(%rip), %xmm0    # 0x2d000
movsd %xmm1, 0x8(%rsp)
jb 0x14c7b
sqrtsd %xmm0, %xmm0
jmp 0x14c9e
movsd %xmm4, 0x78(%rsp)
movsd %xmm5, 0x70(%rsp)
callq 0x9a00
movsd 0x70(%rsp), %xmm5
movsd 0x78(%rsp), %xmm4
movsd 0x8(%rsp), %xmm1
movapd %xmm0, 0xc0(%rsp)
addsd %xmm5, %xmm4
addsd %xmm1, %xmm4
addsd 0x10(%rsp), %xmm4
addsd 0x18cb3(%rip), %xmm4    # 0x2d970
ucomisd 0x1833b(%rip), %xmm4    # 0x2d000
jb 0x14ccd
sqrtsd %xmm4, %xmm2
jmp 0x14ce0
movapd %xmm4, %xmm0
callq 0x9a00
movsd 0x8(%rsp), %xmm1
movapd %xmm0, %xmm2
movsd 0x20(%rsp), %xmm0
addsd %xmm1, %xmm0
addsd 0xa0(%rsp), %xmm0
addsd 0x50(%rsp), %xmm0
addsd 0x18c6f(%rip), %xmm0    # 0x2d970
ucomisd 0x182f7(%rip), %xmm0    # 0x2d000
movapd %xmm2, 0x20(%rsp)
jb 0x14d17
sqrtsd %xmm0, %xmm2
jmp 0x14d26
callq 0x9a00
movsd 0x8(%rsp), %xmm1
movapd %xmm0, %xmm2
addsd 0x10(%rsp), %xmm1
addsd 0x50(%rsp), %xmm1
addsd 0xa8(%rsp), %xmm1
addsd 0x18c2d(%rip), %xmm1    # 0x2d970
ucomisd 0x182b5(%rip), %xmm1    # 0x2d000
jb 0x14d53
sqrtsd %xmm1, %xmm0
jmp 0x14d68
movapd %xmm1, %xmm0
movsd %xmm2, 0x10(%rsp)
callq 0x9a00
movsd 0x10(%rsp), %xmm2
movapd 0x18c2f(%rip), %xmm14   # 0x2d9a0
movsd 0x18bfe(%rip), %xmm15   # 0x2d978
movapd 0x20(%rsp), %xmm3
testl %r15d, %r15d
je 0x14d8b
movapd %xmm2, %xmm1
jmp 0x14d93
movapd %xmm3, %xmm1
movapd %xmm2, %xmm3
movapd 0xc0(%rsp), %xmm2
unpcklpd %xmm1, %xmm2            # xmm2 = xmm2[0],xmm1[0]
unpcklpd %xmm3, %xmm0            # xmm0 = xmm0[0],xmm3[0]
movapd 0x18be4(%rip), %xmm4    # 0x2d990
movapd %xmm4, %xmm1
divpd %xmm0, %xmm1
movapd %xmm1, 0x10(%rsp)
divpd %xmm2, %xmm4
movapd %xmm4, 0x50(%rsp)
movq 0x10(%r14), %rax
movq 0x88(%rsp), %rbx
imulq %rax, %rbx
movq 0x80(%rsp), %rdi
imulq %rax, %rdi
movq %rax, %r8
imulq (%rsp), %r8
movq %rbp, %r9
imulq %rax, %r9
leaq (%r12,%r9), %r10
imulq 0x30(%rsp), %r13
movq 0x40(%rsp), %rcx
addq %r13, %rcx
addq %rcx, %r9
xorpd %xmm5, %xmm5
movq 0x48(%rsp), %rdx
movq %rax, %r11
xorpd %xmm4, %xmm4
xorpd %xmm3, %xmm3
xorpd %xmm0, %xmm0
subq $0x1, %r11
jb 0x15041
movss (%r10,%rdx), %xmm6
movss (%r12,%rdx), %xmm7
unpcklps %xmm6, %xmm7            # xmm7 = xmm7[0],xmm6[0],xmm7[1],xmm6[1]
cvtps2pd %xmm7, %xmm10
movapd %xmm10, %xmm9
unpcklpd %xmm10, %xmm9           # xmm9 = xmm9[0],xmm10[0]
movapd 0x50(%rsp), %xmm1
mulpd %xmm1, %xmm9
movapd %xmm10, %xmm11
unpckhpd %xmm10, %xmm11          # xmm11 = xmm11[1],xmm10[1]
mulpd %xmm1, %xmm11
movapd %xmm9, %xmm8
addpd %xmm11, %xmm8
movapd %xmm14, %xmm6
cmpltpd %xmm8, %xmm6
movmskpd %xmm6, %esi
movapd %xmm15, %xmm6
testb $0x1, %sil
jne 0x14e86
movapd %xmm8, %xmm6
movapd %xmm15, %xmm7
testb $0x2, %sil
jne 0x14e9b
unpckhpd %xmm8, %xmm8            # xmm8 = xmm8[1,1]
movapd %xmm8, %xmm7
movapd 0x10(%rsp), %xmm1
movapd %xmm1, %xmm13
mulpd %xmm10, %xmm13
shufpd $0x1, %xmm10, %xmm10    # xmm10 = xmm10[1,0]
mulpd %xmm1, %xmm10
movapd %xmm13, %xmm12
addpd %xmm10, %xmm12
movapd %xmm14, %xmm8
minpd %xmm12, %xmm8
movl (%r14), %esi
testl %esi, %esi
je 0x14fd3
cmpl $0x1, %esi
jne 0x15022
movapd %xmm3, %xmm2
movapd %xmm0, %xmm3
movapd %xmm15, %xmm12
minsd %xmm10, %xmm12
movapd %xmm15, %xmm14
minsd %xmm13, %xmm14
unpckhpd %xmm13, %xmm13          # xmm13 = xmm13[1,1]
movsd 0x18a70(%rip), %xmm15   # 0x2d978
minsd %xmm13, %xmm15
movsd 0x18a62(%rip), %xmm13   # 0x2d978
minsd %xmm11, %xmm13
unpckhpd %xmm11, %xmm11          # xmm11 = xmm11[1,1]
movsd 0x18a50(%rip), %xmm0    # 0x2d978
minsd %xmm11, %xmm0
unpckhpd %xmm10, %xmm10          # xmm10 = xmm10[1,1]
movsd 0x18a3d(%rip), %xmm11   # 0x2d978
minsd %xmm10, %xmm11
movapd 0x18a58(%rip), %xmm1    # 0x2d9a0
minpd %xmm9, %xmm1
movapd %xmm1, %xmm10
unpckhpd %xmm1, %xmm10           # xmm10 = xmm10[1],xmm1[1]
addsd %xmm1, %xmm10
addsd %xmm11, %xmm10
addsd %xmm14, %xmm10
movapd 0x18a31(%rip), %xmm14   # 0x2d9a0
mulsd 0x18248(%rip), %xmm10   # 0x2d1c0
movapd %xmm6, %xmm1
unpcklpd %xmm13, %xmm1           # xmm1 = xmm1[0],xmm13[0]
movapd %xmm7, %xmm9
unpcklpd %xmm0, %xmm9            # xmm9 = xmm9[0],xmm0[0]
addpd %xmm1, %xmm9
movapd %xmm8, %xmm0
shufpd $0x1, %xmm15, %xmm0     # xmm0 = xmm0[1],xmm15[0]
movsd 0x189d4(%rip), %xmm15   # 0x2d978
addpd %xmm9, %xmm0
movapd %xmm8, %xmm9
unpcklpd %xmm12, %xmm9           # xmm9 = xmm9[0],xmm12[0]
addpd %xmm0, %xmm9
cvtsd2ss %xmm10, %xmm0
mulpd 0x180ea(%rip), %xmm9    # 0x2d0b0
movss %xmm0, (%rcx,%rdx)
movq %r8, %r15
movq %rbx, %rsi
jmp 0x14ff9
movapd %xmm3, %xmm2
movapd %xmm0, %xmm3
cvtsd2ss %xmm6, %xmm0
movss %xmm0, (%rcx,%rdx)
cvtsd2ss %xmm7, %xmm0
movss %xmm0, (%r9,%rdx)
movq %rbx, %r15
movq %rdi, %rsi
movapd %xmm8, %xmm9
cvtsd2ss %xmm9, %xmm0
movhlps %xmm9, %xmm9            # xmm9 = xmm9[1,1]
cvtsd2ss %xmm9, %xmm1
leaq (%rcx,%r15,4), %r15
movss %xmm1, (%rdx,%r15)
leaq (%rcx,%rsi,4), %rsi
movss %xmm0, (%rdx,%rsi)
movapd %xmm3, %xmm0
movapd %xmm2, %xmm3
addsd %xmm6, %xmm5
addsd %xmm7, %xmm4
addsd %xmm8, %xmm0
unpckhpd %xmm8, %xmm8            # xmm8 = xmm8[1,1]
addsd %xmm8, %xmm3
addq %rbp, %rdx
jmp 0x14e1c
cmpl $0x1, (%r14)
jne 0x150cd
movq 0x68(%rsp), %rsi
imulq %rax, %rsi
addq %r13, %rsi
addq 0x40(%rsp), %rsi
movapd %xmm0, %xmm2
movsd 0x18918(%rip), %xmm1    # 0x2d980
mulsd %xmm1, %xmm5
cvtsd2ss %xmm5, %xmm0
movss %xmm0, (%rdx,%rsi)
leaq 0x4(,%rax,8), %rsi
movq (%rsp), %rdi
imulq %rdi, %rsi
mulsd %xmm1, %xmm4
cvtsd2ss %xmm4, %xmm0
addq %rcx, %rsi
movss %xmm0, (%rdx,%rsi)
leaq 0x8(,%rax,8), %rsi
imulq %rdi, %rsi
addq %rcx, %rsi
mulsd %xmm1, %xmm3
cvtsd2ss %xmm3, %xmm0
movss %xmm0, (%rdx,%rsi)
leaq 0xc(,%rax,8), %rax
imulq %rdi, %rax
addq %rcx, %rax
mulsd %xmm1, %xmm2
cvtsd2ss %xmm2, %xmm0
movss %xmm0, (%rdx,%rax)
movq 0xb8(%rsp), %rdx
addq $0x4, %rdx
movq 0x58(%r14), %r13
addq $0x4, 0x48(%rsp)
movq 0xb0(%rsp), %rax
movq 0x98(%rsp), %r9
jmp 0x14b6a
movq 0x60(%r14), %rax
addq $0x4, 0x30(%rsp)
movq %rdx, %r12
movq 0x38(%rsp), %r9
jmp 0x14b2a
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nopl (%rax)