swh:1:snp:9dcf3ab72851691ef27e40da9b2a50243c1bdd22
Raw File
Tip revision: 5f23fb0b6e1d50d996ac54daaa7e637e5d8decaf authored by Software Heritage on 05 May 2020, 00:00:00 UTC
ipol: Deposit 1363 in collection ipol
Tip revision: 5f23fb0
lib_discrete.c
/*
IPOL SIFT
Copyright (C) 2014, Ives Rey-Otero, CMLA ENS Cachan
<ives.rey-otero@cmla.ens-cachan.fr>

Version 20140911 (September 11th, 2014)

This C ANSI source code is related to the IPOL publication

    [1] "Anatomy of the SIFT Method."
        I. Rey Otero  and  M. Delbracio
        Image Processing Online, 2013.
        http://www.ipol.im/pub/algo/rd_anatomy_sift/

An IPOL demo is available at
        http://www.ipol.im/pub/demo/rd_anatomy_sift/





== Patent Warning and License =================================================

The SIFT method is patented

    [3] "Method and apparatus for identifying scale invariant features
      in an image."
        David G. Lowe
        Patent number: 6711293
        Filing date: Mar 6, 2000
        Issue date: Mar 23, 2004
        Application number: 09/519,89

 These source codes are made available for the exclusive aim of serving as
 scientific tool to verify the soundness and completeness of the algorithm
 description. Compilation, execution and redistribution of this file may
 violate patents rights in certain countries. The situation being different
 for every country and changing over time, it is your responsibility to
 determine which patent rights restrictions apply to you before you compile,
 use, modify, or redistribute this file. A patent lawyer is qualified to make
 this determination. If and only if they don't conflict with any patent terms,
 you can benefit from the following license terms attached to this file.


This program is free software: you can use, modify and/or
redistribute it under the terms of the simplified BSD
License. You should have received a copy of this license along
this program. If not, see
<http://www.opensource.org/licenses/bsd-license.html>.

*/
/**
 * @file lib_discrete.c
 * @brief simple image transformations
 *
 * This is a front-end to libpng, with routines to:
 *      @li Separable discrete convolutions
 *      @li Gaussian blur via discrete convolution with truncated kernel
 *      @li 2D Gradient
 *      @li Subsampling by integer factor
 *      @li bilinear interpolation
 *
 * @author Ives Rey-Otero <ives.rey-otero@cmla.ens-cachan.fr>
 */




#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "lib_discrete.h"
#include "lib_util.h"







/** @brief Compute image gradient via symmetric finite difference schemes
 *
 *   image extension :  symmetrization at x=-1/2
 *
 */
void sift_compute_gradient(const float* im, float* im_x, float* im_y, int w, int h)
{

    const float* p_in;
    const float* p_in_p;
    const float* p_in_m;
    float* p_out;

    /** Computing im_y      */
    /* pixels in the center */
    p_in   = &im[1];
    p_out  = &im_y[1];
    p_in_p = p_in+1;
    p_in_m = p_in-1;
    for(int i=1; i<h*w-1; i++)  /* produces false value on borders but it's ok */
    {
        *p_out = (*p_in_p-*p_in_m)*0.5;
        p_out++;
        p_in_m++;
        p_in_p++;
    }
    /*    pixels on borders - symmetrization at y=-1/2  */
    for(int i=0; i<h; i++)
    {
        im_y[i*w]           = im[i*w+1]- im[i*w];
        im_y[i*w+(w-1)] = im[i*w+(w-1)] - im[i*w+(w-2)];
    }


    /** Computing im_x      */
    /* pixels in the center */
    p_in   = &im[w];
    p_out  = &im_x[w];
    p_in_p = p_in+w;
    p_in_m = p_in-w;
    for(int i=w; i<h*w-w; i++)  /* produces false value on borders */
    {
        *p_out = (*p_in_p-*p_in_m)*0.5;
        p_out++;
        p_in_m++;
        p_in_p++;
    }
    /*    pixels on borders - symmetrization at x=-1/2  */
    for(int i=0; i<w; i++)
    {
        im_x[i]                   = im[i+w]-im[i];
        im_x[(h-1)*w+i]  = im[(h-1)*w+i] - im[(h-1-1)*w+i];
    }
}




/**
 * @brief Builds mono-dimensional sampled Gaussian kernel.
 *
 *        Only considers the right side of the kernel
 *        (including the center
 *
 *        Returns a (rad+1) long vector
 *
 *
 */
static float* malloc_gaussian_symm_kernel(float sigma, int rad)
{
    assert(sigma>=0);
    float* gker = xmalloc((rad+1)*sizeof(float));
    gker[0] = 1.;
    if(sigma>0)
    {
        float sum = gker[0];
        for(int i = 1; i <= rad; i++)
        {
            gker[i] = exp(-0.5*(float)i*(float)i/sigma/sigma);
            sum += 2*gker[i];
        }
        for(int i = 0; i <= rad; i++)
            gker[i] /= sum;
    }
    else
    {
        for(int i = 1; i <= rad; i++)
        {
            gker[i] = 0.0;
        }
    }
    return gker;
}


static void convolve_symm(const float* in, float* out, int w, int h,
                          const float* xker, int r_xker,
                          const float* yker, int r_yker);


void sift_add_gaussian_blur(const float* in, float* out, int w, int h, float sigma)
{
    int r_gker = (int)ceil(4*sigma);  // ceil(4*sigma)
    float* gker = malloc_gaussian_symm_kernel(sigma, r_gker);
    convolve_symm(in,out,w,h,gker,r_gker,gker,r_gker);
    xfree(gker);
}

/** @brief sub sampling by factor 2, keeping sample (0,0) */
void sift_subsample_by2(const float* in, float* out, int wi, int hi)
{
    int wo = wi/2;
    int ho = hi/2;
    int i, j, i_p, j_p;
    for(i=0; i<ho; i++)
    {
        i_p = 2*i;
        for(j=0; j<wo; j++)
        {
            j_p=2*j;
            out[i*wo+j] = in[i_p*wi+j_p];
        }
    }
}




/** @brief Interpolate the image with a bilinear model
 *
 *  the inter-pixel distance in the output image is delta_out
 *
 *  in  : input digital image with (wi X hi) samples.
 *  out : output digital image with (wo X ho) samples,
 *        with wo  = \lfloor wi  / delta_out \rfloor
 *         and ho = \lfloor hi / delta_out \rfloor
 *
 *
 */
void sift_oversample_bilin(const float* in, int wi,  int hi,
                           float* out, int wo, int ho,
                           float delta_out)
{
    assert(delta_out<=1);

    for(int i = 0; i < ho; i++)
    {
        for(int j = 0; j < wo; j++)
        {

            float x = i*delta_out;
            float y= j*delta_out;
            int im = (int)x;
            int jm = (int)y;
            int ip = im +1;
            int jp = jm +1;

            //image extension by symmetrization
            if(ip >= hi)
            {
                ip = 2*hi-1-ip;
            }
            if(im >= hi)
            {
                im = 2*hi-1-im;
            }
            if(jp >= wi)
            {
                jp = 2*wi-1-jp;
            }
            if(jm >= wi)
            {
                jm = 2*wi-1-jm;
            }

            const float fractional_x = x - floor(x);
            const float fractional_y = y - floor(y);
            out[i*wo+j] = fractional_x  * ( fractional_y  * in[ip*wi+jp]
                                            + (1 - fractional_y) * in[ip*wi+jm] )
                          + (1-fractional_x) * ( fractional_y  * in[im*wi+jp]
                                                 + (1 - fractional_y) * in[im*wi+jm] );
        }
    }
}



// Returns the corresponding coordinate 0<=i<l under symmetrized signal
// extension
static inline int symmetrized_coordinates(int i, int l)
{
    int ll = 2*l;
    i = (i+ll)%(ll);
    if(i>l-1)
    {
        i = ll-1-i;
    }
    return i;
}



/** @brief Apply a convolution with a separable kernel
 * and signal extension by symmetrization
 *
 * @param in             Input image of w X h samples
 * @param out            Output image (same dimension)
 *
 * @param xker           Kernel applied along direction x
 *                          radius = r_xker
 *                          w = 2*r_xker+1
 *
 * @param yker           Kernel applied along direction y
 *                          radius = r_yker
 *                          w = 2*r_yker+1
 *
 *  Compute:
 *
 *   out[i,j] = \sum_{-r_xker \leq k \leq +r_xker}
 *                    xker[k]
 *                    . \sum_{-r_xker \leq l \leq +r_xker}
 *                              yker[l].in[i-k,j-l]
 *
 *  Border condition:  symmetrization at border
 *                     (at x = -1./2 and x = w-1./2)
 *
 */
static void convolve_symm(const float* in, float* out, int w, int h,
                          const float* xker, int r_xker,
                          const float* yker, int r_yker)
{
    float* im_tmp = xmalloc(w*h*sizeof(float));
    /* convolution along x coordinates */
    for(int i=0; i<h; i++)
    {
        for(int j=0; j<w; j++)
        {
            float sum = in[i*w+j] * xker[0] ;
            for(int k = 1; k <= r_xker; k++)
            {
                int i_p_left = symmetrized_coordinates(i-k, h);
                int i_p_right = symmetrized_coordinates(i+k, h);
                sum += xker[k]*(in[i_p_left*w+j] + in[i_p_right*w+j]);
            }
            im_tmp[i*w+j] = sum;
        }
    }
    /* convolution along y coordinates */
    for(int i=0; i<h; i++)
    {
        for(int j=0; j<w; j++)
        {
            float sum = im_tmp[i*w+j] * xker[0];
            for(int k = 1; k <= r_yker; k++)
            {
                int j_p_left = symmetrized_coordinates(j-k, w);
                int j_p_right = symmetrized_coordinates(j+k, w);
                sum += yker[k]*(im_tmp[i*w+j_p_left] + im_tmp[i*w+j_p_right]);
            }
            out[i*w+j] = sum;
        }
    }
    xfree(im_tmp);
}
back to top