// File: /workspace/github_c_makefile_star2_O3/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 $0xc8, %rsp
movq %rsi, 0x28(%rsp)
movq 0x58(%rdi), %r15
movq 0x60(%rdi), %rax
movq %rax, %rcx
imulq %r15, %rcx
movq %rcx, 0x10(%rsp)
movq 0x10(%rdi), %rcx
movq 0x48(%rdi), %r12
testq %rcx, %rcx
je 0x161f4
movq 0x50(%rdi), %rdx
movq 0x10(%rsp), %r8
movq %r8, %rsi
imulq %rcx, %rsi
leaq (,%r8,4), %r11
xorl %r8d, %r8d
movq %r12, %r9
cmpq $0x0, 0x10(%rsp)
je 0x161ec
xorl %r10d, %r10d
movss (%r9), %xmm0
addss (%r9,%rsi,4), %xmm0
mulss %xmm0, %xmm0
addss (%rdx,%r10), %xmm0
movss %xmm0, (%rdx,%r10)
addq $0x4, %r9
addq $0x4, %r10
cmpq %r10, %r11
jne 0x161c4
incq %r8
cmpq %rcx, %r8
jne 0x161b9
testl %eax, %eax
jle 0x167e0
movq 0x10(%rsp), %rcx
leaq (%rcx,%rcx), %rdx
movq %rdx, 0x90(%rsp)
leaq (%rcx,%rcx,2), %rdx
movq %rdx, 0x78(%rsp)
leaq (,%rcx,4), %rbp
movq $0x0, 0x8(%rsp)
movsd 0x1c780(%rip), %xmm14   # 0x329b0
movq %rdi, 0x20(%rsp)
movq %r15, %rcx
shlq $0x20, %rcx
testq %rcx, %rcx
jle 0x167c4
movq 0x8(%rsp), %rax
cmpq $0x2, %rax
movl $0x1, %edx
cmovgeq %rax, %rdx
decq %rdx
movq %rdx, 0x98(%rsp)
leaq 0x1(%rax), %r13
leaq (,%rax,4), %rax
movq %rax, 0x80(%rsp)
movq $0x0, 0x58(%rsp)
xorl %r14d, %r14d
movq %r12, %rdx
movq %r13, 0x50(%rsp)
movq %rdx, 0xa8(%rsp)
cmpq $0x2, %r14
movl $0x1, %eax
cmovgeq %r14, %rax
leaq 0x1(%r14), %r8
movabsq $-0x100000000, %rsi     # imm = 0xFFFFFFFF00000000
addq %rsi, %rcx
sarq $0x20, %rcx
cmpq %rcx, %r8
movq %r8, 0xa0(%rsp)
cmovlq %r8, %rcx
movq 0x60(%rdi), %rdx
shlq $0x20, %rdx
addq %rsi, %rdx
sarq $0x20, %rdx
cmpq %rdx, %r13
cmovlq %r13, %rdx
movq 0x50(%rdi), %rsi
movq %r15, %r9
imulq 0x98(%rsp), %r9
leaq (%rsi,%rax,4), %rax
xorps %xmm0, %xmm0
cvtss2sd -0x4(%rax,%r9,4), %xmm0
leaq (%rsi,%r14,4), %r8
xorps %xmm7, %xmm7
cvtss2sd (%r8,%r9,4), %xmm7
leaq (%rsi,%rcx,4), %rcx
cvtss2sd (%rcx,%r9,4), %xmm8
movq %r15, %r13
imulq 0x8(%rsp), %r13
xorps %xmm5, %xmm5
cvtss2sd -0x4(%rax,%r13,4), %xmm5
xorps %xmm1, %xmm1
cvtss2sd (%r8,%r13,4), %xmm1
xorps %xmm2, %xmm2
cvtss2sd (%rcx,%r13,4), %xmm2
imulq %r15, %rdx
cvtss2sd -0x4(%rax,%rdx,4), %xmm6
cvtss2sd (%r8,%rdx,4), %xmm4
xorps %xmm3, %xmm3
cvtss2sd (%rcx,%rdx,4), %xmm3
movl 0x18(%rdi), %ebx
addsd %xmm7, %xmm0
addsd %xmm5, %xmm0
addsd %xmm1, %xmm0
addsd %xmm14, %xmm0
ucomisd 0x1bcc9(%rip), %xmm0    # 0x32030
movsd %xmm1, 0x18(%rsp)
movsd %xmm2, 0x38(%rsp)
movsd %xmm3, 0x70(%rsp)
movsd %xmm4, 0x30(%rsp)
movsd %xmm5, 0x68(%rsp)
movsd %xmm6, 0x60(%rsp)
jb 0x16393
sqrtsd %xmm0, %xmm0
jmp 0x163cd
movsd %xmm7, 0x40(%rsp)
movsd %xmm8, 0x88(%rsp)
callq 0x9990
movsd 0x88(%rsp), %xmm8
movsd 0x40(%rsp), %xmm7
movsd 0x38(%rsp), %xmm2
movsd 0x18(%rsp), %xmm1
movsd 0x1c5e3(%rip), %xmm14   # 0x329b0
movapd %xmm0, 0xb0(%rsp)
addsd %xmm8, %xmm7
addsd %xmm1, %xmm7
addsd %xmm2, %xmm7
addsd %xmm14, %xmm7
ucomisd 0x1bc40(%rip), %xmm7    # 0x32030
jb 0x163fb
xorps %xmm0, %xmm0
sqrtsd %xmm7, %xmm0
jmp 0x16413
movapd %xmm7, %xmm0
callq 0x9990
movsd 0x18(%rsp), %xmm1
movsd 0x1c59d(%rip), %xmm14   # 0x329b0
movapd %xmm0, 0x40(%rsp)
movsd 0x30(%rsp), %xmm3
movsd 0x68(%rsp), %xmm0
movsd 0x60(%rsp), %xmm2
addsd %xmm1, %xmm0
addsd %xmm2, %xmm0
addsd %xmm3, %xmm0
addsd %xmm14, %xmm0
ucomisd 0x1bbec(%rip), %xmm0    # 0x32030
jb 0x1644f
xorps %xmm4, %xmm4
sqrtsd %xmm0, %xmm4
jmp 0x1646d
callq 0x9990
movsd 0x30(%rsp), %xmm3
movsd 0x18(%rsp), %xmm1
movsd 0x1c547(%rip), %xmm14   # 0x329b0
movapd %xmm0, %xmm4
movsd 0x38(%rsp), %xmm0
movsd 0x70(%rsp), %xmm2
addsd %xmm0, %xmm1
addsd %xmm3, %xmm1
addsd %xmm2, %xmm1
addsd %xmm14, %xmm1
ucomisd 0x1bb9e(%rip), %xmm1    # 0x32030
jb 0x1649d
xorps %xmm0, %xmm0
sqrtsd %xmm1, %xmm0
jmp 0x164bb
movapd %xmm1, %xmm0
movsd %xmm4, 0x18(%rsp)
callq 0x9990
movsd 0x18(%rsp), %xmm4
movsd 0x1c4f5(%rip), %xmm14   # 0x329b0
movq 0x20(%rsp), %rdi
movapd 0x40(%rsp), %xmm1
testl %ebx, %ebx
je 0x164d0
movapd %xmm4, %xmm2
jmp 0x164d8
movapd %xmm1, %xmm2
movapd %xmm4, %xmm1
movq 0x10(%rdi), %rdx
movq 0x90(%rsp), %rax
imulq %rdx, %rax
movl (%rdi), %ecx
testq %rdx, %rdx
je 0x16733
unpcklpd 0xb0(%rsp), %xmm2       # xmm2 = xmm2[0],mem[0]
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
movapd 0x1c4b8(%rip), %xmm3    # 0x329c0
movapd %xmm3, %xmm1
divpd %xmm0, %xmm1
movapd %xmm3, %xmm0
divpd %xmm2, %xmm0
movq 0x78(%rsp), %rdi
imulq %rdx, %rdi
movq %rdx, %r8
imulq 0x10(%rsp), %r8
imulq 0x80(%rsp), %r15
movq 0x28(%rsp), %rsi
leaq (%rsi,%r15), %r9
movq %rbp, %r10
imulq %rdx, %r10
leaq (%r9,%r10), %r11
addq %r12, %r10
xorpd %xmm2, %xmm2
movq 0x58(%rsp), %rsi
xorpd %xmm3, %xmm3
movq 0x50(%rsp), %r13
movss (%r12,%rsi), %xmm4
movss (%r10,%rsi), %xmm5
unpcklps %xmm4, %xmm5            # xmm5 = xmm5[0],xmm4[0],xmm5[1],xmm4[1]
cvtps2pd %xmm5, %xmm6
movapd %xmm6, %xmm10
shufpd $0x1, %xmm6, %xmm10     # xmm10 = xmm10[1],xmm6[0]
movapd %xmm0, %xmm9
mulpd %xmm10, %xmm9
mulpd %xmm1, %xmm10
movapd %xmm0, %xmm8
mulpd %xmm6, %xmm8
mulpd %xmm1, %xmm6
movapd %xmm10, %xmm7
addpd %xmm6, %xmm7
movapd %xmm9, %xmm5
addpd %xmm8, %xmm5
movapd 0x1c41e(%rip), %xmm11   # 0x329d0
movapd %xmm11, %xmm4
minpd %xmm5, %xmm4
movapd %xmm11, %xmm5
minpd %xmm7, %xmm5
testl %ecx, %ecx
je 0x166ab
cmpl $0x1, %ecx
jne 0x166f4
movsd 0x1c3db(%rip), %xmm7    # 0x329b8
movapd %xmm7, %xmm15
minsd %xmm6, %xmm15
movapd %xmm7, %xmm12
minsd %xmm10, %xmm12
unpckhpd %xmm10, %xmm10          # xmm10 = xmm10[1,1]
movapd %xmm7, %xmm11
minsd %xmm10, %xmm11
movapd %xmm7, %xmm10
minsd %xmm8, %xmm10
shufpd $0x1, %xmm9, %xmm8      # xmm8 = xmm8[1],xmm9[0]
unpckhpd %xmm9, %xmm9            # xmm9 = xmm9[1,1]
movapd %xmm7, %xmm13
minsd %xmm9, %xmm13
unpckhpd %xmm6, %xmm6            # xmm6 = xmm6[1,1]
minsd %xmm6, %xmm7
movapd 0x1c3a1(%rip), %xmm6    # 0x329d0
minpd %xmm8, %xmm6
movapd %xmm6, %xmm8
unpckhpd %xmm6, %xmm8            # xmm8 = xmm8[1],xmm6[1]
addsd %xmm6, %xmm8
addsd %xmm7, %xmm8
addsd %xmm12, %xmm8
mulsd 0x1bb8a(%rip), %xmm8    # 0x321e0
movapd %xmm4, %xmm6
shufpd $0x1, %xmm13, %xmm6     # xmm6 = xmm6[1],xmm13[0]
movapd %xmm4, %xmm9
unpcklpd %xmm10, %xmm9           # xmm9 = xmm9[0],xmm10[0]
addpd %xmm6, %xmm9
movapd %xmm5, %xmm10
shufpd $0x1, %xmm11, %xmm10    # xmm10 = xmm10[1],xmm11[0]
addpd %xmm9, %xmm10
movapd %xmm5, %xmm6
unpcklpd %xmm15, %xmm6           # xmm6 = xmm6[0],xmm15[0]
addpd %xmm10, %xmm6
xorps %xmm7, %xmm7
cvtsd2ss %xmm8, %xmm7
mulpd 0x1ba53(%rip), %xmm6    # 0x320f0
movss %xmm7, (%r9,%rsi)
movq %r8, %rbx
movq %rax, %r14
jmp 0x166d4
movapd %xmm4, %xmm6
unpckhpd %xmm4, %xmm6            # xmm6 = xmm6[1],xmm4[1]
cvtsd2ss %xmm6, %xmm6
movss %xmm6, (%r9,%rsi)
xorps %xmm6, %xmm6
cvtsd2ss %xmm4, %xmm6
movss %xmm6, (%r11,%rsi)
movq %rax, %rbx
movq %rdi, %r14
movapd %xmm5, %xmm6
xorps %xmm7, %xmm7
cvtsd2ss %xmm6, %xmm7
movhlps %xmm6, %xmm6            # xmm6 = xmm6[1,1]
cvtsd2ss %xmm6, %xmm6
leaq (%r9,%rbx,4), %rbx
movss %xmm6, (%rsi,%rbx)
leaq (%r9,%r14,4), %rbx
movss %xmm7, (%rsi,%rbx)
addpd %xmm5, %xmm3
addpd %xmm4, %xmm2
addq %rbp, %rsi
decq %rdx
jne 0x1655c
movapd 0x1c2d0(%rip), %xmm0    # 0x329e0
mulpd %xmm0, %xmm3
mulpd %xmm0, %xmm2
cvtpd2ps %xmm2, %xmm0
cvtpd2ps %xmm3, %xmm1
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
addq 0x28(%rsp), %rsi
addq %r15, %rsi
movq 0x20(%rsp), %rdi
jmp 0x16749
movq 0x28(%rsp), %rdx
leaq (%rdx,%r14,4), %rdx
leaq (%rdx,%r13,4), %rsi
xorpd %xmm0, %xmm0
movq 0x50(%rsp), %r13
cmpl $0x1, %ecx
movq 0xa8(%rsp), %rdx
jne 0x1678a
leaq (%rsi,%rax,4), %rax
movapd %xmm0, %xmm1
shufps $0x55, %xmm0, %xmm1     # xmm1 = xmm1[1,1],xmm0[1,1]
movss %xmm1, (%rax)
movq 0x10(%rsp), %rcx
leaq (%rax,%rcx,4), %rax
movss %xmm0, (%rax)
leaq (%rax,%rcx,4), %rax
movaps %xmm0, %xmm1
shufps $0xff, %xmm0, %xmm1     # xmm1 = xmm1[3,3],xmm0[3,3]
movss %xmm1, (%rax)
movhlps %xmm0, %xmm0            # xmm0 = xmm0[1,1]
movss %xmm0, (%rax,%rcx,4)
addq $0x4, %rdx
movq 0x58(%rdi), %r15
movq %r15, %rcx
shlq $0x20, %rcx
movslq %r15d, %rax
addq $0x4, 0x58(%rsp)
movq 0xa0(%rsp), %rsi
movq %rsi, %r14
cmpq %rax, %rsi
jl 0x1628a
movq 0x60(%rdi), %rax
movq %rdx, %r12
movq %r13, 0x8(%rsp)
jmp 0x167d4
movq 0x8(%rsp), %rdx
incq %rdx
movq %rdx, 0x8(%rsp)
movq %rdx, %r13
movslq %eax, %rcx
cmpq %rcx, %r13
jl 0x16235
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop