]> granicus.if.org Git - libvpx/commitdiff
Adds code for corner detection and ransac
authorDeb Mukherjee <debargha@google.com>
Sat, 7 Feb 2015 01:44:49 +0000 (17:44 -0800)
committerDeb Mukherjee <debargha@google.com>
Tue, 10 Feb 2015 08:48:56 +0000 (00:48 -0800)
This code is to start experiments with global motion models.

The corner detection can be either fast_9 or Harris.
Corner matching is currently based on normalized correlation.
Three flavors of ransac are used to estimate either a
homography (8-param), or an affine model (6-param) or a
rotation-zoom only affine model (4-param).

The highest level API for the library is in vp9_global_motion.h,
where there are two functions - one for computing a single model
and another for computing multiple models up to a maximum number
provided or until a desired inlier probability is achieved.

Change-Id: I3f9788ec2dc0635cbc65f5c66c6ea8853cfcf2dd

vp9/encoder/vp9_corner_detect.c [new file with mode: 0644]
vp9/encoder/vp9_corner_detect.h [new file with mode: 0644]
vp9/encoder/vp9_corner_match.c [new file with mode: 0644]
vp9/encoder/vp9_corner_match.h [new file with mode: 0644]
vp9/encoder/vp9_global_motion.c [new file with mode: 0644]
vp9/encoder/vp9_global_motion.h [new file with mode: 0644]
vp9/encoder/vp9_ransac.c [new file with mode: 0644]
vp9/encoder/vp9_ransac.h [new file with mode: 0644]
vp9/vp9cx.mk

diff --git a/vp9/encoder/vp9_corner_detect.c b/vp9/encoder/vp9_corner_detect.c
new file mode 100644 (file)
index 0000000..dd7ab0a
--- /dev/null
@@ -0,0 +1,3011 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+////////////////////////////////////////////////////////////////////
+/*
+ *  The code for FAST in this file is taken from
+ *  http://www.edwardrosten.com/work/fast.html with the following
+ *  copyright notice:
+ *
+ *  Copyright (c) 2006, 2008, 2009, 2010 Edward Rosten
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  *Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *  *Redistributions in binary form must reproduce the above copyright
+ *  notice, this list of conditions and the following disclaimer in the
+ *  documentation and/or other materials provided with the distribution.
+ *
+ *  *Neither the name of the University of Cambridge nor the names of
+ *  its contributors may be used to endorse or promote products derived
+ *  from this software without specific prior written permission.
+
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <math.h>
+
+#include "vp9_corner_detect.h"
+
+typedef struct {
+  int x, y;
+} xy;
+typedef unsigned char byte;
+
+xy* fast_nonmax(const byte* im, int xsize, int ysize, int stride,
+                xy* corners, int numcorners, int barrier, int* numnx);
+xy* fast_corner_detect_9(const byte* im, int xsize, int ysize, int stride,
+                         int barrier, int* numcorners);
+
+xy* fast_corner_detect_9(const byte* im, int xsize, int ysize, int stride,
+                         int barrier, int* num) {
+  int boundary = 3, y, cb, c_b;
+  const byte  *line_max, *line_min;
+  int rsize=512, total=0;
+  xy *ret = (xy*)malloc(rsize*sizeof(xy));
+  const byte* cache_0;
+  const byte* cache_1;
+  const byte* cache_2;
+  int pixel[16];
+  pixel[0] = 0 + 3 * stride;
+  pixel[1] = 1 + 3 * stride;
+  pixel[2] = 2 + 2 * stride;
+  pixel[3] = 3 + 1 * stride;
+  pixel[4] = 3 + 0 * stride;
+  pixel[5] = 3 + -1 * stride;
+  pixel[6] = 2 + -2 * stride;
+  pixel[7] = 1 + -3 * stride;
+  pixel[8] = 0 + -3 * stride;
+  pixel[9] = -1 + -3 * stride;
+  pixel[10] = -2 + -2 * stride;
+  pixel[11] = -3 + -1 * stride;
+  pixel[12] = -3 + 0 * stride;
+  pixel[13] = -3 + 1 * stride;
+  pixel[14] = -2 + 2 * stride;
+  pixel[15] = -1 + 3 * stride;
+  for(y = boundary ; y < ysize - boundary; y++)
+  {
+    cache_0 = im + boundary + y*stride;
+    line_min = cache_0 - boundary;
+    line_max = im + xsize - boundary + y * stride;
+
+    cache_1 = cache_0 + pixel[5];
+    cache_2 = cache_0 + pixel[14];
+
+    for(; cache_0 < line_max;cache_0++, cache_1++, cache_2++)
+    {
+      cb = *cache_0 + barrier;
+      c_b = *cache_0 - barrier;
+      if(*cache_1 > cb)
+        if(*cache_2 > cb)
+          if(*(cache_0+3) > cb)
+            if(*(cache_0 + pixel[0]) > cb)
+              if(*(cache_0 + pixel[3]) > cb)
+                if(*(cache_0 + pixel[6]) > cb)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[15]) > cb)
+                      if(*(cache_0 + pixel[1]) > cb)
+                        goto success;
+                      else if(*(cache_0 + pixel[1]) < c_b)
+                        continue;
+                      else
+                        if(*(cache_0 + pixel[10]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            if(*(cache_0 + pixel[7]) > cb)
+                              if(*(cache_0 + pixel[9]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else if(*(cache_0 + pixel[15]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[8]) > cb)
+                        if(*(cache_0 + pixel[7]) > cb)
+                          if(*(cache_0 + pixel[1]) > cb)
+                            goto success;
+                          else if(*(cache_0 + pixel[1]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[10]) > cb)
+                              goto success;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else if(*(cache_2+4) < c_b)
+                    continue;
+                  else
+                    if(*(cache_1+-6) > cb)
+                      if(*(cache_0 + pixel[9]) > cb)
+                        if(*(cache_0 + pixel[10]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            if(*(cache_0 + pixel[7]) > cb)
+                              goto success;
+                            else if(*(cache_0 + pixel[7]) < c_b)
+                              continue;
+                            else
+                              if(*(cache_0+-3) > cb)
+                                goto success;
+                              else
+                                continue;
+                          else if(*(cache_0 + pixel[8]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0+-3) > cb)
+                              if(*(cache_0 + pixel[1]) > cb)
+                                if(*(cache_0 + pixel[13]) > cb)
+                                  goto success;
+                                else
+                                  continue;
+                              else
+                                continue;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else if(*(cache_0 + pixel[6]) < c_b)
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*(cache_1+-6) > cb)
+                        continue;
+                      else if(*(cache_1+-6) < c_b)
+                        if(*(cache_0 + pixel[15]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[15]) > cb)
+                      if(*(cache_2+4) > cb)
+                        if(*(cache_0 + pixel[1]) > cb)
+                          goto success;
+                        else if(*(cache_0 + pixel[1]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[8]) > cb)
+                            if(*(cache_1+-6) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else if(*(cache_2+4) < c_b)
+                        continue;
+                      else
+                        if(*(cache_0 + pixel[9]) > cb)
+                          if(*(cache_0+-3) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              if(*(cache_0 + pixel[10]) > cb)
+                                if(*(cache_1+-6) > cb)
+                                  goto success;
+                                else
+                                  continue;
+                              else
+                                continue;
+                            else if(*(cache_0 + pixel[1]) < c_b)
+                              continue;
+                            else
+                              if(*(cache_0 + pixel[8]) > cb)
+                                if(*(cache_0 + pixel[10]) > cb)
+                                  goto success;
+                                else
+                                  continue;
+                              else
+                                continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else if(*(cache_0 + pixel[3]) < c_b)
+                continue;
+              else
+                if(*(cache_0+-3) > cb)
+                  if(*(cache_0 + pixel[10]) > cb)
+                    if(*(cache_1+-6) > cb)
+                      if(*(cache_0 + pixel[8]) > cb)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          goto success;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_2+4) > cb)
+                            goto success;
+                          else
+                            continue;
+                      else if(*(cache_0 + pixel[8]) < c_b)
+                        if(*(cache_0 + pixel[7]) > cb || *(cache_0 + pixel[7]) < c_b)
+                          continue;
+                        else
+                          goto success;
+                      else
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[13]) > cb)
+                            if(*(cache_0 + pixel[15]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else if(*(cache_2+4) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[9]) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              if(*(cache_0 + pixel[13]) > cb)
+                                if(*(cache_0 + pixel[15]) > cb)
+                                  goto success;
+                                else
+                                  continue;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[0]) < c_b)
+              if(*(cache_0 + pixel[7]) > cb)
+                if(*(cache_0 + pixel[10]) > cb)
+                  goto success;
+                else
+                  continue;
+              else
+                continue;
+            else
+              if(*(cache_0 + pixel[7]) > cb)
+                if(*(cache_0 + pixel[10]) > cb)
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_0 + pixel[6]) > cb)
+                      if(*(cache_0 + pixel[8]) > cb)
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[9]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else if(*(cache_2+4) < c_b)
+                          continue;
+                        else
+                          if(*(cache_1+-6) > cb)
+                            if(*(cache_0 + pixel[9]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[6]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[15]) > cb)
+                        if(*(cache_0+-3) > cb)
+                          if(*(cache_0 + pixel[9]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else if(*(cache_0 + pixel[3]) < c_b)
+                    continue;
+                  else
+                    if(*(cache_0+-3) > cb)
+                      if(*(cache_0 + pixel[8]) > cb)
+                        if(*(cache_1+-6) > cb)
+                          if(*(cache_0 + pixel[6]) > cb)
+                            if(*(cache_0 + pixel[9]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else if(*(cache_0 + pixel[6]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[15]) > cb)
+                              if(*(cache_0 + pixel[13]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else if(*(cache_0 + pixel[10]) < c_b)
+                  continue;
+                else
+                  if(*(cache_0 + pixel[1]) > cb)
+                    if(*(cache_0 + pixel[9]) > cb)
+                      if(*(cache_0 + pixel[6]) > cb)
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[3]) > cb)
+                            if(*(cache_0 + pixel[8]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else if(*(cache_0+3) < c_b)
+            if(*(cache_0+-3) > cb)
+              if(*(cache_0 + pixel[9]) > cb)
+                if(*(cache_1+-6) > cb)
+                  if(*(cache_0 + pixel[10]) > cb)
+                    if(*(cache_0 + pixel[6]) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              continue;
+          else
+            if(*(cache_0+-3) > cb)
+              if(*(cache_1+-6) > cb)
+                if(*(cache_0 + pixel[7]) > cb)
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[9]) > cb)
+                        if(*(cache_0 + pixel[6]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            goto success;
+                          else if(*(cache_0 + pixel[8]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[0]) > cb)
+                              if(*(cache_0 + pixel[1]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                        else if(*(cache_0 + pixel[6]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[15]) > cb)
+                            if(*(cache_0 + pixel[8]) > cb)
+                              goto success;
+                            else if(*(cache_0 + pixel[8]) < c_b)
+                              continue;
+                            else
+                              if(*(cache_0 + pixel[0]) > cb)
+                                goto success;
+                              else
+                                continue;
+                          else
+                            continue;
+                      else if(*(cache_0 + pixel[9]) < c_b)
+                        continue;
+                      else
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[0]) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[3]) > cb)
+                        if(*(cache_0 + pixel[1]) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[7]) < c_b)
+                  if(*(cache_0 + pixel[10]) > cb)
+                    if(*(cache_2+4) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_0 + pixel[0]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[0]) > cb)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else if(*(cache_2+4) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[9]) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              if(*(cache_0 + pixel[15]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else if(*(cache_0 + pixel[1]) < c_b)
+                              continue;
+                            else
+                              if(*(cache_0 + pixel[8]) > cb)
+                                goto success;
+                              else
+                                continue;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[3]) > cb)
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            if(*(cache_0 + pixel[13]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else
+                continue;
+            else
+              continue;
+        else if(*cache_2 < c_b)
+          if(*(cache_0+3) > cb)
+            if(*(cache_0 + pixel[7]) > cb)
+              if(*(cache_0 + pixel[1]) > cb)
+                if(*(cache_0 + pixel[9]) > cb)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[6]) > cb)
+                      if(*(cache_0 + pixel[3]) > cb)
+                        if(*(cache_0 + pixel[8]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_2+4) < c_b)
+                    continue;
+                  else
+                    if(*(cache_1+-6) > cb)
+                      if(*(cache_0 + pixel[3]) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                else if(*(cache_0 + pixel[9]) < c_b)
+                  if(*(cache_0 + pixel[15]) > cb)
+                    if(*(cache_2+4) > cb)
+                      if(*(cache_0 + pixel[3]) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[0]) > cb)
+                    if(*(cache_0 + pixel[8]) > cb)
+                      if(*(cache_2+4) > cb)
+                        if(*(cache_0 + pixel[3]) > cb)
+                          if(*(cache_0 + pixel[6]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[8]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[15]) > cb)
+                        if(*(cache_2+4) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else if(*(cache_0 + pixel[1]) < c_b)
+                if(*(cache_1+-6) > cb)
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[6]) > cb)
+                        if(*(cache_0 + pixel[8]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_0 + pixel[3]) < c_b)
+                    continue;
+                  else
+                    if(*(cache_0+-3) > cb)
+                      if(*(cache_0 + pixel[10]) > cb)
+                        if(*(cache_0 + pixel[6]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else if(*(cache_1+-6) < c_b)
+                  if(*(cache_0 + pixel[9]) > cb)
+                    if(*(cache_0 + pixel[3]) > cb)
+                      if(*(cache_2+4) > cb)
+                        if(*(cache_0 + pixel[10]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else if(*(cache_2+4) < c_b)
+                        if(*(cache_0 + pixel[10]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[3]) < c_b)
+                      if(*(cache_0 + pixel[15]) < c_b)
+                        if(*(cache_0+-3) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_2+4) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0 + pixel[0]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    if(*(cache_2+4) < c_b)
+                      if(*(cache_0 + pixel[10]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[15]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        if(*(cache_0 + pixel[3]) < c_b)
+                          if(*(cache_0 + pixel[15]) < c_b)
+                            if(*(cache_0 + pixel[0]) < c_b)
+                              if(*(cache_0+-3) < c_b)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                else
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[8]) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                if(*(cache_0 + pixel[10]) > cb)
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_2+4) > cb)
+                      if(*(cache_0 + pixel[6]) > cb)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else if(*(cache_2+4) < c_b)
+                      continue;
+                    else
+                      if(*(cache_1+-6) > cb)
+                        if(*(cache_0 + pixel[6]) > cb)
+                          if(*(cache_0 + pixel[9]) > cb)
+                            if(*(cache_0 + pixel[8]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else if(*(cache_0 + pixel[3]) < c_b)
+                    continue;
+                  else
+                    if(*(cache_0+-3) > cb)
+                      if(*(cache_1+-6) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[7]) < c_b)
+              if(*(cache_1+-6) < c_b)
+                if(*(cache_0 + pixel[15]) > cb)
+                  continue;
+                else if(*(cache_0 + pixel[15]) < c_b)
+                  if(*(cache_0+-3) < c_b)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0 + pixel[13]) < c_b)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            continue;
+                          else if(*(cache_0 + pixel[8]) < c_b)
+                            goto success;
+                          else
+                            if(*(cache_0 + pixel[1]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                        else
+                          if(*(cache_2+4) < c_b)
+                            goto success;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0 + pixel[3]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[6]) < c_b)
+                    if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0+-3) < c_b)
+                        if(*(cache_0 + pixel[8]) < c_b)
+                          if(*(cache_0 + pixel[13]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+            else
+              if(*(cache_0 + pixel[0]) < c_b)
+                if(*(cache_0 + pixel[10]) > cb)
+                  continue;
+                else if(*(cache_0 + pixel[10]) < c_b)
+                  if(*(cache_0 + pixel[9]) > cb)
+                    continue;
+                  else if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0+-3) < c_b)
+                      if(*(cache_0 + pixel[1]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[1]) < c_b)
+                        if(*(cache_1+-6) < c_b)
+                          if(*(cache_0 + pixel[13]) < c_b)
+                            if(*(cache_0 + pixel[15]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        if(*(cache_0 + pixel[8]) < c_b)
+                          if(*(cache_0 + pixel[13]) < c_b)
+                            if(*(cache_1+-6) < c_b)
+                              if(*(cache_0 + pixel[15]) < c_b)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else
+                    if(*(cache_2+4) < c_b)
+                      if(*(cache_0+-3) < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          if(*(cache_1+-6) < c_b)
+                            if(*(cache_0 + pixel[13]) < c_b)
+                              if(*(cache_0 + pixel[15]) < c_b)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  if(*(cache_0 + pixel[3]) < c_b)
+                    if(*(cache_1+-6) < c_b)
+                      if(*(cache_0+-3) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else if(*(cache_0+3) < c_b)
+            if(*(cache_0+-3) > cb)
+              if(*(cache_0 + pixel[13]) > cb)
+                goto success;
+              else
+                continue;
+            else if(*(cache_0+-3) < c_b)
+              if(*(cache_0 + pixel[9]) > cb)
+                if(*(cache_0 + pixel[13]) < c_b)
+                  goto success;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[9]) < c_b)
+                goto success;
+              else
+                if(*(cache_0 + pixel[6]) > cb || *(cache_0 + pixel[6]) < c_b)
+                  continue;
+                else
+                  if(*(cache_2+4) < c_b)
+                    goto success;
+                  else
+                    continue;
+            else
+              continue;
+          else
+            if(*(cache_1+-6) > cb)
+              if(*(cache_0 + pixel[13]) > cb)
+                if(*(cache_0 + pixel[9]) > cb)
+                  if(*(cache_0 + pixel[7]) > cb)
+                    if(*(cache_0+-3) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else if(*(cache_1+-6) < c_b)
+              if(*(cache_0 + pixel[3]) > cb)
+                if(*(cache_0 + pixel[8]) < c_b)
+                  if(*(cache_0 + pixel[15]) > cb)
+                    continue;
+                  else if(*(cache_0 + pixel[15]) < c_b)
+                    if(*(cache_0 + pixel[13]) < c_b)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[0]) < c_b)
+                        goto success;
+                      else
+                        if(*(cache_0 + pixel[7]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else
+                    if(*(cache_0 + pixel[6]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[3]) < c_b)
+                if(*(cache_2+4) > cb)
+                  continue;
+                else if(*(cache_2+4) < c_b)
+                  if(*(cache_0 + pixel[0]) < c_b)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[1]) < c_b)
+                      if(*(cache_0 + pixel[15]) < c_b)
+                        if(*(cache_0+-3) < c_b)
+                          if(*(cache_0 + pixel[13]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0 + pixel[8]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[1]) < c_b)
+                      if(*(cache_0+-3) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0 + pixel[8]) < c_b)
+                        if(*(cache_0 + pixel[0]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else
+                if(*(cache_0 + pixel[1]) > cb)
+                  continue;
+                else if(*(cache_0 + pixel[1]) < c_b)
+                  if(*(cache_0 + pixel[10]) < c_b)
+                    if(*(cache_0+-3) < c_b)
+                      if(*(cache_0 + pixel[9]) > cb)
+                        if(*(cache_2+4) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else if(*(cache_0 + pixel[9]) < c_b)
+                        if(*(cache_0 + pixel[15]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[15]) < c_b)
+                          if(*(cache_0 + pixel[13]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          if(*(cache_0 + pixel[6]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                      else
+                        if(*(cache_2+4) < c_b)
+                          if(*(cache_0 + pixel[15]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[7]) > cb)
+                    continue;
+                  else if(*(cache_0 + pixel[7]) < c_b)
+                    if(*(cache_0 + pixel[15]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[15]) < c_b)
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0+-3) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            if(*(cache_0 + pixel[13]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0 + pixel[6]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                  else
+                    if(*(cache_0 + pixel[0]) < c_b)
+                      if(*(cache_0 + pixel[8]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+            else
+              continue;
+        else
+          if(*(cache_0 + pixel[7]) > cb)
+            if(*(cache_0 + pixel[3]) > cb)
+              if(*(cache_0 + pixel[10]) > cb)
+                if(*(cache_0+3) > cb)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[6]) > cb)
+                      if(*(cache_0 + pixel[8]) > cb)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          goto success;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[0]) > cb)
+                            goto success;
+                          else
+                            continue;
+                      else if(*(cache_0 + pixel[8]) < c_b)
+                        continue;
+                      else
+                        if(*(cache_0 + pixel[15]) > cb)
+                          if(*(cache_0 + pixel[0]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else if(*(cache_2+4) < c_b)
+                    if(*(cache_1+-6) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    if(*(cache_1+-6) > cb)
+                      if(*(cache_0 + pixel[6]) > cb)
+                        if(*(cache_0 + pixel[8]) > cb)
+                          if(*(cache_0 + pixel[9]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else if(*(cache_0+3) < c_b)
+                  continue;
+                else
+                  if(*(cache_0+-3) > cb)
+                    if(*(cache_0 + pixel[13]) > cb)
+                      if(*(cache_1+-6) > cb)
+                        if(*(cache_0 + pixel[6]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            if(*(cache_0 + pixel[9]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else if(*(cache_0 + pixel[10]) < c_b)
+                if(*(cache_0 + pixel[15]) > cb)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[6]) > cb)
+                      if(*(cache_0+3) > cb)
+                        if(*(cache_0 + pixel[0]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[15]) < c_b)
+                  continue;
+                else
+                  if(*(cache_0 + pixel[8]) > cb)
+                    if(*(cache_0 + pixel[0]) > cb)
+                      goto success;
+                    else if(*(cache_0 + pixel[0]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[9]) > cb)
+                        if(*(cache_0 + pixel[1]) > cb)
+                          if(*(cache_0 + pixel[6]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else
+                if(*(cache_0 + pixel[1]) > cb)
+                  if(*(cache_0 + pixel[9]) > cb)
+                    if(*(cache_0 + pixel[6]) > cb)
+                      if(*(cache_0+3) > cb)
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            goto success;
+                          else if(*(cache_0 + pixel[8]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[15]) > cb)
+                              goto success;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0 + pixel[0]) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    if(*(cache_0 + pixel[0]) > cb)
+                      if(*(cache_0+3) > cb)
+                        if(*(cache_0 + pixel[6]) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            if(*(cache_2+4) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else if(*(cache_0 + pixel[15]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[8]) > cb)
+                              if(*(cache_2+4) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[3]) < c_b)
+              if(*(cache_0 + pixel[13]) > cb)
+                if(*(cache_1+-6) > cb)
+                  if(*(cache_0 + pixel[9]) > cb)
+                    if(*(cache_0+-3) > cb)
+                      if(*(cache_0 + pixel[6]) > cb)
+                        if(*(cache_0 + pixel[8]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[13]) < c_b)
+                continue;
+              else
+                if(*(cache_0+3) > cb)
+                  if(*(cache_0+-3) > cb)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else
+              if(*(cache_0+-3) > cb)
+                if(*(cache_0 + pixel[13]) > cb)
+                  if(*(cache_1+-6) > cb)
+                    if(*(cache_0 + pixel[9]) > cb)
+                      if(*(cache_0 + pixel[6]) > cb)
+                        if(*(cache_0 + pixel[10]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[13]) < c_b)
+                  if(*(cache_0 + pixel[0]) > cb)
+                    goto success;
+                  else
+                    continue;
+                else
+                  if(*(cache_0+3) > cb)
+                    if(*(cache_0 + pixel[9]) > cb)
+                      if(*(cache_1+-6) > cb)
+                        if(*(cache_0 + pixel[6]) > cb)
+                          if(*(cache_0 + pixel[10]) > cb)
+                            if(*(cache_0 + pixel[8]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else
+            continue;
+      else if(*cache_1 < c_b)
+        if(*(cache_0 + pixel[15]) > cb)
+          if(*(cache_1+-6) > cb)
+            if(*(cache_2+4) > cb)
+              if(*(cache_0+-3) > cb)
+                if(*(cache_0 + pixel[10]) > cb)
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*cache_2 > cb)
+                        goto success;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[1]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[7]) > cb)
+                        goto success;
+                      else
+                        continue;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[10]) < c_b)
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_0 + pixel[13]) > cb)
+                      if(*cache_2 > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*cache_2 > cb)
+                        if(*(cache_0 + pixel[0]) > cb)
+                          if(*(cache_0 + pixel[13]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+            else if(*(cache_2+4) < c_b)
+              if(*(cache_0 + pixel[7]) > cb)
+                if(*(cache_0+-3) > cb)
+                  if(*cache_2 > cb)
+                    if(*(cache_0 + pixel[13]) > cb)
+                      if(*(cache_0 + pixel[9]) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[7]) < c_b)
+                if(*(cache_0 + pixel[9]) > cb)
+                  if(*(cache_0 + pixel[1]) > cb)
+                    if(*(cache_0+-3) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[9]) < c_b)
+                  if(*(cache_0 + pixel[10]) > cb)
+                    continue;
+                  else if(*(cache_0 + pixel[10]) < c_b)
+                    if(*(cache_0 + pixel[3]) < c_b)
+                      if(*(cache_0+3) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    if(*(cache_0 + pixel[1]) < c_b)
+                      if(*(cache_0 + pixel[3]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  if(*(cache_0 + pixel[0]) < c_b)
+                    goto success;
+                  else
+                    continue;
+              else
+                if(*(cache_0 + pixel[0]) > cb)
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[9]) > cb)
+                      if(*cache_2 > cb)
+                        if(*(cache_0 + pixel[1]) > cb)
+                          if(*(cache_0 + pixel[10]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else if(*(cache_0 + pixel[1]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[8]) > cb)
+                            if(*(cache_0+-3) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else
+              if(*(cache_0 + pixel[9]) > cb)
+                if(*(cache_0+-3) > cb)
+                  if(*(cache_0 + pixel[1]) > cb)
+                    if(*cache_2 > cb)
+                      if(*(cache_0 + pixel[10]) > cb)
+                        if(*(cache_0 + pixel[13]) > cb)
+                          if(*(cache_0 + pixel[0]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_0 + pixel[1]) < c_b)
+                    continue;
+                  else
+                    if(*(cache_0 + pixel[7]) > cb)
+                      if(*(cache_0 + pixel[10]) > cb)
+                        if(*(cache_0 + pixel[13]) > cb)
+                          if(*cache_2 > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[7]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[0]) > cb)
+                        if(*(cache_0 + pixel[8]) > cb)
+                          if(*(cache_0 + pixel[6]) < c_b)
+                            if(*(cache_0 + pixel[10]) > cb)
+                              if(*(cache_0 + pixel[13]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                else
+                  continue;
+              else
+                continue;
+          else if(*(cache_1+-6) < c_b)
+            if(*(cache_0 + pixel[3]) > cb)
+              if(*(cache_0 + pixel[13]) > cb)
+                if(*(cache_0+-3) > cb)
+                  if(*(cache_0+3) > cb)
+                    goto success;
+                  else
+                    continue;
+                else if(*(cache_0+-3) < c_b)
+                  if(*(cache_0+3) < c_b)
+                    if(*(cache_0 + pixel[6]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[13]) < c_b)
+                if(*(cache_0 + pixel[7]) < c_b)
+                  if(*(cache_0 + pixel[6]) < c_b)
+                    if(*(cache_0 + pixel[8]) < c_b)
+                      if(*(cache_0+-3) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                if(*(cache_0+3) < c_b)
+                  if(*(cache_0+-3) < c_b)
+                    if(*(cache_0 + pixel[7]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[3]) < c_b)
+              if(*(cache_0 + pixel[8]) < c_b)
+                if(*(cache_0 + pixel[9]) < c_b)
+                  if(*(cache_0 + pixel[7]) < c_b)
+                    if(*(cache_0+3) > cb)
+                      continue;
+                    else if(*(cache_0+3) < c_b)
+                      if(*(cache_0 + pixel[10]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[6]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                    else
+                      if(*(cache_0 + pixel[13]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              if(*(cache_0+-3) < c_b)
+                if(*(cache_0+3) > cb)
+                  continue;
+                else if(*(cache_0+3) < c_b)
+                  if(*(cache_0 + pixel[6]) < c_b)
+                    if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0 + pixel[9]) < c_b)
+                        if(*(cache_0 + pixel[7]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[13]) < c_b)
+                    if(*(cache_0 + pixel[7]) < c_b)
+                      if(*(cache_0 + pixel[6]) < c_b)
+                        if(*(cache_0 + pixel[10]) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            if(*(cache_0 + pixel[9]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else
+            if(*(cache_2+4) > cb)
+              if(*(cache_0+3) > cb)
+                if(*(cache_0+-3) > cb)
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*(cache_0 + pixel[3]) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else if(*(cache_2+4) < c_b)
+              if(*(cache_0 + pixel[10]) > cb)
+                continue;
+              else if(*(cache_0 + pixel[10]) < c_b)
+                if(*(cache_0+3) < c_b)
+                  if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0 + pixel[3]) < c_b)
+                      if(*(cache_0 + pixel[7]) < c_b)
+                        if(*(cache_0 + pixel[6]) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                if(*(cache_0 + pixel[1]) < c_b)
+                  if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0 + pixel[3]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else
+              continue;
+        else if(*(cache_0 + pixel[15]) < c_b)
+          if(*(cache_0+3) > cb)
+            if(*(cache_0+-3) < c_b)
+              if(*(cache_1+-6) < c_b)
+                if(*(cache_0 + pixel[13]) < c_b)
+                  if(*(cache_0 + pixel[7]) > cb)
+                    continue;
+                  else if(*(cache_0 + pixel[7]) < c_b)
+                    goto success;
+                  else
+                    if(*(cache_0 + pixel[8]) < c_b)
+                      if(*(cache_0 + pixel[0]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              continue;
+          else if(*(cache_0+3) < c_b)
+            if(*(cache_0 + pixel[6]) > cb)
+              if(*(cache_0 + pixel[13]) > cb)
+                if(*cache_2 > cb)
+                  if(*(cache_0 + pixel[10]) > cb)
+                    goto success;
+                  else
+                    continue;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[13]) < c_b)
+                if(*(cache_0 + pixel[0]) < c_b)
+                  if(*(cache_2+4) < c_b)
+                    if(*cache_2 < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else if(*(cache_0 + pixel[6]) < c_b)
+              if(*(cache_0 + pixel[3]) > cb)
+                if(*(cache_0+-3) < c_b)
+                  if(*(cache_0 + pixel[1]) < c_b)
+                    continue;
+                  else
+                    goto success;
+                else
+                  continue;
+              else if(*(cache_0 + pixel[3]) < c_b)
+                if(*(cache_0 + pixel[7]) > cb)
+                  if(*cache_2 < c_b)
+                    goto success;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[7]) < c_b)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[10]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else if(*(cache_2+4) < c_b)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[1]) < c_b)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[0]) < c_b)
+                        goto success;
+                      else
+                        if(*(cache_0 + pixel[9]) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[8]) < c_b)
+                          if(*(cache_0 + pixel[9]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    if(*(cache_1+-6) < c_b)
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[8]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  if(*cache_2 < c_b)
+                    if(*(cache_2+4) < c_b)
+                      if(*(cache_0 + pixel[0]) < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                if(*(cache_0+-3) < c_b)
+                  if(*(cache_1+-6) < c_b)
+                    if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0 + pixel[8]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[8]) < c_b)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          if(*(cache_0 + pixel[7]) > cb)
+                            continue;
+                          else if(*(cache_0 + pixel[7]) < c_b)
+                            goto success;
+                          else
+                            if(*(cache_0 + pixel[13]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                        else
+                          if(*(cache_2+4) < c_b)
+                            goto success;
+                          else
+                            continue;
+                      else
+                        if(*(cache_0 + pixel[13]) < c_b)
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            if(*(cache_0 + pixel[7]) > cb || *(cache_0 + pixel[7]) < c_b)
+                              continue;
+                            else
+                              goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else
+              if(*(cache_0 + pixel[13]) < c_b)
+                if(*(cache_2+4) > cb)
+                  continue;
+                else if(*(cache_2+4) < c_b)
+                  if(*cache_2 < c_b)
+                    if(*(cache_0 + pixel[3]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[3]) < c_b)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[0]) < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        if(*(cache_0 + pixel[7]) < c_b)
+                          if(*(cache_1+-6) < c_b)
+                            if(*(cache_0 + pixel[8]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      if(*(cache_0+-3) < c_b)
+                        if(*(cache_0 + pixel[10]) < c_b)
+                          if(*(cache_0 + pixel[1]) > cb)
+                            continue;
+                          else if(*(cache_0 + pixel[1]) < c_b)
+                            goto success;
+                          else
+                            if(*(cache_0 + pixel[7]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_1+-6) < c_b)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[0]) < c_b)
+                        if(*cache_2 < c_b)
+                          if(*(cache_0 + pixel[10]) < c_b)
+                            if(*(cache_0+-3) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        if(*(cache_0 + pixel[7]) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            if(*(cache_0 + pixel[1]) > cb || *(cache_0 + pixel[1]) < c_b)
+                              continue;
+                            else
+                              goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else
+            if(*(cache_0+-3) < c_b)
+              if(*(cache_0 + pixel[13]) < c_b)
+                if(*(cache_1+-6) < c_b)
+                  if(*(cache_0 + pixel[9]) > cb)
+                    if(*(cache_0 + pixel[3]) < c_b)
+                      if(*(cache_2+4) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_0 + pixel[9]) < c_b)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0 + pixel[7]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[7]) < c_b)
+                        if(*cache_2 > cb || *cache_2 < c_b)
+                          goto success;
+                        else
+                          if(*(cache_0 + pixel[6]) < c_b)
+                            if(*(cache_0 + pixel[8]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else
+                        if(*(cache_0 + pixel[1]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[1]) < c_b)
+                          if(*cache_2 < c_b)
+                            if(*(cache_0 + pixel[0]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            if(*(cache_0 + pixel[8]) < c_b)
+                              if(*cache_2 < c_b)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                    else
+                      if(*(cache_0 + pixel[3]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                  else
+                    if(*(cache_2+4) < c_b)
+                      if(*(cache_0 + pixel[1]) < c_b)
+                        if(*(cache_0 + pixel[10]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[10]) < c_b)
+                          if(*cache_2 < c_b)
+                            if(*(cache_0 + pixel[0]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          if(*(cache_0 + pixel[3]) < c_b)
+                            if(*(cache_0 + pixel[0]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              continue;
+        else
+          if(*(cache_0 + pixel[8]) > cb)
+            if(*(cache_0 + pixel[6]) > cb)
+              if(*cache_2 > cb)
+                if(*(cache_1+-6) > cb)
+                  if(*(cache_0 + pixel[10]) > cb)
+                    goto success;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              continue;
+          else if(*(cache_0 + pixel[8]) < c_b)
+            if(*(cache_0 + pixel[3]) > cb)
+              if(*(cache_0 + pixel[13]) > cb)
+                continue;
+              else if(*(cache_0 + pixel[13]) < c_b)
+                if(*(cache_0+-3) < c_b)
+                  if(*(cache_0 + pixel[7]) < c_b)
+                    if(*(cache_1+-6) < c_b)
+                      if(*(cache_0 + pixel[6]) < c_b)
+                        if(*(cache_0 + pixel[10]) < c_b)
+                          if(*(cache_0 + pixel[9]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                if(*(cache_0+3) < c_b)
+                  if(*(cache_0+-3) < c_b)
+                    if(*(cache_0 + pixel[10]) < c_b)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[3]) < c_b)
+              if(*(cache_2+4) > cb)
+                if(*(cache_1+-6) < c_b)
+                  if(*(cache_0 + pixel[7]) < c_b)
+                    goto success;
+                  else
+                    continue;
+                else
+                  continue;
+              else if(*(cache_2+4) < c_b)
+                if(*(cache_0 + pixel[6]) < c_b)
+                  if(*(cache_0+3) > cb)
+                    continue;
+                  else if(*(cache_0+3) < c_b)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        continue;
+                      else if(*(cache_0 + pixel[0]) < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        if(*(cache_0 + pixel[9]) < c_b)
+                          if(*(cache_0 + pixel[1]) < c_b)
+                            if(*(cache_0 + pixel[7]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0 + pixel[7]) < c_b)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          goto success;
+                        else
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0 + pixel[1]) < c_b)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          if(*(cache_0 + pixel[7]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            if(*(cache_0 + pixel[7]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else
+                        continue;
+                  else
+                    if(*(cache_0+-3) < c_b)
+                      if(*(cache_0 + pixel[13]) < c_b)
+                        if(*(cache_1+-6) < c_b)
+                          if(*(cache_0 + pixel[7]) < c_b)
+                            if(*(cache_0 + pixel[10]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  continue;
+              else
+                if(*(cache_1+-6) < c_b)
+                  if(*(cache_0+3) > cb)
+                    continue;
+                  else if(*(cache_0+3) < c_b)
+                    if(*(cache_0 + pixel[6]) < c_b)
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[7]) < c_b)
+                          if(*(cache_0 + pixel[9]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    if(*(cache_0+-3) < c_b)
+                      if(*(cache_0 + pixel[13]) < c_b)
+                        if(*(cache_0 + pixel[6]) < c_b)
+                          if(*(cache_0 + pixel[7]) < c_b)
+                            if(*(cache_0 + pixel[10]) < c_b)
+                              if(*(cache_0 + pixel[9]) < c_b)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  continue;
+            else
+              if(*(cache_0+-3) < c_b)
+                if(*(cache_0 + pixel[13]) > cb)
+                  if(*(cache_0+3) < c_b)
+                    goto success;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[13]) < c_b)
+                  if(*(cache_1+-6) < c_b)
+                    if(*(cache_0 + pixel[7]) < c_b)
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[6]) < c_b)
+                          if(*(cache_0 + pixel[9]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0+3) < c_b)
+                    if(*(cache_0 + pixel[10]) < c_b)
+                      if(*(cache_0 + pixel[6]) < c_b)
+                        if(*(cache_1+-6) < c_b)
+                          if(*(cache_0 + pixel[7]) < c_b)
+                            if(*(cache_0 + pixel[9]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else
+            continue;
+      else
+        if(*(cache_0+-3) > cb)
+          if(*cache_2 > cb)
+            if(*(cache_0 + pixel[7]) > cb)
+              if(*(cache_1+-6) > cb)
+                if(*(cache_0 + pixel[6]) > cb)
+                  if(*(cache_0 + pixel[13]) > cb)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[9]) > cb)
+                        if(*(cache_0 + pixel[8]) > cb)
+                          goto success;
+                        else if(*(cache_0 + pixel[8]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_0 + pixel[0]) > cb)
+                            goto success;
+                          else
+                            continue;
+                      else if(*(cache_0 + pixel[9]) < c_b)
+                        continue;
+                      else
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[0]) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[3]) > cb)
+                        if(*(cache_0 + pixel[0]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[6]) < c_b)
+                  continue;
+                else
+                  if(*(cache_0 + pixel[15]) > cb)
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_0 + pixel[9]) > cb)
+                          if(*(cache_0 + pixel[8]) > cb)
+                            goto success;
+                          else if(*(cache_0 + pixel[8]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[1]) > cb)
+                              goto success;
+                            else
+                              continue;
+                        else if(*(cache_0 + pixel[9]) < c_b)
+                          continue;
+                        else
+                          if(*(cache_2+4) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              if(*(cache_0 + pixel[0]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                      else
+                        continue;
+                    else if(*(cache_0 + pixel[10]) < c_b)
+                      continue;
+                    else
+                      if(*(cache_0 + pixel[3]) > cb)
+                        if(*(cache_0 + pixel[1]) > cb)
+                          if(*(cache_2+4) > cb)
+                            if(*(cache_0 + pixel[13]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else if(*(cache_1+-6) < c_b)
+                continue;
+              else
+                if(*(cache_0+3) > cb)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        if(*(cache_0 + pixel[3]) > cb)
+                          if(*(cache_0 + pixel[13]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[7]) < c_b)
+              if(*(cache_2+4) > cb)
+                if(*(cache_1+-6) > cb)
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_0 + pixel[15]) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_0 + pixel[1]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_0 + pixel[3]) < c_b)
+                    continue;
+                  else
+                    if(*(cache_0 + pixel[10]) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_0 + pixel[0]) > cb)
+                          if(*(cache_0 + pixel[1]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                else if(*(cache_1+-6) < c_b)
+                  if(*(cache_0+3) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*(cache_0 + pixel[0]) > cb)
+                        if(*(cache_0 + pixel[3]) > cb)
+                          goto success;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0+3) > cb)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_0 + pixel[3]) > cb)
+                          if(*(cache_0 + pixel[0]) > cb)
+                            if(*(cache_0 + pixel[15]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else if(*(cache_2+4) < c_b)
+                continue;
+              else
+                if(*(cache_0 + pixel[9]) > cb)
+                  if(*(cache_0 + pixel[0]) > cb)
+                    if(*(cache_1+-6) > cb)
+                      goto success;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+            else
+              if(*(cache_0 + pixel[0]) > cb)
+                if(*(cache_0 + pixel[10]) > cb)
+                  if(*(cache_2+4) > cb)
+                    if(*(cache_0 + pixel[13]) > cb)
+                      if(*(cache_1+-6) > cb)
+                        if(*(cache_0 + pixel[15]) > cb)
+                          if(*(cache_0 + pixel[1]) > cb)
+                            goto success;
+                          else if(*(cache_0 + pixel[1]) < c_b)
+                            continue;
+                          else
+                            if(*(cache_0 + pixel[8]) > cb)
+                              goto success;
+                            else
+                              continue;
+                        else
+                          continue;
+                      else if(*(cache_1+-6) < c_b)
+                        continue;
+                      else
+                        if(*(cache_0+3) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                  else if(*(cache_2+4) < c_b)
+                    if(*(cache_0 + pixel[1]) > cb)
+                      if(*(cache_0 + pixel[3]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    if(*(cache_0 + pixel[9]) > cb)
+                      if(*(cache_0 + pixel[1]) > cb)
+                        if(*(cache_0 + pixel[13]) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            if(*(cache_1+-6) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else if(*(cache_0 + pixel[1]) < c_b)
+                        continue;
+                      else
+                        if(*(cache_0 + pixel[8]) > cb)
+                          if(*(cache_1+-6) > cb)
+                            if(*(cache_0 + pixel[13]) > cb)
+                              if(*(cache_0 + pixel[15]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                    else
+                      continue;
+                else if(*(cache_0 + pixel[10]) < c_b)
+                  if(*(cache_0+3) > cb)
+                    if(*(cache_0 + pixel[13]) > cb)
+                      if(*(cache_2+4) > cb)
+                        if(*(cache_0 + pixel[3]) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else if(*(cache_0+3) < c_b)
+                    continue;
+                  else
+                    if(*(cache_1+-6) > cb)
+                      if(*(cache_0 + pixel[3]) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  if(*(cache_0 + pixel[3]) > cb)
+                    if(*(cache_1+-6) > cb)
+                      if(*(cache_0 + pixel[13]) > cb)
+                        if(*(cache_2+4) > cb)
+                          if(*(cache_0 + pixel[15]) > cb)
+                            if(*(cache_0 + pixel[1]) > cb)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else if(*(cache_1+-6) < c_b)
+                      if(*(cache_0+3) > cb)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0+3) > cb)
+                        if(*(cache_0 + pixel[13]) > cb)
+                          if(*(cache_0 + pixel[1]) > cb)
+                            if(*(cache_2+4) > cb)
+                              if(*(cache_0 + pixel[15]) > cb)
+                                goto success;
+                              else
+                                continue;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else
+                continue;
+          else
+            continue;
+        else if(*(cache_0+-3) < c_b)
+          if(*(cache_0 + pixel[15]) > cb)
+            if(*cache_2 < c_b)
+              if(*(cache_0 + pixel[6]) < c_b)
+                if(*(cache_0 + pixel[10]) < c_b)
+                  if(*(cache_0 + pixel[7]) < c_b)
+                    goto success;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              continue;
+          else if(*(cache_0 + pixel[15]) < c_b)
+            if(*(cache_0 + pixel[10]) > cb)
+              if(*(cache_0+3) > cb)
+                continue;
+              else if(*(cache_0+3) < c_b)
+                if(*(cache_0 + pixel[3]) < c_b)
+                  if(*(cache_0 + pixel[13]) < c_b)
+                    goto success;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                if(*(cache_1+-6) < c_b)
+                  if(*(cache_0 + pixel[3]) < c_b)
+                    goto success;
+                  else
+                    continue;
+                else
+                  continue;
+            else if(*(cache_0 + pixel[10]) < c_b)
+              if(*cache_2 < c_b)
+                if(*(cache_0 + pixel[9]) > cb)
+                  if(*(cache_2+4) < c_b)
+                    goto success;
+                  else
+                    continue;
+                else if(*(cache_0 + pixel[9]) < c_b)
+                  if(*(cache_1+-6) > cb)
+                    continue;
+                  else if(*(cache_1+-6) < c_b)
+                    if(*(cache_0 + pixel[13]) < c_b)
+                      if(*(cache_0 + pixel[1]) > cb)
+                        if(*(cache_0 + pixel[7]) < c_b)
+                          goto success;
+                        else
+                          continue;
+                      else if(*(cache_0 + pixel[1]) < c_b)
+                        if(*(cache_0 + pixel[0]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[0]) < c_b)
+                          goto success;
+                        else
+                          if(*(cache_0 + pixel[7]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                      else
+                        if(*(cache_0 + pixel[7]) > cb)
+                          continue;
+                        else if(*(cache_0 + pixel[7]) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            if(*(cache_0 + pixel[8]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                    else
+                      continue;
+                  else
+                    if(*(cache_0+3) < c_b)
+                      if(*(cache_0 + pixel[3]) < c_b)
+                        goto success;
+                      else
+                        continue;
+                    else
+                      continue;
+                else
+                  if(*(cache_2+4) < c_b)
+                    if(*(cache_1+-6) > cb)
+                      continue;
+                    else if(*(cache_1+-6) < c_b)
+                      if(*(cache_0 + pixel[13]) < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      if(*(cache_0+3) < c_b)
+                        if(*(cache_0 + pixel[3]) < c_b)
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                  else
+                    continue;
+              else
+                continue;
+            else
+              if(*(cache_0 + pixel[3]) < c_b)
+                if(*(cache_1+-6) > cb)
+                  continue;
+                else if(*(cache_1+-6) < c_b)
+                  if(*(cache_2+4) < c_b)
+                    if(*(cache_0 + pixel[13]) < c_b)
+                      if(*cache_2 < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          if(*(cache_0 + pixel[0]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  if(*(cache_0+3) < c_b)
+                    if(*(cache_2+4) < c_b)
+                      if(*cache_2 < c_b)
+                        if(*(cache_0 + pixel[1]) < c_b)
+                          if(*(cache_0 + pixel[13]) < c_b)
+                            if(*(cache_0 + pixel[0]) < c_b)
+                              goto success;
+                            else
+                              continue;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+              else
+                continue;
+          else
+            if(*(cache_0 + pixel[6]) < c_b)
+              if(*cache_2 < c_b)
+                if(*(cache_0 + pixel[7]) < c_b)
+                  if(*(cache_1+-6) < c_b)
+                    if(*(cache_0 + pixel[13]) < c_b)
+                      if(*(cache_0 + pixel[10]) < c_b)
+                        if(*(cache_0 + pixel[9]) < c_b)
+                          if(*(cache_0 + pixel[8]) < c_b)
+                            goto success;
+                          else
+                            continue;
+                        else
+                          continue;
+                      else
+                        continue;
+                    else
+                      continue;
+                  else
+                    continue;
+                else
+                  continue;
+              else
+                continue;
+            else
+              continue;
+        else
+          continue;
+success:
+      if(total >= rsize) {
+        rsize *=2;
+        ret=(xy*)realloc(ret, rsize*sizeof(xy));
+      }
+      ret[total].x = cache_0-line_min;
+      ret[total++].y = y;
+    }
+  }
+  *num = total;
+  return ret;
+}
+
+int corner_score(const byte*  imp, const int *pointer_dir, int barrier) {
+  /*The score for a positive feature is sum of the difference between the pixels
+    and the barrier if the difference is positive. Negative is similar.
+    The score is the max of those two.
+
+    B = {x | x = points on the Bresenham circle around c}
+    Sp = { I(x) - t | x E B , I(x) - t > 0 }
+    Sn = { t - I(x) | x E B, t - I(x) > 0}
+
+    Score = max sum(Sp), sum(Sn)*/
+
+  int cb = *imp + barrier;
+  int c_b = *imp - barrier;
+  int sp=0, sn = 0;
+
+  int i=0;
+
+  for(i=0; i<16; i++)
+  {
+    int p = imp[pointer_dir[i]];
+
+    if(p > cb)
+      sp += p-cb;
+    else if(p < c_b)
+      sn += c_b-p;
+  }
+
+  if(sp > sn)
+    return sp;
+  else
+    return sn;
+}
+
+xy* fast_nonmax(const byte* im, int xsize, int ysize, int stride,
+                xy* corners, int numcorners, int barrier, int* numnx) {
+  /*Create a list of integer pointer offstes, corresponding to the */
+  /*direction offsets in dir[]*/
+  int  pointer_dir[16];
+  int* row_start = (int*) malloc(ysize * sizeof(int));
+  int* scores    = (int*) malloc(numcorners * sizeof(int));
+  xy*  nonmax_corners=(xy*)malloc(numcorners* sizeof(xy));
+  int num_nonmax=0;
+  int prev_row = -1;
+  int i, j;
+  int point_above = 0;
+  int point_below = 0;
+  (void) xsize;
+
+  pointer_dir[0] = 0 + 3 * stride;
+  pointer_dir[1] = 1 + 3 * stride;
+  pointer_dir[2] = 2 + 2 * stride;
+  pointer_dir[3] = 3 + 1 * stride;
+  pointer_dir[4] = 3 + 0 * stride;
+  pointer_dir[5] = 3 + -1 * stride;
+  pointer_dir[6] = 2 + -2 * stride;
+  pointer_dir[7] = 1 + -3 * stride;
+  pointer_dir[8] = 0 + -3 * stride;
+  pointer_dir[9] = -1 + -3 * stride;
+  pointer_dir[10] = -2 + -2 * stride;
+  pointer_dir[11] = -3 + -1 * stride;
+  pointer_dir[12] = -3 + 0 * stride;
+  pointer_dir[13] = -3 + 1 * stride;
+  pointer_dir[14] = -2 + 2 * stride;
+  pointer_dir[15] = -1 + 3 * stride;
+
+  if (numcorners < 5) {
+    free(row_start);
+    free(scores);
+    free(nonmax_corners);
+    return 0;
+  }
+
+  /*xsize ysize numcorners corners*/
+  /*Compute the score for each detected corner, and find where each row begins*/
+  /* (the corners are output in raster scan order). A beginning of -1 signifies*/
+  /* that there are no corners on that row.*/
+
+
+  for (i = 0; i < ysize; i++)
+    row_start[i] = -1;
+
+
+  for (i = 0; i< numcorners; i++) {
+    if (corners[i].y != prev_row) {
+      row_start[corners[i].y] = i;
+      prev_row = corners[i].y;
+    }
+    scores[i] = corner_score(im + corners[i].x + corners[i].y * stride,
+                             pointer_dir, barrier);
+  }
+  /*Point above points (roughly) to the pixel above the one of interest, if there*/
+  /*is a feature there.*/
+  for (i = 0; i < numcorners; i++) {
+    int score = scores[i];
+    xy pos = corners[i];
+
+    //Check left
+    if (i > 0)
+      if (corners[i-1].x == pos.x-1 && corners[i-1].y == pos.y &&
+          scores[i-1] > score)
+        continue;
+
+    //Check right
+    if (i < (numcorners - 1))
+      if (corners[i+1].x == pos.x+1 && corners[i+1].y == pos.y && scores[i+1] > score)
+        continue;
+
+    //Check above (if there is a valid row above)
+    if (pos.y != 0 && row_start[pos.y - 1] != -1) {
+      //Make sure that current point_above is one
+      //row above.
+      if (corners[point_above].y < pos.y - 1)
+        point_above = row_start[pos.y-1];
+
+      //Make point_above point to the first of the pixels above the current point,
+      //if it exists.
+      for (; corners[point_above].y < pos.y &&
+           corners[point_above].x < pos.x - 1; point_above++) {}
+
+
+      for (j = point_above;
+           corners[j].y < pos.y && corners[j].x <= pos.x + 1; j++) {
+        int x = corners[j].x;
+        if ((x == pos.x - 1 || x ==pos.x || x == pos.x+1) && (scores[j] > score))
+          goto cont;
+      }
+    }
+
+    //Check below (if there is anything below)
+    if (pos.y != ysize-1 && row_start[pos.y + 1] != -1 &&
+        point_below < numcorners) {  // Nothing below
+      if (corners[point_below].y < pos.y + 1)
+        point_below = row_start[pos.y+1];
+
+      // Make point below point to one of the pixels belowthe current point,
+      // if it exists.
+      for (; point_below < numcorners && corners[point_below].y == pos.y+1 &&
+             corners[point_below].x < pos.x - 1; point_below++) {}
+
+      for(j = point_below;
+          j < numcorners && corners[j].y == pos.y+1 &&
+          corners[j].x <= pos.x + 1; j++) {
+        int x = corners[j].x;
+        if ((x == pos.x - 1 || x ==pos.x || x == pos.x+1) && (scores[j] >score))
+          goto cont;
+      }
+    }
+
+    nonmax_corners[num_nonmax].x = corners[i].x;
+    nonmax_corners[num_nonmax].y = corners[i].y;
+    num_nonmax++;
+
+cont:
+    ;
+  }
+  *numnx = num_nonmax;
+  free(row_start);
+  free(scores);
+  return nonmax_corners;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Nonmax suppression wrapper
+
+#define NONMAX_BARRIER  5
+int NonmaxSuppression(unsigned char *frmbuf, int width, int height, int stride,
+                      int *frm_corners, int num_frm_corners) {
+  int num_frm_corners_nonmax;
+  xy *frm_corners_nonmax_xy;
+  frm_corners_nonmax_xy = fast_nonmax(frmbuf, width, height, stride,
+                                      (xy *)frm_corners, num_frm_corners,
+                                      NONMAX_BARRIER, &num_frm_corners_nonmax);
+  memcpy(frm_corners, frm_corners_nonmax_xy,
+         sizeof(int) * 2 * num_frm_corners_nonmax);
+  free(frm_corners_nonmax_xy);
+  return num_frm_corners_nonmax;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Fast_9 wrapper
+
+#define FAST_BARRIER    40
+int FastCornerDetect(unsigned char *buf, int width, int height, int stride,
+                     int *points, int max_points) {
+  int num_points;
+  xy *frm_corners_xy;
+  frm_corners_xy = fast_corner_detect_9(buf, width, height, stride,
+                                        FAST_BARRIER, &num_points);
+  num_points =
+      (num_points <= max_points ? num_points : max_points);
+  memcpy(points, frm_corners_xy, sizeof(int) * num_points * 2);
+  free(frm_corners_xy);
+  return NonmaxSuppression(buf, width, height, stride, points, num_points);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// Harris Corner detector
+
+#define HARRIS_THRESH   50
+
+#define GAUSS_FILT_SZ 7
+#define GAUSS_FILT_SZ_BY2 ((GAUSS_FILT_SZ - 1) / 2)
+
+double GaussianKernel[GAUSS_FILT_SZ_BY2 + 1][GAUSS_FILT_SZ_BY2 + 1] = {
+  {0.046701777738928, 0.041214174199798, 0.028326060061745, 0.01516184737296,},
+  {0.041214174199798, 0.036371381073904, 0.024997660266915, 0.013380283344101},
+  {0.028326060061745, 0.024997660266915, 0.017180623896310, 0.009196125289586},
+  {0.015161847372964, 0.013380283344101, 0.009196125289586, 0.004922331159344},
+};
+
+int HarrisCornerDetect(unsigned char *buf, int width, int height, int stride,
+                       int *points, int max_points) {
+  const double eps = 1e-6;
+  int i, j, num_points = 0;
+  double *gx2 = (double *)malloc(width * height * sizeof(double));
+  double *gy2 = (double *)malloc(width * height * sizeof(double));
+  double *gxy = (double *)malloc(width * height * sizeof(double));
+  double *met = (double *)malloc(width * height * sizeof(double));
+  double max_met = 0;
+  double thresh;
+  if (width < GAUSS_FILT_SZ + 2 || height < GAUSS_FILT_SZ + 2)
+    return 0;
+  // Sobel operator
+  for (i = 1; i < height - 1; ++i) {
+    for (j = 1; j < width - 1; ++j) {
+      gx2[i * width + j] = (buf[(i + 1) * stride + j] - buf[(i - 1) * stride + j]) * 2 +
+                           (buf[(i + 1) * stride + j - 1] - buf[(i - 1) * stride + j - 1]) +
+                           (buf[(i + 1) * stride + j + 1] - buf[(i - 1) * stride + j + 1]);
+      gy2[i * width + j] = (buf[i * stride + j + 1] - buf[i * stride + j - 1]) * 2 +
+                           (buf[(i - 1) * stride + j + 1] - buf[(i - 1) * stride + j - 1]) +
+                           (buf[(i + 1) * stride + j + 1] - buf[(i + 1) * stride + j - 1]);
+      gx2[i * width + j] /= 8;
+      gy2[i * width + j] /= 8;
+      gxy[i * width + j] = gx2[i * width + j] * gy2[i * width + j];
+      gx2[i * width + j] *= gx2[i * width + j];
+      gy2[i * width + j] *= gy2[i * width + j];
+    }
+  }
+  // Gaussian filter and metric computation
+  for (i = 1 + GAUSS_FILT_SZ_BY2; i < height - 1 - GAUSS_FILT_SZ_BY2; ++i) {
+    for (j = 1 + GAUSS_FILT_SZ_BY2; j < width - 1 - GAUSS_FILT_SZ_BY2; ++j) {
+      double valx2 = 0;
+      double valy2 = 0;
+      double valxy = 0;
+      int k, l;
+      valx2 = GaussianKernel[0][0] * gx2[i * width + j];
+      valy2 = GaussianKernel[0][0] * gy2[i * width + j];
+      valxy = GaussianKernel[0][0] * gxy[i * width + j];
+      for (k = 1; k <= GAUSS_FILT_SZ_BY2; k++) {
+        valx2 += GaussianKernel[k][0] * (gx2[(i + k) * width + j] +
+                                         gx2[(i - k) * width + j]);
+        valy2 += GaussianKernel[k][0] * (gy2[(i + k) * width + j] +
+                                         gy2[(i - k) * width + j]);
+        valxy += GaussianKernel[k][0] * (gxy[(i + k) * width + j] +
+                                         gxy[(i - k) * width + j]);
+      }
+      for (l = 1; l <= GAUSS_FILT_SZ_BY2; l++) {
+        valx2 += GaussianKernel[0][l] * (gx2[i * width + j + l] +
+                                         gx2[i * width + j - l]);
+        valy2 += GaussianKernel[0][l] * (gy2[i * width + j + l] +
+                                         gy2[i * width + j - l]);
+        valxy += GaussianKernel[0][l] * (gxy[i * width + j + l] +
+                                         gxy[i * width + j - l]);
+      }
+      for (k = 1; k <= GAUSS_FILT_SZ_BY2; k++) {
+        for (l = 1; l <= GAUSS_FILT_SZ_BY2; ++l) {
+          valx2 += GaussianKernel[k][l] * (gx2[(i + k) * width + (j + l)] +
+                                           gx2[(i - k) * width + (j + l)] +
+                                           gx2[(i + k) * width + (j - l)] +
+                                           gx2[(i - k) * width + (j - l)]);
+          valy2 += GaussianKernel[k][l] * (gy2[(i + k) * width + (j + l)] +
+                                           gy2[(i - k) * width + (j + l)] +
+                                           gy2[(i + k) * width + (j - l)] +
+                                           gy2[(i - k) * width + (j - l)]);
+          valxy += GaussianKernel[k][l] * (gxy[(i + k) * width + (j + l)] +
+                                           gxy[(i - k) * width + (j + l)] +
+                                           gxy[(i + k) * width + (j - l)] +
+                                           gxy[(i - k) * width + (j - l)]);
+        }
+      }
+      met[i * width + j] = (valx2 * valy2 - valxy * valxy)/(valx2 + valy2 + eps);
+      if (met[i * width + j] > max_met) max_met = met[i * width + j];
+    }
+  }
+  thresh = max_met < 2*HARRIS_THRESH ? max_met/2 : HARRIS_THRESH;
+  free(gx2);
+  free(gy2);
+  free(gxy);
+  for (i = 1 + GAUSS_FILT_SZ_BY2; i < height - 1 - GAUSS_FILT_SZ_BY2; ++i) {
+    for (j = 1 + GAUSS_FILT_SZ_BY2; j < width - 1 - GAUSS_FILT_SZ_BY2; ++j) {
+      if (met[i * width + j] > thresh) {
+        points[num_points * 2] = j;
+        points[num_points * 2 + 1] = i;
+        num_points++;
+        if (num_points == max_points) {
+          free(met);
+          return num_points;
+        }
+      }
+    }
+  }
+  free(met);
+  return NonmaxSuppression(buf, width, height, stride, points, num_points);
+}
diff --git a/vp9/encoder/vp9_corner_detect.h b/vp9/encoder/vp9_corner_detect.h
new file mode 100644 (file)
index 0000000..51c7785
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#ifndef VP9_ENCODER_VP9_CORNER_DETECT_H
+#define VP9_ENCODER_VP9_CORNER_DETECT_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+int HarrisCornerDetect(unsigned char *buf, int width, int height, int stride,
+                       int *points, int max_points);
+int FastCornerDetect(unsigned char *buf, int width, int height, int stride,
+                     int *points, int max_points);
+
+#endif  // VP9_ENCODER_VP9_CORNER_DETECT_H
diff --git a/vp9/encoder/vp9_corner_match.c b/vp9/encoder/vp9_corner_match.c
new file mode 100644 (file)
index 0000000..5c4fd13
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+
+#include "vp9_corner_match.h"
+
+#define MATCH_SZ 21
+#define MATCH_SZ_BY2 ((MATCH_SZ - 1)/2)
+#define MATCH_SZ_SQ (MATCH_SZ * MATCH_SZ)
+#define SEARCH_SZ 9
+#define SEARCH_SZ_BY2 ((SEARCH_SZ - 1)/2)
+
+#define THRESHOLD_NCC   0.80
+
+typedef struct {
+  int x, y;
+  int rx, ry;
+} correspondence;
+
+static double compute_variance(unsigned char *im, int stride,
+                               int x, int y, double *mean) {
+  double sum = 0.0;
+  double sumsq = 0.0;
+  double var;
+  int i, j;
+  for (i = 0; i < MATCH_SZ; ++i)
+    for (j = 0; j < MATCH_SZ; ++j) {
+      sum   += im[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)];
+      sumsq += im[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)] *
+               im[(i + y - MATCH_SZ_BY2) * stride + (j + x - MATCH_SZ_BY2)];
+    }
+  var = (sumsq * MATCH_SZ_SQ - sum * sum) / (MATCH_SZ_SQ * MATCH_SZ_SQ);
+  if (mean) *mean = sum / MATCH_SZ_SQ;
+  return var;
+}
+
+static double compute_cross_correlation(unsigned char *im1, int stride1,
+                                        int x1, int y1,
+                                        unsigned char *im2, int stride2,
+                                        int x2, int y2) {
+  double sum1 = 0;
+  double sum2 = 0;
+  double cross = 0;
+  double corr;
+  int i, j;
+  for (i = 0; i < MATCH_SZ; ++i)
+    for (j = 0; j < MATCH_SZ; ++j) {
+      sum1 += im1[(i + y1 - MATCH_SZ_BY2) * stride1 + (j + x1 - MATCH_SZ_BY2)];
+      sum2 += im2[(i + y2 - MATCH_SZ_BY2) * stride2 + (j + x2 - MATCH_SZ_BY2)];
+      cross += im1[(i + y1 - MATCH_SZ_BY2) * stride1 + (j + x1 - MATCH_SZ_BY2)] *
+               im2[(i + y2 - MATCH_SZ_BY2) * stride2 + (j + x2 - MATCH_SZ_BY2)];
+    }
+  corr = (cross * MATCH_SZ_SQ - sum1 * sum2) / (MATCH_SZ_SQ * MATCH_SZ_SQ);
+  return corr;
+}
+
+static int is_eligible_point(double pointx, double pointy,
+                             int width, int height) {
+  return (pointx >= MATCH_SZ_BY2 && pointy >= MATCH_SZ_BY2 &&
+          pointx + MATCH_SZ_BY2 < width && pointy + MATCH_SZ_BY2 < height);
+}
+
+static int is_eligible_distance(double point1x, double point1y,
+                                double point2x, double point2y,
+                                int width, int height) {
+  const int thresh = (width < height ? height : width) >> 4;
+  return ((point1x - point2x) * (point1x - point2x) +
+          (point1y - point2y) * (point1y - point2y)) <= thresh * thresh;
+}
+
+static void improve_correspondence(unsigned char *frm, unsigned char *ref,
+                                   int width, int height,
+                                   int frm_stride, int ref_stride,
+                                   correspondence *correspondences,
+                                   int num_correspondences) {
+  int i;
+  for (i = 0; i < num_correspondences; ++i) {
+    double template_norm = compute_variance(frm, frm_stride,
+                                            correspondences[i].x,
+                                            correspondences[i].y, NULL);
+    int x, y, best_x = 0, best_y = 0;
+    double best_match_ncc = 0.0;
+    for (y = -SEARCH_SZ_BY2; y <= SEARCH_SZ_BY2; ++y) {
+      for (x = -SEARCH_SZ_BY2; x <= SEARCH_SZ_BY2; ++x) {
+        double match_ncc;
+        double subimage_norm;
+        if (!is_eligible_point(correspondences[i].rx + x,
+                               correspondences[i].ry + y,
+                               width, height))
+          continue;
+        if (!is_eligible_distance(
+            correspondences[i].x, correspondences[i].y,
+            correspondences[i].rx + x, correspondences[i].ry + y,
+            width, height))
+          continue;
+        subimage_norm = compute_variance(ref, ref_stride,
+                                         correspondences[i].rx + x,
+                                         correspondences[i].ry + y, NULL);
+        match_ncc = compute_cross_correlation(
+            frm, frm_stride,
+            correspondences[i].x, correspondences[i].y,
+            ref, ref_stride,
+            correspondences[i].rx + x, correspondences[i].ry + y) /
+            sqrt(template_norm * subimage_norm);
+        if (match_ncc > best_match_ncc) {
+          best_match_ncc = match_ncc;
+          best_y = y;
+          best_x = x;
+        }
+      }
+    }
+    correspondences[i].rx += best_x;
+    correspondences[i].ry += best_y;
+  }
+  for (i = 0; i < num_correspondences; ++i) {
+    double template_norm = compute_variance(
+        ref, ref_stride, correspondences[i].rx, correspondences[i].ry, NULL);
+    int x, y, best_x = 0, best_y = 0;
+    double best_match_ncc = 0.0;
+    for (y = -SEARCH_SZ_BY2; y <= SEARCH_SZ_BY2; ++y)
+      for (x = -SEARCH_SZ_BY2; x <= SEARCH_SZ_BY2; ++x) {
+        double match_ncc;
+        double subimage_norm;
+        if (!is_eligible_point(correspondences[i].x + x,
+                               correspondences[i].y + y, width, height))
+          continue;
+        if (!is_eligible_distance(
+            correspondences[i].x + x, correspondences[i].y + y,
+            correspondences[i].rx, correspondences[i].ry, width, height))
+          continue;
+        subimage_norm = compute_variance(
+            frm, frm_stride,
+            correspondences[i].x + x, correspondences[i].y + y, NULL);
+        match_ncc = compute_cross_correlation(
+            frm, frm_stride, correspondences[i].x + x, correspondences[i].y + y,
+            ref, ref_stride, correspondences[i].rx, correspondences[i].ry) /
+            sqrt(template_norm * subimage_norm);
+        if (match_ncc > best_match_ncc) {
+          best_match_ncc = match_ncc;
+          best_y = y;
+          best_x = x;
+        }
+      }
+    correspondences[i].x += best_x;
+    correspondences[i].y += best_y;
+  }
+}
+
+int determine_correspondence(unsigned char *frm,
+                             int *frm_corners, int num_frm_corners,
+                             unsigned char *ref,
+                             int *ref_corners, int num_ref_corners,
+                             int width, int height,
+                             int frm_stride, int ref_stride,
+                             int *correspondence_pts) {
+  // Debargha: Improve this to include 2-way match
+  int i, j;
+  correspondence *correspondences = (correspondence *)correspondence_pts;
+  int num_correspondences = 0;
+  for (i = 0; i < num_frm_corners; ++i) {
+    double best_match_ncc = 0.0;
+    double template_norm;
+    int best_match_j = -1;
+    if (!is_eligible_point(frm_corners[2 * i], frm_corners[2 * i + 1],
+                           width, height))
+      continue;
+    template_norm = compute_variance(
+        frm, frm_stride, frm_corners[2 * i], frm_corners[2*i+1], NULL);
+    for (j = 0; j < num_ref_corners; ++j) {
+      double match_ncc;
+      double subimage_norm;
+      if (!is_eligible_point(ref_corners[2 * j], ref_corners[2 * j + 1],
+                             width, height))
+        continue;
+      if (!is_eligible_distance(frm_corners[2 * i], frm_corners[2 * i + 1],
+                                ref_corners[2 * j], ref_corners[2 * j + 1],
+                                width, height))
+        continue;
+      subimage_norm = compute_variance(
+          ref, ref_stride, ref_corners[2*j], ref_corners[2 * j + 1], NULL);
+      match_ncc = compute_cross_correlation(frm, frm_stride,
+                                            frm_corners[2 * i],
+                                            frm_corners[2 * i + 1],
+                                            ref, ref_stride,
+                                            ref_corners[2 * j],
+                                            ref_corners[2 * j + 1]) /
+          sqrt(template_norm * subimage_norm);
+      if (match_ncc > best_match_ncc) {
+        best_match_ncc = match_ncc;
+        best_match_j = j;
+      }
+    }
+    if (best_match_ncc > THRESHOLD_NCC) {
+      correspondences[num_correspondences].x = frm_corners[2 * i];
+      correspondences[num_correspondences].y = frm_corners[2 * i + 1];
+      correspondences[num_correspondences].rx = ref_corners[2 * best_match_j];
+      correspondences[num_correspondences].ry =
+          ref_corners[2 * best_match_j + 1];
+      /*
+      printf("  %d %d %d %d\n",
+             correspondences[num_correspondences].x,
+             correspondences[num_correspondences].y,
+             correspondences[num_correspondences].rx,
+             correspondences[num_correspondences].ry);
+             */
+      num_correspondences++;
+    }
+  }
+  improve_correspondence(frm, ref, width, height, frm_stride, ref_stride,
+                         correspondences, num_correspondences);
+  return num_correspondences;
+}
diff --git a/vp9/encoder/vp9_corner_match.h b/vp9/encoder/vp9_corner_match.h
new file mode 100644 (file)
index 0000000..217d4d1
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#ifndef VP9_ENCODER_VP9_CORNER_MATCH_H
+#define VP9_ENCODER_VP9_CORNER_MATCH_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+int determine_correspondence(unsigned char *frm,
+                             int *frm_corners, int num_frm_corners,
+                             unsigned char *ref,
+                             int *ref_corners, int num_ref_corners,
+                             int width, int height,
+                             int frm_stride, int ref_stride,
+                             int *correspondence_pts);
+
+#endif  // VP9_ENCODER_VP9_CORNER_MATCH_H
diff --git a/vp9/encoder/vp9_global_motion.c b/vp9/encoder/vp9_global_motion.c
new file mode 100644 (file)
index 0000000..6570e0c
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+#include <assert.h>
+
+#include "vp9_corner_detect.h"
+#include "vp9_corner_match.h"
+#include "vp9_ransac.h"
+#include "vp9_global_motion.h"
+
+// #define VERBOSE
+
+// Default is Harris
+#define USE_FAST_CORNER
+
+#define MIN_INLIER_PROB 0.1
+
+#define MAX_CORNERS 4096
+
+inline int get_numparams(TransformationType type) {
+  switch (type) {
+    case HOMOGRAPHY:
+      return 9;
+    case AFFINE:
+      return 6;
+    case ROTZOOM:
+      return 4;
+    default:
+      assert(0);
+      return 0;
+  }
+}
+
+inline ransacType get_ransacType(TransformationType type) {
+  switch (type) {
+    case HOMOGRAPHY:
+      return ransacHomography;
+    case AFFINE:
+      return ransacAffine;
+    case ROTZOOM:
+      return ransacRotZoom;
+    default:
+      assert(0);
+      return NULL;
+  }
+}
+
+inline projectPointsType get_projectPointsType(TransformationType type) {
+  switch (type) {
+    case HOMOGRAPHY:
+      return projectPointsHomography;
+    case AFFINE:
+      return projectPointsAffine;
+    case ROTZOOM:
+      return projectPointsRotZoom;
+    default:
+      assert(0);
+      return NULL;
+  }
+}
+
+static double compute_error_score(TransformationType type,
+                                  int *points1, int stride1,
+                                  int *points2, int stride2,
+                                  int npoints, double *H,
+                                  int *map) {
+  int i, n = 0;
+  double ot[2], pt[2];
+  int *mp1 = points1;
+  int *mp2 = points2;
+  double sqerr = 0.0;
+  const int numparams = get_numparams(type);
+
+  projectPointsType projectPoints = get_projectPointsType(type);
+  if (projectPoints == NULL) return -1.0;
+  if (map) {
+    for (i = 0; i < npoints; ++i, mp1+=stride1, mp2+=stride2) {
+      if (map[i] != -1) {
+        ot[0] = mp1[0];
+        ot[1] = mp1[1];
+        projectPoints(&H[map[i] * numparams], ot, pt, 1, stride1, stride2);
+        sqerr += (pt[0] - mp2[0]) * (pt[0] - mp2[0]) +
+                 (pt[1] - mp2[1]) * (pt[1] - mp2[1]);
+        n++;
+      }
+    }
+  } else {
+    for (i = 0; i < npoints; ++i, mp1+=stride1, mp2+=stride2) {
+      ot[0] = mp1[0];
+      ot[1] = mp1[1];
+      projectPoints(H, ot, pt, 1, stride1, stride2);
+      sqerr += (pt[0] - mp2[0]) * (pt[0] - mp2[0]) +
+               (pt[1] - mp2[1]) * (pt[1] - mp2[1]);
+      n++;
+    }
+  }
+  return sqrt(sqerr / n);
+}
+
+static int compute_global_motion_single(TransformationType type,
+                                        int *correspondences,
+                                        int num_correspondences,
+                                        double *H,
+                                        int *inlier_map) {
+  double *mp, *matched_points;
+  int *cp = correspondences;
+  int i, result;
+  int num_inliers = 0;
+  ransacType ransac = get_ransacType(type);
+  if (ransac == NULL)
+    return 0;
+  matched_points =
+      (double *)malloc(4 * num_correspondences * sizeof(double));
+
+  for (mp = matched_points, cp = correspondences, i = 0;
+       i < num_correspondences; ++i) {
+    *mp++ = *cp++;
+    *mp++ = *cp++;
+    *mp++ = *cp++;
+    *mp++ = *cp++;
+  }
+  result = ransac(matched_points, num_correspondences,
+                  &num_inliers, inlier_map, H);
+  if (!result && num_inliers < MIN_INLIER_PROB * num_correspondences) {
+    result = 1;
+    num_inliers = 0;
+  }
+  if (!result) {
+    for (i = 0; i < num_correspondences; ++i) {
+      inlier_map[i] = inlier_map[i] - 1;
+    }
+  }
+  free(matched_points);
+  return num_inliers;
+}
+
+// Returns number of models actually returned: 1 - if success, 0 - if failure
+int vp9_compute_global_motion_single_feature_based(TransformationType type,
+                                                   unsigned char *frmbuf,
+                                                   unsigned char *refbuf,
+                                                   int width,
+                                                   int height,
+                                                   int frm_stride,
+                                                   int ref_stride,
+                                                   double *H) {
+  int num_frm_corners, num_ref_corners;
+  int num_correspondences;
+  int *correspondences;
+  int num_inliers;
+  int *inlier_map = NULL;
+  int frm_corners[2 * MAX_CORNERS], ref_corners[2 * MAX_CORNERS];
+
+#ifdef USE_FAST_CORNER
+  num_frm_corners = FastCornerDetect(frmbuf, width, height, frm_stride,
+                                     frm_corners, MAX_CORNERS);
+  num_ref_corners = FastCornerDetect(refbuf, width, height, ref_stride,
+                                     ref_corners, MAX_CORNERS);
+#else
+  num_frm_corners = HarrisCornerDetect(frmbuf, width, height, frm_stride,
+                                       frm_corners, MAX_CORNERS);
+  num_ref_corners = HarrisCornerDetect(refbuf, width, height, ref_stride,
+                                       ref_corners, MAX_CORNERS);
+#endif
+#ifdef VERBOSE
+  printf("Frame corners     = %d\n", num_frm_corners);
+  printf("Reference corners = %d\n", num_ref_corners);
+#endif
+
+  correspondences = (int *)malloc(
+      num_frm_corners * 4 * sizeof(int));
+
+  num_correspondences = determine_correspondence(frmbuf, (int*)frm_corners,
+                                                 num_frm_corners,
+                                                 refbuf, (int*)ref_corners,
+                                                 num_ref_corners,
+                                                 width, height,
+                                                 frm_stride, ref_stride,
+                                                 correspondences);
+#ifdef VERBOSE
+  printf("Number of correspondences = %d\n", num_correspondences);
+#endif
+  inlier_map = (int *)malloc(num_correspondences * sizeof(int));
+  num_inliers = compute_global_motion_single(type, correspondences,
+                                             num_correspondences, H,
+                                             inlier_map);
+#ifdef VERBOSE
+  printf("Inliers = %d\n", num_inliers);
+  printf("Error Score (inliers) = %g\n",
+         compute_error_score(type, correspondences, 4, correspondences + 2, 4,
+                             num_correspondences, H, inlier_map));
+#endif
+  free(correspondences);
+  free(inlier_map);
+  return (num_inliers > 0);
+}
+
+static int compute_global_motion_multiple(TransformationType type,
+                                          int *correspondences,
+                                          int num_correspondences,
+                                          double *H,
+                                          int max_models,
+                                          double inlier_prob,
+                                          int *num_models,
+                                          int *processed_mask) {
+  int *cp = correspondences;
+  double *mp, *matched_points;
+  int *best_inlier_mask;
+  int i, result;
+  int num_points = 0;
+  int num_inliers = 0;
+  int num_inliers_sum = 0;
+  const int numparams = get_numparams(type);
+  ransacType ransac = get_ransacType(type);
+  if (ransac == NULL)
+    return 0;
+  matched_points =
+      (double *)malloc(4 * num_correspondences * sizeof(double));
+  best_inlier_mask =
+      (int *)malloc(num_correspondences * sizeof(int));
+  for (i = 0; i < num_correspondences; ++i)
+    processed_mask[i] = -1;
+  *num_models = 0;
+
+  while ((double)num_inliers_sum / (double)num_correspondences < inlier_prob &&
+         *num_models < max_models) {
+    num_points = 0;
+    for (mp = matched_points, cp = correspondences, i = 0;
+         i < num_correspondences; ++i) {
+      if (processed_mask[i] == -1) {
+        *mp++ = *cp++;
+        *mp++ = *cp++;
+        *mp++ = *cp++;
+        *mp++ = *cp++;
+        num_points++;
+      } else {
+        cp += 4;
+      }
+    }
+    result = ransac(matched_points, num_points,
+                    &num_inliers, best_inlier_mask,
+                    &H[(*num_models) * numparams]);
+    if (!result && num_inliers < MIN_INLIER_PROB * num_correspondences) {
+      result = 1;
+      num_inliers = 0;
+    }
+    if (!result) {
+      num_points = 0;
+      for (i = 0; i < num_correspondences; ++i) {
+        if (processed_mask[i] == -1) {
+          if (best_inlier_mask[num_points]) processed_mask[i] = *num_models;
+          num_points++;
+        }
+      }
+      num_inliers_sum += num_inliers;
+      (*num_models)++;
+    } else {
+      break;
+    }
+  }
+  free(matched_points);
+  free(best_inlier_mask);
+  return num_inliers_sum;
+}
+
+// Returns number of models actually returned
+int vp9_compute_global_motion_multiple_feature_based(TransformationType type,
+                                                     unsigned char *frmbuf,
+                                                     unsigned char *refbuf,
+                                                     int width,
+                                                     int height,
+                                                     int frm_stride,
+                                                     int ref_stride,
+                                                     int max_models,
+                                                     double inlier_prob,
+                                                     double *H) {
+  int num_frm_corners, num_ref_corners;
+  int num_correspondences;
+  int *correspondences;
+  int num_inliers;
+  int frm_corners[2 * MAX_CORNERS], ref_corners[2 * MAX_CORNERS];
+  int num_models = 0;
+  int *inlier_map = NULL;
+
+#ifdef USE_FAST_CORNER
+  num_frm_corners = FastCornerDetect(frmbuf, width, height, frm_stride,
+                                     frm_corners, MAX_CORNERS);
+  num_ref_corners = FastCornerDetect(refbuf, width, height, ref_stride,
+                                     ref_corners, MAX_CORNERS);
+#else
+  num_frm_corners = HarrisCornerDetect(frmbuf, width, height, frm_stride,
+                                       frm_corners, MAX_CORNERS);
+  num_ref_corners = HarrisCornerDetect(refbuf, width, height, ref_stride,
+                                       ref_corners, MAX_CORNERS);
+#endif
+#ifdef VERBOSE
+  printf("Frame corners     = %d\n", num_frm_corners);
+  printf("Reference corners = %d\n", num_ref_corners);
+#endif
+
+  correspondences = (int *)malloc(num_frm_corners * 4 * sizeof(int));
+
+  num_correspondences = determine_correspondence(frmbuf, (int*)frm_corners,
+                                                 num_frm_corners,
+                                                 refbuf, (int*)ref_corners,
+                                                 num_ref_corners,
+                                                 width, height,
+                                                 frm_stride, ref_stride,
+                                                 correspondences);
+#ifdef VERBOSE
+  printf("Number of correspondences = %d\n", num_correspondences);
+#endif
+  inlier_map = (int *)malloc(num_correspondences * sizeof(int));
+  num_inliers = compute_global_motion_multiple(type, correspondences,
+                                               num_correspondences, H,
+                                               max_models, inlier_prob,
+                                               &num_models, inlier_map);
+#ifdef VERBOSE
+  printf("Models = %d, Inliers = %d\n", num_models, num_inliers);
+  if (num_models)
+    printf("Error Score (inliers) = %g\n",
+           compute_error_score(type, correspondences, 4, correspondences + 2, 4,
+                               num_correspondences, H, inlier_map));
+#endif
+  (void) num_inliers;
+  free(correspondences);
+  free(inlier_map);
+  return num_models;
+}
diff --git a/vp9/encoder/vp9_global_motion.h b/vp9/encoder/vp9_global_motion.h
new file mode 100644 (file)
index 0000000..aea8d8a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VP9_ENCODER_VP9_GLOBAL_MOTION_H
+#define VP9_ENCODER_VP9_GLOBAL_MOTION_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+#include <assert.h>
+
+#include "vp9_corner_detect.h"
+#include "vp9_corner_match.h"
+#include "vp9_ransac.h"
+
+// Default is Harris
+#define USE_FAST_CORNER
+#define MAX_CORNERS 4096
+
+typedef enum {
+  UNKNOWN = -1,
+  HOMOGRAPHY,  // homography, 8-parameter
+  AFFINE,      // affine, 6-parameter
+  ROTZOOM      // simplified affine with rotation and zoom only, 4-parameter
+} TransformationType;
+
+inline int get_numparams(TransformationType type);
+
+inline ransacType get_ransacType(TransformationType type);
+
+inline projectPointsType get_projectPointsType(TransformationType type);
+
+// Returns number of models actually returned: 1 - if success, 0 - if failure
+int vp9_compute_global_motion_single_feature_based(TransformationType type,
+                                                   unsigned char *frm,
+                                                   unsigned char *ref,
+                                                   int width,
+                                                   int height,
+                                                   int frm_stride,
+                                                   int ref_stride,
+                                                   double *H);
+
+// Returns number of models actually returned: 1+ - #models, 0 - if failure
+// max_models is the maximum number of models returned
+// inlier_prob is the probability of being inlier over all the models
+// combined, beyond which no more models are computed.
+// Ex. if max_models = 4, and inlier_prob = 0.8, and during the
+// process three models together already cover more than 80% of the
+// matching points, then only three models are returned.
+int vp9_compute_global_motion_multiple_feature_based(TransformationType type,
+                                                     unsigned char *frm,
+                                                     unsigned char *ref,
+                                                     int width,
+                                                     int height,
+                                                     int frm_stride,
+                                                     int ref_stride,
+                                                     int max_models,
+                                                     double inlier_prob,
+                                                     double *H);
+
+#endif  // VP9_ENCODER_VP9_GLOBAL_MOTION_H
diff --git a/vp9/encoder/vp9_ransac.c b/vp9/encoder/vp9_ransac.c
new file mode 100644 (file)
index 0000000..da3bd18
--- /dev/null
@@ -0,0 +1,951 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <memory.h>
+#include <math.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "vp9_ransac.h"
+
+#define MAX_PARAMDIM 9
+#define MAX_MINPTS   4
+
+// svdcmp
+// Adopted from Numerical Recipes in C
+
+static const double TINY_NEAR_ZERO = 1.0E-12;
+
+static inline double SIGN(double a, double b) {
+  return ((b) >= 0 ? fabs(a) : -fabs(a));
+}
+
+static inline double PYTHAG(double a, double b) {
+  double absa, absb, ct;
+  absa = fabs(a);
+  absb = fabs(b);
+
+  if(absa > absb) {
+    ct = absb/absa;
+    return absa * sqrt(1.0 + ct*ct);
+  } else {
+    ct = absa/absb;
+    return (absb == 0) ? 0 : absb * sqrt(1.0 + ct*ct);
+  }
+}
+
+inline int IMIN(int a, int b) {
+  return (((a) < (b)) ? (a) : (b));
+}
+
+inline int IMAX(int a, int b) {
+  return (((a) < (b)) ? (b) : (a));
+}
+
+static void MultiplyMat(double *m1, double *m2, double *res,
+                        const int M1, const int N1, const int N2) {
+  int timesInner = N1;
+  int timesRows = M1;
+  int timesCols = N2;
+  double sum;
+
+  int row, col, inner;
+  for( row = 0; row < timesRows; ++row ) {
+    for( col = 0; col < timesCols; ++col ) {
+      sum = 0;
+      for (inner = 0; inner < timesInner; ++inner )
+        sum += m1[row*N1 + inner] * m2[inner*N2 + col];
+      *(res++) = sum;
+    }
+  }
+}
+
+static int svdcmp_(double **u, int m, int n, double w[], double **v) {
+  const int max_its = 30;
+  int flag, i, its, j, jj, k, l, nm;
+  double anorm, c, f, g, h, s, scale, x, y, z;
+  double *rv1 = (double *)malloc(sizeof(double) * (n + 1));
+  g = scale = anorm = 0.0;
+  for (i=0;i<n;i++) {
+    l=i+1;
+    rv1[i]=scale*g;
+    g=s=scale=0.0;
+    if (i < m) {
+      for (k=i;k<m;k++) scale += fabs(u[k][i]);
+      if (scale) {
+        for (k=i; k<m; k++) {
+          u[k][i] /= scale;
+          s += u[k][i]*u[k][i];
+        }
+        f = u[i][i];
+        g = -SIGN(sqrt(s), f);
+        h=f*g-s;
+        u[i][i]=f-g;
+        for (j=l;j<n;j++) {
+          for (s=0.0,k=i;k<m;k++) s += u[k][i]*u[k][j];
+          f=s/h;
+          for (k=i;k<m;k++) u[k][j] += f*u[k][i];
+        }
+        for (k=i;k<m;k++) u[k][i] *= scale;
+      }
+    }
+    w[i]=scale *g;
+    g=s=scale=0.0;
+    if (i < m && i != n - 1) {
+      for (k=l;k<n;k++) scale += fabs(u[i][k]);
+      if (scale) {
+        for (k=l;k<n;k++) {
+          u[i][k] /= scale;
+          s += u[i][k]*u[i][k];
+        }
+        f=u[i][l];
+        g = -SIGN(sqrt(s),f);
+        h=f*g-s;
+        u[i][l]=f-g;
+        for (k=l;k<n;k++) rv1[k]=u[i][k]/h;
+        for (j=l;j<m;j++) {
+          for (s=0.0,k=l;k<n;k++) s += u[j][k]*u[i][k];
+          for (k=l;k<n;k++) u[j][k] += s*rv1[k];
+        }
+        for (k=l;k<n;k++) u[i][k] *= scale;
+      }
+    }
+    anorm=fmax(anorm,(fabs(w[i])+fabs(rv1[i])));
+  }
+
+  for (i=n-1;i>=0;i--) {
+    if (i < n - 1) {
+      if (g) {
+        for (j=l;j<n;j++) v[j][i]=(u[i][j]/u[i][l])/g;
+        for (j=l;j<n;j++) {
+          for (s=0.0,k=l;k<n;k++) s += u[i][k]*v[k][j];
+          for (k=l;k<n;k++) v[k][j] += s*v[k][i];
+        }
+      }
+      for (j=l;j<n;j++) v[i][j]=v[j][i]=0.0;
+    }
+    v[i][i]=1.0;
+    g=rv1[i];
+    l=i;
+  }
+
+  for (i = IMIN(m,n) - 1; i>=0; i--) {
+    l=i+1;
+    g=w[i];
+    for (j=l;j<n;j++) u[i][j]=0.0;
+    if (g) {
+      g=1.0/g;
+      for (j=l;j<n;j++) {
+        for (s=0.0,k=l;k<m;k++) s += u[k][i]*u[k][j];
+        f = (s/u[i][i])*g;
+        for (k=i;k<m;k++) u[k][j] += f*u[k][i];
+      }
+      for (j=i;j<m;j++) u[j][i] *= g;
+    } else for (j=i;j<m;j++) u[j][i]=0.0;
+    ++u[i][i];
+  }
+  for (k=n-1;k>=0;k--) {
+    for (its=0;its<max_its;its++) {
+      flag=1;
+      for (l=k;l>=0;l--) {
+        nm=l-1;
+        if ((double)(fabs(rv1[l])+anorm) == anorm || nm < 0) {
+          flag=0;
+          break;
+        }
+        if ((double)(fabs(w[nm])+anorm) == anorm) break;
+      }
+      if (flag) {
+        c=0.0;
+        s=1.0;
+        for (i=l;i<=k;i++) {
+          f=s*rv1[i];
+          rv1[i]=c*rv1[i];
+          if ((double)(fabs(f)+anorm) == anorm) break;
+          g=w[i];
+          h=PYTHAG(f,g);
+          w[i]=h;
+          h=1.0/h;
+          c=g*h;
+          s = -f*h;
+          for (j=0;j<m;j++) {
+            y=u[j][nm];
+            z=u[j][i];
+            u[j][nm]=y*c+z*s;
+            u[j][i]=z*c-y*s;
+          }
+        }
+      }
+      z=w[k];
+      if (l == k) {
+        if (z < 0.0) {
+          w[k] = -z;
+          for (j=0;j<n;j++) v[j][k] = -v[j][k];
+        }
+        break;
+      }
+      if (its == max_its - 1) {
+        return 1;
+      }
+      assert(k > 0);
+      x=w[l];
+      nm=k-1;
+      y=w[nm];
+      g=rv1[nm];
+      h=rv1[k];
+      f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
+      g=PYTHAG(f,1.0);
+      f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
+      c=s=1.0;
+      for (j=l;j<=nm;j++) {
+        i=j+1;
+        g=rv1[i];
+        y=w[i];
+        h=s*g;
+        g=c*g;
+        z=PYTHAG(f,h);
+        rv1[j]=z;
+        c=f/z;
+        s=h/z;
+        f=x*c+g*s;
+        g = g*c-x*s;
+        h=y*s;
+        y *= c;
+        for (jj=0;jj<n;jj++) {
+          x=v[jj][j];
+          z=v[jj][i];
+          v[jj][j]=x*c+z*s;
+          v[jj][i]=z*c-x*s;
+        }
+        z=PYTHAG(f,h);
+        w[j]=z;
+        if (z) {
+          z=1.0/z;
+          c=f*z;
+          s=h*z;
+        }
+        f=c*g+s*y;
+        x=c*y-s*g;
+        for (jj=0;jj<m;jj++) {
+          y=u[jj][j];
+          z=u[jj][i];
+          u[jj][j]=y*c+z*s;
+          u[jj][i]=z*c-y*s;
+        }
+      }
+      rv1[l]=0.0;
+      rv1[k]=f;
+      w[k]=x;
+    }
+  }
+  free(rv1);
+  return 0;
+}
+
+static int SVD(double *U, double *W, double *V, double *matx, int M, int N) {
+  // Assumes allocation for U is MxN
+  double **nrU, **nrV;
+  int problem, i;
+
+  nrU = (double **)malloc((M)*sizeof(double*));
+  nrV = (double **)malloc((N)*sizeof(double*));
+  problem = !(nrU && nrV);
+  if (!problem) {
+    problem = 0;
+    for (i=0; i<M; i++) {
+      nrU[i] = &U[i * N];
+    }
+    for(i=0; i<N; i++) {
+      nrV[i] = &V[i * N];
+    }
+  }
+  if (problem) {
+    return 1;
+  }
+
+  /* copy from given matx into nrU */
+  for (i=0; i<M; i++) {
+    memcpy(&(nrU[i][0]), matx + N*i, N*sizeof(double));
+  }
+
+  /* HERE IT IS: do SVD */
+  if (svdcmp_(nrU, M, N, W, nrV)) {
+    return 1;
+  }
+
+  /* free Numerical Recipes arrays */
+  free(nrU);
+  free(nrV);
+
+  return 0;
+}
+
+int PseudoInverse(double *inv, double *matx, const int M, const int N) {
+  double *U, *W, *V, ans;
+  int i, j, k;
+  U = (double *)malloc(M*N*sizeof(double));
+  W = (double *)malloc(N*sizeof(double));
+  V = (double *)malloc(N*N*sizeof(double));
+
+  if (!(U && W && V)) {
+    return 1;
+  }
+  if (SVD(U, W, V, matx, M, N)) {
+    return 1;
+  }
+  for (i=0; i<N; i++) {
+    if (fabs(W[i]) < TINY_NEAR_ZERO) {
+      return 1;
+    }
+  }
+
+  for (i=0; i<N; i++) {
+    for (j=0; j<M; j++) {
+      ans = 0;
+      for (k=0; k<N; k++) {
+        ans += V[k + N*i]*U[k + N*j]/W[k];
+      }
+      inv[j + M*i] = ans;
+    }
+  }
+  free(U);
+  free(W);
+  free(V);
+  return 0;
+}
+
+static double compute_error(projectPointsType projectPoints,
+                            double *points1, int stride1,
+                            double *points2, int stride2,
+                            int npoints, double *H, int *mask) {
+  int i, n = 0;
+  double pt[2];
+  double *mp1 = points1;
+  double *mp2 = points2;
+  double sqerr = 0.0;
+
+  if (projectPoints == NULL) return -1.0;
+  if (mask) {
+    for (i = 0; i < npoints; ++i, mp1+=stride1, mp2+=stride2) {
+      if (mask[i]) {
+        projectPoints(H, mp1, pt, 1, stride1, stride2);
+        sqerr += (pt[0] - mp2[0]) * (pt[0] - mp2[0]) +
+                 (pt[1] - mp2[1]) * (pt[1] - mp2[1]);
+        n++;
+      }
+    }
+  } else {
+    for (i = 0; i < npoints; ++i, mp1+=stride1, mp2+=stride2) {
+      projectPoints(H, mp1, pt, 1, stride1, stride2);
+      sqerr += (pt[0] - mp2[0]) * (pt[0] - mp2[0]) +
+               (pt[1] - mp2[1]) * (pt[1] - mp2[1]);
+      n++;
+    }
+  }
+  return sqrt(sqerr / n);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ransac
+typedef int  (*isDegenerateType)(double *p);
+typedef void (*normalizeType)(double *p, int np, double *T);
+typedef void (*denormalizeType)(double *H, double *T1, double *T2);
+typedef int  (*findTransformationType)(int points,
+                                       double *points1,
+                                       double *points2,
+                                       double *H);
+
+int ransac_(double *matched_points,
+            int npoints,
+            int *number_of_inliers,
+            int *best_inlier_mask,
+            double *bestH,
+            const int minpts,
+            const int paramdim,
+            isDegenerateType isDegenerate,
+            normalizeType normalize,
+            denormalizeType denormalize,
+            findTransformationType findTransformation,
+            projectPointsType projectPoints) {
+
+  static const double INLIER_THRESHOLD_NORMALIZED = 0.1;
+  static const double INLIER_THRESHOLD_UNNORMALIZED = 1.5;
+  static const double PROBABILITY_REQUIRED = 0.9;
+  static const double EPS = 1e-12;
+  static const int MIN_TRIALS = 20;
+
+  const double inlier_threshold = (normalize && denormalize ?
+                                   INLIER_THRESHOLD_NORMALIZED :
+                                   INLIER_THRESHOLD_UNNORMALIZED);
+  int N = 10000, trial_count = 0;
+  int i, j;
+
+  int max_inliers = 0;
+  double best_variance = 0.0;
+  double H[MAX_PARAMDIM];
+  double points1[2 * MAX_MINPTS];
+  double points2[2 * MAX_MINPTS];
+
+  double *best_inlier_set1;
+  double *best_inlier_set2;
+  double *inlier_set1;
+  double *inlier_set2;
+  double *corners1;
+  double *corners2;
+  double *image1_coord;
+  double *image2_coord;
+  int *inlier_mask;
+
+  double *cnp1, *cnp2;
+  double T1[9], T2[9];
+
+  srand((unsigned)time(NULL)) ;
+  // srand( 12345 ) ;
+  //
+  *number_of_inliers = 0;
+  if (npoints < minpts) {
+    printf("Cannot find motion with %d matches\n", npoints);
+    return 1;
+  }
+
+  best_inlier_set1 = (double *)malloc(sizeof(double) * npoints * 2);
+  best_inlier_set2 = (double *)malloc(sizeof(double) * npoints * 2);
+  inlier_set1 = (double *)malloc(sizeof(double) * npoints * 2);
+  inlier_set2 = (double *)malloc(sizeof(double) * npoints * 2);
+  corners1 = (double *)malloc(sizeof(double) * npoints * 2);
+  corners2 = (double *)malloc(sizeof(double) * npoints * 2);
+  image1_coord = (double *)malloc(sizeof(double) * npoints * 2);
+  image2_coord = (double *)malloc(sizeof(double) * npoints * 2);
+  inlier_mask = (int*)malloc(sizeof(int) * npoints);
+
+  for(cnp1 = corners1, cnp2 = corners2, i = 0; i < npoints; ++i) {
+    *(cnp1++) = *(matched_points++);
+    *(cnp1++) = *(matched_points++);
+    *(cnp2++) = *(matched_points++);
+    *(cnp2++) = *(matched_points++);
+  }
+  matched_points -= 4 * npoints;
+
+  if (normalize && denormalize) {
+    normalize(corners1, npoints, T1);
+    normalize(corners2, npoints, T2);
+  }
+
+  while (N > trial_count) {
+    int num_inliers = 0;
+    double sum_distance = 0.0;
+    double sum_distance_squared = 0.0;
+
+    int degenerate = 1;
+    while (degenerate) {
+      i = 0;
+      while (i < minpts) {
+        int index = rand() % npoints;
+        int duplicate = 0;
+        for (j = 0; j < i; ++j) {
+          if (points1[j*2] == corners1[index*2] &&
+              points1[j*2+1] == corners1[index*2+1]) {
+            duplicate = 1;
+            break;
+          }
+        }
+        if(duplicate) continue;
+        // add to list
+        points1[i*2] = corners1[index*2];
+        points1[i*2+1] = corners1[index*2+1];
+        points2[i*2] = corners2[index*2];
+        points2[i*2+1] = corners2[index*2+1];
+        i++;
+      }
+      degenerate = isDegenerate(points1);
+    }
+
+    if (findTransformation(minpts, points1, points2, H)) {
+      trial_count++;
+      continue;
+    }
+
+    projectPoints(H, corners1, image1_coord, npoints, 2, 2);
+
+    for( i = 0; i < npoints; ++i ) {
+      double dx = image1_coord[i*2] - corners2[i*2];
+      double dy = image1_coord[i*2 + 1] - corners2[i*2 + 1];
+      double distance = sqrt(dx*dx + dy*dy);
+
+      inlier_mask[i] = distance < inlier_threshold;
+      if (inlier_mask[i]) {
+        inlier_set1[num_inliers*2] =            corners1[i*2];
+        inlier_set1[num_inliers*2 + 1] =        corners1[i*2 + 1];
+        inlier_set2[num_inliers*2] =            corners2[i*2];
+        inlier_set2[num_inliers*2 + 1] =        corners2[i*2 + 1];
+        num_inliers++;
+        sum_distance += distance;
+        sum_distance_squared += distance*distance;
+      }
+    }
+
+    if (num_inliers >= max_inliers) {
+      double mean_distance = sum_distance / ((double)num_inliers);
+      double variance = sum_distance_squared / ((double)num_inliers - 1.0) -
+          mean_distance * mean_distance *
+          ((double)num_inliers) / ((double)num_inliers - 1.0);
+      if ((num_inliers > max_inliers) ||
+          (num_inliers==max_inliers && variance < best_variance)) {
+        best_variance = variance;
+        max_inliers = num_inliers;
+        memcpy(bestH, H, paramdim * sizeof(double));
+        memcpy(best_inlier_set1, inlier_set1, num_inliers*2 * sizeof(double));
+        memcpy(best_inlier_set2, inlier_set2, num_inliers*2 * sizeof(double));
+        memcpy(best_inlier_mask, inlier_mask, npoints * sizeof(int));
+
+        if (num_inliers > 0) {
+          double fracinliers =  (double)num_inliers/(double)npoints;
+          double pNoOutliers = 1 - pow(fracinliers, minpts);
+          int temp;
+          pNoOutliers = fmax(EPS, pNoOutliers);
+          pNoOutliers = fmin(1 - EPS, pNoOutliers);
+          temp = (int)(log(1.0 - PROBABILITY_REQUIRED)/log(pNoOutliers));
+          if (temp > 0 && temp < N) {
+            N = IMAX(temp, MIN_TRIALS);
+          }
+        }
+      }
+    }
+    trial_count++;
+  }
+  // printf("Number of trials = %d\n", trial_count);
+  findTransformation(max_inliers, best_inlier_set1, best_inlier_set2, bestH);
+  if (normalize && denormalize) {
+    denormalize(bestH, T1, T2);
+  }
+  *number_of_inliers = max_inliers;
+  /*
+  printf("Error score (all) = %g\n",
+         compute_error(projectPoints, matched_points, 4,
+                       matched_points + 2, 4,
+                       npoints, bestH, NULL));
+  printf("Error score (inliers) = %g\n",
+         compute_error(projectPoints, matched_points, 4,
+                       matched_points + 2, 4,
+                       npoints, bestH,
+                       best_inlier_mask));
+  */
+  free(best_inlier_set1);
+  free(best_inlier_set2);
+  free(inlier_set1);
+  free(inlier_set2);
+  free(corners1);
+  free(corners2);
+  free(image1_coord);
+  free(image2_coord);
+  free(inlier_mask);
+  return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static void normalizeHomography(double *pts, int n, double *T) {
+  // Assume the points are 2d coordinates with scale = 1
+  double *p = pts;
+  double mean[2] = {0, 0};
+  double msqe = 0;
+  double scale;
+  int i;
+  for (i = 0; i < n; ++i, p+=2) {
+    mean[0] += p[0];
+    mean[1] += p[1];
+  }
+  mean[0] /= n;
+  mean[1] /= n;
+  for (p = pts, i = 0; i < n; ++i, p+=2) {
+    p[0] -= mean[0];
+    p[1] -= mean[1];
+    msqe += sqrt(p[0] * p[0] + p[1] * p[1]);
+  }
+  msqe /= n;
+  scale = sqrt(2)/msqe;
+  T[0] = scale;
+  T[1] = 0;
+  T[2] = -scale * mean[0];
+  T[3] = 0;
+  T[4] = scale;
+  T[5] = -scale * mean[1];
+  T[6] = 0;
+  T[7] = 0;
+  T[8] = 1;
+  for (p = pts, i = 0; i < n; ++i, p+=2) {
+    p[0] *= scale;
+    p[1] *= scale;
+  }
+}
+
+static void invnormalize_mat(double *T, double *iT) {
+  double is = 1.0/T[0];
+  double m0 = -T[2]*is;
+  double m1 = -T[5]*is;
+  iT[0] = is;
+  iT[1] = 0;
+  iT[2] = m0;
+  iT[3] = 0;
+  iT[4] = is;
+  iT[5] = m1;
+  iT[6] = 0;
+  iT[7] = 0;
+  iT[8] = 1;
+}
+
+static void denormalizeHomography(double *H, double *T1, double *T2) {
+  double iT2[9];
+  double H2[9];
+  invnormalize_mat(T2, iT2);
+  MultiplyMat(H, T1, H2, 3, 3, 3);
+  MultiplyMat(iT2, H2, H, 3, 3, 3);
+}
+
+static void denormalizeAffine(double *H, double *T1, double *T2) {
+  double Ha[MAX_PARAMDIM];
+  Ha[0] = H[0];
+  Ha[1] = H[1];
+  Ha[2] = H[4];
+  Ha[3] = H[2];
+  Ha[4] = H[3];
+  Ha[5] = H[5];
+  Ha[6] = Ha[7] = 0;
+  Ha[8] = 1;
+  denormalizeHomography(Ha, T1, T2);
+  H[0] = Ha[0];
+  H[1] = Ha[1];
+  H[2] = Ha[3];
+  H[3] = Ha[4];
+  H[4] = Ha[2];
+  H[5] = Ha[5];
+}
+
+static void denormalizeRotZoom(double *H, double *T1, double *T2) {
+  double Ha[MAX_PARAMDIM];
+  memcpy(Ha, H, 6 * sizeof(*H));
+  Ha[0] = H[0];
+  Ha[1] = H[1];
+  Ha[2] = H[2];
+  Ha[3] = -H[1];
+  Ha[4] = H[0];
+  Ha[5] = H[3];
+  Ha[6] = Ha[7] = 0;
+  Ha[8] = 1;
+  denormalizeHomography(Ha, T1, T2);
+  H[0] = Ha[0];
+  H[1] = Ha[1];
+  H[2] = Ha[2];
+  H[3] = Ha[5];
+}
+
+static int is_collinear3(double *p1, double *p2, double *p3) {
+  static const double collinear_eps = 1e-3;
+  const double v = (p2[0] - p1[0]) * (p3[1] - p1[1]) - (p2[1] - p1[1]) * (p3[0] - p1[0]);
+  return fabs(v) < collinear_eps;
+}
+
+static int isDegenerateAffine(double *p) {
+  return is_collinear3(p, p + 2, p + 4);
+}
+
+static int isDegenerateHomography(double *p) {
+  return is_collinear3(p, p + 2, p + 4) ||
+         is_collinear3(p, p + 2, p + 6) ||
+         is_collinear3(p, p + 4, p + 6) ||
+         is_collinear3(p + 2, p + 4, p + 6);
+}
+
+void projectPointsRotZoom(double *mat, double *points, double *proj, const int n,
+                          const int stride_points, const int stride_proj) {
+  int i;
+  for (i = 0; i < n; ++i) {
+    const double x = *(points++), y = *(points++);
+    *(proj++) = mat[0]*x + mat[1]*y + mat[2];
+    *(proj++) = -mat[1]*x + mat[0]*y + mat[3];
+    points += stride_points - 2;
+    proj += stride_proj - 2;
+  }
+}
+
+void projectPointsAffine(double *mat, double *points, double *proj, const int n,
+                         const int stride_points, const int stride_proj) {
+  int i;
+  for (i = 0; i < n; ++i) {
+    const double x = *(points++), y = *(points++);
+    *(proj++) = mat[0]*x + mat[1]*y + mat[4];
+    *(proj++) = mat[2]*x + mat[3]*y + mat[5];
+    points += stride_points - 2;
+    proj += stride_proj - 2;
+  }
+}
+
+void projectPointsHomography(double *mat, double *points, double *proj, const int n,
+                             const int stride_points, const int stride_proj) {
+  int i;
+  double x, y, Z;
+  for (i = 0; i < n; ++i) {
+    x = *(points++), y = *(points++);
+    Z = 1./(mat[6]*x + mat[7]*y + mat[8]);
+    *(proj++) =     (mat[0]*x + mat[1]*y + mat[2])*Z;
+    *(proj++) =     (mat[3]*x + mat[4]*y + mat[5])*Z;
+    points += stride_points - 2;
+    proj += stride_proj - 2;
+  }
+}
+
+int findRotZoom(const int np, double *pts1, double *pts2, double *mat) {
+  const int np2 = np * 2;
+  double *a = (double *)malloc(sizeof(double) * np2 * 9);
+  double *b = a + np2 * 4;
+  double *temp = b + np2;
+  int i;
+  double sx, sy, dx, dy;
+
+  double T1[9], T2[9];
+  normalizeHomography(pts1, np, T1);
+  normalizeHomography(pts2, np, T2);
+
+  for (i = 0; i < np; ++i) {
+    dx = *(pts2++);
+    dy = *(pts2++);
+    sx = *(pts1++);
+    sy = *(pts1++);
+
+    a[i * 2 * 4 + 0] = sx;
+    a[i * 2 * 4 + 1] = sy;
+    a[i * 2 * 4 + 2] = 1;
+    a[i * 2 * 4 + 3] = 0;
+    a[(i * 2 + 1) * 4 + 0] = sy;
+    a[(i * 2 + 1) * 4 + 1] = -sx;
+    a[(i * 2 + 1) * 4 + 2] = 0;
+    a[(i * 2 + 1) * 4 + 3] = 1;
+
+    b[2 * i] = dx;
+    b[2 * i + 1] = dy;
+  }
+  if (PseudoInverse(temp, a, np2, 4)){
+    free(a);
+    return 1;
+  }
+  MultiplyMat(temp, b, mat, 4, np2, 1);
+  denormalizeRotZoom(mat, T1, T2);
+  free(a);
+  return 0;
+}
+
+int findAffine(const int np, double *pts1, double *pts2, double *mat) {
+  const int np2 = np * 2;
+  double *a = (double *)malloc(sizeof(double) * np2 * 13);
+  double *b = a + np2 * 6;
+  double *temp = b + np2;
+  int i;
+  double sx, sy, dx, dy;
+
+  double T1[9], T2[9];
+  normalizeHomography(pts1, np, T1);
+  normalizeHomography(pts2, np, T2);
+
+  for (i = 0; i < np; ++i) {
+    dx = *(pts2++);
+    dy = *(pts2++);
+    sx = *(pts1++);
+    sy = *(pts1++);
+
+    a[i * 2 * 6 + 0] = sx;
+    a[i * 2 * 6 + 1] = sy;
+    a[i * 2 * 6 + 2] = 0;
+    a[i * 2 * 6 + 3] = 0;
+    a[i * 2 * 6 + 4] = 1;
+    a[i * 2 * 6 + 5] = 0;
+    a[(i * 2 + 1) * 6 + 0] = 0;
+    a[(i * 2 + 1) * 6 + 1] = 0;
+    a[(i * 2 + 1) * 6 + 2] = sx;
+    a[(i * 2 + 1) * 6 + 3] = sy;
+    a[(i * 2 + 1) * 6 + 4] = 0;
+    a[(i * 2 + 1) * 6 + 5] = 1;
+
+    b[2 * i] = dx;
+    b[2 * i + 1] = dy;
+  }
+  if (PseudoInverse(temp, a, np2, 6)){
+    free(a);
+    return 1;
+  }
+  MultiplyMat(temp, b, mat, 6, np2, 1);
+  denormalizeAffine(mat, T1, T2);
+  free(a);
+  return 0;
+}
+
+int findHomography(const int np, double *pts1, double *pts2, double *mat) {
+  // Implemented from Peter Kovesi's normalized implementation
+  const int np3 = np * 3;
+  double *a = (double *)malloc(sizeof(double) * np3 * 18);
+  double *U = a + np3 * 9;
+  double S[9], V[9 * 9];
+  int i, mini;
+  double sx, sy, dx, dy;
+  double T1[9], T2[9];
+
+  normalizeHomography(pts1, np, T1);
+  normalizeHomography(pts2, np, T2);
+
+  for (i = 0; i < np; ++i) {
+    dx = *(pts2++);
+    dy = *(pts2++);
+    sx = *(pts1++);
+    sy = *(pts1++);
+
+    a[i * 3 * 9 + 0] = a[i * 3 * 9 + 1] = a[i * 3 * 9 + 2] = 0;
+    a[i * 3 * 9 + 3] = -sx;
+    a[i * 3 * 9 + 4] = -sy;
+    a[i * 3 * 9 + 5] = -1;
+    a[i * 3 * 9 + 6] = dy * sx;
+    a[i * 3 * 9 + 7] = dy * sy;
+    a[i * 3 * 9 + 8] = dy;
+
+    a[(i * 3 + 1) * 9 + 0] = sx;
+    a[(i * 3 + 1) * 9 + 1] = sy;
+    a[(i * 3 + 1) * 9 + 2] = 1;
+    a[(i * 3 + 1) * 9 + 3] = a[(i * 3 + 1) * 9 + 4] =
+        a[(i * 3 + 1) * 9 + 5] = 0;
+    a[(i * 3 + 1) * 9 + 6] = -dx * sx;
+    a[(i * 3 + 1) * 9 + 7] = -dx * sy;
+    a[(i * 3 + 1) * 9 + 8] = -dx;
+
+    a[(i * 3 + 2) * 9 + 0] = -dy * sx;
+    a[(i * 3 + 2) * 9 + 1] = -dy * sy;
+    a[(i * 3 + 2) * 9 + 2] = -dy;
+    a[(i * 3 + 2) * 9 + 3] = dx * sx;
+    a[(i * 3 + 2) * 9 + 4] = dx * sy;
+    a[(i * 3 + 2) * 9 + 5] = dx;
+    a[(i * 3 + 2) * 9 + 6] = a[(i * 3 + 2) * 9 + 7] =
+        a[(i * 3 + 2) * 9 + 8] = 0;
+  }
+
+  if (SVD(U, S, V, a, np3, 9)) {
+    free(a);
+    return 1;
+  } else {
+    double minS = 1e12;
+    mini = -1;
+    for (i = 0; i < 9; ++i) {
+      if (S[i] < minS) {
+        minS = S[i];
+        mini = i;
+      }
+    }
+  }
+
+  for (i = 0; i < 9; i++) mat[i] = V[i * 9 + mini];
+  denormalizeHomography(mat, T1, T2);
+  // if (mat[8] == 0.0) return 1;
+  // for (i = 0; i < 9; i++) mat[i] /= mat[8];
+  free(a);
+  return 0;
+}
+
+int findHomographyScale1(const int np, double *pts1, double *pts2,
+                         double *mat) {
+  // This implementation assumes h33 = 1, but does not seem to give good results
+  const int np2 = np * 2;
+  double *a = (double *)malloc(sizeof(double) * np2 * 17);
+  double *b = a + np2 * 8;
+  double *temp = b + np2;
+  int i, j;
+  double sx, sy, dx, dy;
+  double T1[9], T2[9];
+
+  normalizeHomography(pts1, np, T1);
+  normalizeHomography(pts2, np, T2);
+
+  for (i = 0, j = np; i < np; ++i, ++j) {
+    dx = *(pts2++);
+    dy = *(pts2++);
+    sx = *(pts1++);
+    sy = *(pts1++);
+    a[i * 8 + 0] = a[j * 8 + 3] = sx;
+    a[i * 8 + 1] = a[j * 8 + 4] = sy;
+    a[i * 8 + 2] = a[j * 8 + 5] = 1;
+    a[i * 8 + 3] = a[i * 8 + 4] = a[i * 8 + 5] =
+        a[j * 8 + 0] = a[j * 8 + 1] = a[j * 8 + 2] = 0;
+    a[i * 8 + 6] = -dx * sx;
+    a[i * 8 + 7] = -dx * sy;
+    a[j * 8 + 6] = -dy * sx;
+    a[j * 8 + 7] = -dy * sy;
+    b[i] = dx;
+    b[j] = dy;
+  }
+
+  if (PseudoInverse(temp, a, np2, 8)) {
+    free(a);
+    return 1;
+  }
+  MultiplyMat(temp, b, &*mat, 8, np2, 1);
+  mat[8] = 1;
+
+  denormalizeHomography(mat, T1, T2);
+  free(a);
+  return 0;
+}
+
+int ransacRotZoom(double *matched_points, int npoints,
+                  int *number_of_inliers,
+                  int *best_inlier_mask, double *bestH) {
+  return ransac_(matched_points,
+                 npoints,
+                 number_of_inliers,
+                 best_inlier_mask,
+                 bestH,
+                 3,
+                 4,
+                 isDegenerateAffine,
+                 NULL,  // normalizeHomography,
+                 NULL,  // denormalizeRotZoom,
+                 findRotZoom,
+                 projectPointsRotZoom);
+}
+
+int ransacAffine(double *matched_points, int npoints,
+                 int *number_of_inliers,
+                 int *best_inlier_mask, double *bestH) {
+  return ransac_(matched_points,
+                 npoints,
+                 number_of_inliers,
+                 best_inlier_mask,
+                 bestH,
+                 3,
+                 6,
+                 isDegenerateAffine,
+                 NULL, // normalizeHomography,
+                 NULL, // denormalizeAffine,
+                 findAffine,
+                 projectPointsAffine);
+}
+
+int ransacHomography(double *matched_points, int npoints,
+                     int *number_of_inliers,
+                     int *best_inlier_mask, double *bestH) {
+  return ransac_(matched_points,
+                 npoints,
+                 number_of_inliers,
+                 best_inlier_mask,
+                 bestH,
+                 4,
+                 8,
+                 isDegenerateHomography,
+                 NULL, // normalizeHomography,
+                 NULL, // denormalizeHomography,
+                 findHomography,
+                 projectPointsHomography);
+}
diff --git a/vp9/encoder/vp9_ransac.h b/vp9/encoder/vp9_ransac.h
new file mode 100644 (file)
index 0000000..d4f4998
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be
+ *  found  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef VP9_ENCODER_VP9_RANSAC_H
+#define VP9_ENCODER_VP9_RANSAC_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <memory.h>
+
+typedef int (*ransacType)(double *matched_points, int npoints,
+                          int *number_of_inliers, int *best_inlier_mask,
+                          double *bestH);
+typedef void (*projectPointsType)(double *mat, double *points, double *proj,
+                                  const int n, const int stride_points,
+                                  const int stride_proj);
+
+int ransacHomography(double *matched_points, int npoints,
+                     int *number_of_inliers, int *best_inlier_indices,
+                     double *bestH);
+int ransacAffine(double *matched_points, int npoints,
+                 int *number_of_inliers, int *best_inlier_indices,
+                 double *bestH);
+int ransacRotZoom(double *matched_points, int npoints,
+                  int *number_of_inliers, int *best_inlier_indices,
+                  double *bestH);
+
+void projectPointsHomography(double *mat, double *points, double *proj,
+                             const int n, const int stride_points, const int stride_proj);
+void projectPointsAffine(double *mat, double *points, double *proj,
+                         const int n, const int stride_points, const int stride_proj);
+void projectPointsRotZoom(double *mat, double *points, double *proj,
+                          const int n, const int stride_points, const int stride_proj);
+
+#endif  // VP9_ENCODER_VP9_RANSAC_H
index 0fdd89d610bd0ea7db6dea908ebc9fb36b86bf53..09743a623901bd8dd3aff39da00c9cf5c8a8f651 100644 (file)
@@ -74,6 +74,14 @@ VP9_CX_SRCS-yes += encoder/vp9_subexp.h
 VP9_CX_SRCS-yes += encoder/vp9_svc_layercontext.c
 VP9_CX_SRCS-yes += encoder/vp9_resize.c
 VP9_CX_SRCS-yes += encoder/vp9_resize.h
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_ransac.c
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_ransac.h
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_detect.c
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_detect.h
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_match.c
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_corner_match.h
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_global_motion.c
+VP9_CX_SRCS-$(CONFIG_EXPERIMENTAL) += encoder/vp9_global_motion.h
 VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/vp9_ssim.c
 VP9_CX_SRCS-$(CONFIG_INTERNAL_STATS) += encoder/vp9_ssim.h
 VP9_CX_SRCS-yes += encoder/vp9_tokenize.c