// File: /workspace/github_c_makefile_star2_O1/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 %rdi, %rbp
movq 0x58(%rdi), %rax
imulq 0x60(%rdi), %rax
movq %rax, 0x8(%rsp)
movq %rsi, 0x30(%rsp)
movq 0x10(%rdi), %rax
movq 0x48(%rdi), %r12
testq %rax, %rax
je 0x1624c
movq 0x50(%rbp), %rcx
movq 0x8(%rsp), %rsi
movq %rsi, %rdx
imulq %rax, %rdx
leaq (,%rsi,4), %rsi
xorl %edi, %edi
movq %r12, %r8
cmpq $0x0, 0x8(%rsp)
je 0x16244
xorl %r9d, %r9d
movss (%r8), %xmm0
addss (%r8,%rdx,4), %xmm0
mulss %xmm0, %xmm0
addss (%rcx,%r9), %xmm0
movss %xmm0, (%rcx,%r9)
addq $0x4, %r8
addq $0x4, %r9
cmpq %r9, %rsi
jne 0x1621c
incq %rdi
cmpq %rax, %rdi
jne 0x16211
cmpl $0x0, 0x60(%rbp)
jle 0x16855
movq 0x8(%rsp), %rax
leaq (%rax,%rax), %rcx
movq %rcx, 0x48(%rsp)
leaq (%rax,%rax,2), %rcx
movq %rcx, 0xb8(%rsp)
leaq (,%rax,4), %r14
movq $0x0, 0x68(%rsp)
movsd 0x1d726(%rip), %xmm14   # 0x339b0
movq $0x0, 0x20(%rsp)
movq %rbp, 0x90(%rsp)
movq 0x58(%rbp), %rbx
movq %rbx, %rax
shlq $0x20, %rax
testq %rax, %rax
jle 0x1682b
movq 0x20(%rsp), %rcx
cmpq $0x2, %rcx
movl $0x1, %edx
cmovgeq %rcx, %rdx
decq %rdx
movq %rdx, 0xa8(%rsp)
incq %rcx
movq %rcx, 0xa0(%rsp)
movq $0x0, 0x70(%rsp)
xorl %r15d, %r15d
movq %r12, 0x28(%rsp)
cmpq $0x2, %r15
movl $0x1, %ecx
cmovgeq %r15, %rcx
leaq 0x1(%r15), %rdi
movabsq $-0x100000000, %rsi     # imm = 0xFFFFFFFF00000000
addq %rsi, %rax
sarq $0x20, %rax
cmpq %rax, %rdi
movq %rdi, 0xb0(%rsp)
cmovlq %rdi, %rax
movq 0x60(%rbp), %rdx
shlq $0x20, %rdx
addq %rsi, %rdx
sarq $0x20, %rdx
movq 0xa0(%rsp), %rsi
cmpq %rdx, %rsi
cmovlq %rsi, %rdx
movq 0x50(%rbp), %rsi
movq %rbx, %rdi
imulq 0xa8(%rsp), %rdi
leaq (%rsi,%rcx,4), %rcx
xorps %xmm0, %xmm0
cvtss2sd -0x4(%rcx,%rdi,4), %xmm0
leaq (%rsi,%r15,4), %r8
xorps %xmm7, %xmm7
cvtss2sd (%r8,%rdi,4), %xmm7
leaq (%rsi,%rax,4), %rax
cvtss2sd (%rax,%rdi,4), %xmm8
movq %rbx, %r13
imulq 0x20(%rsp), %r13
xorps %xmm5, %xmm5
cvtss2sd -0x4(%rcx,%r13,4), %xmm5
xorps %xmm1, %xmm1
cvtss2sd (%r8,%r13,4), %xmm1
xorps %xmm2, %xmm2
cvtss2sd (%rax,%r13,4), %xmm2
imulq %rbx, %rdx
cvtss2sd -0x4(%rcx,%rdx,4), %xmm6
xorps %xmm4, %xmm4
cvtss2sd (%r8,%rdx,4), %xmm4
xorps %xmm3, %xmm3
cvtss2sd (%rax,%rdx,4), %xmm3
movl 0x18(%rbp), %eax
addsd %xmm7, %xmm0
addsd %xmm5, %xmm0
addsd %xmm1, %xmm0
addsd %xmm14, %xmm0
ucomisd 0x1cc69(%rip), %xmm0    # 0x33030
movl %eax, 0x1c(%rsp)
movsd %xmm1, 0x10(%rsp)
movsd %xmm2, 0x40(%rsp)
movsd %xmm3, 0x88(%rsp)
movsd %xmm4, 0x38(%rsp)
movsd %xmm5, 0x80(%rsp)
movsd %xmm6, 0x78(%rsp)
jb 0x163fd
sqrtsd %xmm0, %xmm0
jmp 0x16437
movsd %xmm7, 0x50(%rsp)
movsd %xmm8, 0x98(%rsp)
callq 0x9990
movsd 0x98(%rsp), %xmm8
movsd 0x50(%rsp), %xmm7
movsd 0x40(%rsp), %xmm2
movsd 0x10(%rsp), %xmm1
movsd 0x1d579(%rip), %xmm14   # 0x339b0
movapd %xmm0, 0xc0(%rsp)
addsd %xmm8, %xmm7
addsd %xmm1, %xmm7
addsd %xmm2, %xmm7
addsd %xmm14, %xmm7
ucomisd 0x1cbd6(%rip), %xmm7    # 0x33030
jb 0x16465
xorps %xmm0, %xmm0
sqrtsd %xmm7, %xmm0
jmp 0x1647d
movapd %xmm7, %xmm0
callq 0x9990
movsd 0x10(%rsp), %xmm1
movsd 0x1d533(%rip), %xmm14   # 0x339b0
movapd %xmm0, 0x50(%rsp)
movsd 0x38(%rsp), %xmm3
movsd 0x80(%rsp), %xmm0
movsd 0x78(%rsp), %xmm2
addsd %xmm1, %xmm0
addsd %xmm2, %xmm0
addsd %xmm3, %xmm0
addsd %xmm14, %xmm0
ucomisd 0x1cb7f(%rip), %xmm0    # 0x33030
jb 0x164bc
xorps %xmm4, %xmm4
sqrtsd %xmm0, %xmm4
jmp 0x164da
callq 0x9990
movsd 0x38(%rsp), %xmm3
movsd 0x10(%rsp), %xmm1
movsd 0x1d4da(%rip), %xmm14   # 0x339b0
movapd %xmm0, %xmm4
movsd 0x40(%rsp), %xmm0
movsd 0x88(%rsp), %xmm2
addsd %xmm0, %xmm1
addsd %xmm3, %xmm1
addsd %xmm2, %xmm1
addsd %xmm14, %xmm1
ucomisd 0x1cb2e(%rip), %xmm1    # 0x33030
jb 0x1650d
xorps %xmm0, %xmm0
sqrtsd %xmm1, %xmm0
jmp 0x1652b
movapd %xmm1, %xmm0
movsd %xmm4, 0x10(%rsp)
callq 0x9990
movsd 0x10(%rsp), %xmm4
movsd 0x1d485(%rip), %xmm14   # 0x339b0
movl 0x1c(%rsp), %eax
movapd 0x50(%rsp), %xmm1
testl %eax, %eax
je 0x1653f
movapd %xmm4, %xmm2
jmp 0x16547
movapd %xmm1, %xmm2
movapd %xmm4, %xmm1
movq 0x10(%rbp), %rax
testq %rax, %rax
je 0x167aa
unpcklpd 0xc0(%rsp), %xmm2       # xmm2 = xmm2[0],mem[0]
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
movapd 0x1d467(%rip), %xmm3    # 0x339d0
movapd %xmm3, %xmm1
divpd %xmm0, %xmm1
movapd %xmm3, %xmm0
divpd %xmm2, %xmm0
movq %rbp, %rcx
movq 0x48(%rsp), %rbp
imulq %rax, %rbp
movl (%rcx), %esi
movq %rax, %rdi
imulq 0x8(%rsp), %rdi
imulq 0x68(%rsp), %rbx
movq 0x30(%rsp), %rcx
leaq (%rcx,%rbx), %r8
leaq (,%rax,4), %r9
movq %r14, %r10
imulq %rax, %r10
leaq (%r8,%r10), %r11
addq %r12, %r10
xorpd %xmm2, %xmm2
movq %rax, %r15
movq 0x70(%rsp), %rcx
xorpd %xmm3, %xmm3
movss (%r12,%rcx), %xmm4
movss (%r10,%rcx), %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 0x1d3c5(%rip), %xmm11   # 0x339e0
movapd %xmm11, %xmm4
minpd %xmm5, %xmm4
movapd %xmm11, %xmm5
minpd %xmm7, %xmm5
testl %esi, %esi
je 0x16716
cmpl $0x1, %esi
jne 0x16768
movsd 0x1d372(%rip), %xmm7    # 0x339b8
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 0x1d348(%rip), %xmm6    # 0x339e0
minpd %xmm8, %xmm6
movapd %xmm6, %xmm8
unpckhpd %xmm6, %xmm8            # xmm8 = xmm8[1],xmm6[1]
addsd %xmm6, %xmm8
addsd %xmm7, %xmm8
addsd %xmm12, %xmm8
mulsd 0x1cb11(%rip), %xmm8    # 0x331d0
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 0x1c9ea(%rip), %xmm6    # 0x330f0
movss %xmm7, (%r8,%rcx)
movq %rdi, %rdx
movq 0x48(%rsp), %r13
jmp 0x16744
movapd %xmm4, %xmm6
unpckhpd %xmm4, %xmm6            # xmm6 = xmm6[1],xmm4[1]
cvtsd2ss %xmm6, %xmm6
movss %xmm6, (%r8,%rcx)
xorps %xmm6, %xmm6
cvtsd2ss %xmm4, %xmm6
movss %xmm6, (%r11,%rcx)
movq %rbp, %rdx
movq 0xb8(%rsp), %r13
movapd %xmm5, %xmm6
xorps %xmm7, %xmm7
cvtsd2ss %xmm6, %xmm7
imulq %r9, %r13
movhlps %xmm6, %xmm6            # xmm6 = xmm6[1,1]
cvtsd2ss %xmm6, %xmm6
leaq (%r8,%rdx,4), %rdx
movss %xmm6, (%rcx,%rdx)
addq %r8, %r13
movss %xmm7, (%rcx,%r13)
addpd %xmm5, %xmm3
addpd %xmm4, %xmm2
addq %r14, %rcx
decq %r15
jne 0x165c5
movapd 0x1d26c(%rip), %xmm0    # 0x339f0
mulpd %xmm0, %xmm3
mulpd %xmm0, %xmm2
cvtpd2ps %xmm2, %xmm0
cvtpd2ps %xmm3, %xmm1
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
addq 0x30(%rsp), %rcx
addq %rbx, %rcx
movq 0x90(%rsp), %rbp
jmp 0x167bb
movq 0x30(%rsp), %rcx
leaq (%rcx,%r15,4), %rcx
leaq (%rcx,%r13,4), %rcx
xorpd %xmm0, %xmm0
cmpl $0x1, (%rbp)
jne 0x167fb
imulq 0x48(%rsp), %rax
leaq (%rcx,%rax,4), %rax
movapd %xmm0, %xmm1
shufps $0x55, %xmm0, %xmm1     # xmm1 = xmm1[1,1],xmm0[1,1]
movss %xmm1, (%rax)
movq 0x8(%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, 0x28(%rsp)
movq 0x58(%rbp), %rbx
movq %rbx, %rax
shlq $0x20, %rax
movslq %ebx, %rcx
addq $0x4, 0x70(%rsp)
movq 0xb0(%rsp), %rdx
movq %rdx, %r15
cmpq %rcx, %rdx
jl 0x162e8
jmp 0x16830
movq %r12, 0x28(%rsp)
movq 0x20(%rsp), %rdx
incq %rdx
movslq 0x60(%rbp), %rax
addq $0x4, 0x68(%rsp)
movq 0x28(%rsp), %r12
movq %rdx, 0x20(%rsp)
cmpq %rax, %rdx
jl 0x1629b
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop