// Catalano Imaging Library
// The Catalano Framework
//
// Copyright © Diego Catalano, 2012-2016
// diego.catalano at live.com
//
// Copyright © César Souza, 2009-2013
// cesarsouza at gmail.com
//
// Copyright (c) 2011-2012 LTS2, EPFL
// 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 CherryPy Team 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 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package Catalano.Imaging.Corners.FREAK;
import Catalano.Imaging.FastBitmap;
import Catalano.Imaging.Tools.IntegralImage;
import Catalano.Math.Constants;
import java.util.ArrayList;
import java.util.List;
/**
* Fast Retina Keypoint (FREAK) descriptor.
* @author Diego Catalano
*/
public class FastRetinaKeypointDescriptor {
private FastRetinaKeypointPattern pattern;
private boolean isOrientationNormal;
private boolean isScaleNormal;
private boolean isExtended;
private FastBitmap Image;
public IntegralImage Integral;
FastRetinaKeypoint temp;
public boolean IsOrientationNormal() {
return isOrientationNormal;
}
public void setOrientationNormal(boolean isOrientationNormal) {
this.isOrientationNormal = isOrientationNormal;
}
public boolean IsScaleNormal() {
return isScaleNormal;
}
public void setScaleNormal(boolean isScaleNormal) {
this.isScaleNormal = isScaleNormal;
}
public boolean IsExtended() {
return isExtended;
}
public void setExtended(boolean isExtended) {
this.isExtended = isExtended;
}
FastRetinaKeypointDescriptor(FastBitmap fastBitmap, IntegralImage integral, FastRetinaKeypointPattern pattern){
this.isExtended = false;
this.isOrientationNormal = true;
this.isScaleNormal = true;
this.Image = fastBitmap;
this.Integral = integral;
this.pattern = pattern;
}
public void Compute(List points)
{
final int CV_FREAK_SMALLEST_KP_SIZE = FastRetinaKeypointPattern.Size;
final int CV_FREAK_NB_SCALES = FastRetinaKeypointPattern.Scales;
final int CV_FREAK_NB_ORIENTATION = FastRetinaKeypointPattern.Orientations;
int[] patternSizes = pattern.patternSizes;
int[] pointsValues = pattern.pointsValues;
FastRetinaKeypointPattern.OrientationPair[] orientationPairs = pattern.orientationPairs;
FastRetinaKeypointPattern.DescriptionPair[] descriptionPairs = pattern.descriptionPairs;
double step = pattern.step;
// used to save pattern scale index corresponding to each keypoints
ArrayList scaleIndex = new ArrayList(points.size());
for (int i = 0; i < points.size(); i++)
scaleIndex.add(0);
// 1. Compute the scale index corresponding to the keypoint
// size and remove keypoints which are close to the border
//
if (isScaleNormal)
{
for (int k = points.size() - 1; k >= 0; k--)
{
// Is k non-zero? If so, decrement it and continue.
double ratio = points.get(k).scale / CV_FREAK_SMALLEST_KP_SIZE;
scaleIndex.set(k, Math.max((int)(Math.log(ratio) * step + 0.5), 0));
if (scaleIndex.get(k) >= CV_FREAK_NB_SCALES)
scaleIndex.set(k, CV_FREAK_NB_SCALES - 1);
// Check if the description at this position and scale fits inside the image
if ((points.get(k).x <= patternSizes[scaleIndex.get(k)]) ||
points.get(k).y <= patternSizes[scaleIndex.get(k)] ||
points.get(k).x >= Image.getHeight()- patternSizes[scaleIndex.get(k)] ||
points.get(k).y >= Image.getWidth()- patternSizes[scaleIndex.get(k)])
{
points.remove(k); // No, it doesn't. Remove the point.
scaleIndex.remove(k);
}
}
}
else // if (!IsScaleNormal)
{
int scale = Math.max((int)(Constants.Log3 * step + 0.5), 0);
for (int k = points.size() - 1; k >= 0; k--)
{
// equivalent to the formule when the scale is normalized with
// a constant size of keypoints[k].size = 3 * SMALLEST_KP_SIZE
scaleIndex.set(k, scale);
if (scaleIndex.get(k) >= CV_FREAK_NB_SCALES)
scaleIndex.set(k, CV_FREAK_NB_SCALES - 1);
if ((points.get(k).x <= patternSizes[scaleIndex.get(k)]) ||
points.get(k).y <= patternSizes[scaleIndex.get(k)] ||
points.get(k).x >= Image.getHeight()- patternSizes[scaleIndex.get(k)] ||
points.get(k).y >= Image.getWidth()- patternSizes[scaleIndex.get(k)])
{
points.remove(k);
scaleIndex.remove(k);
}
}
}
// 2. Allocate descriptor memory, estimate
// orientations, and extract descriptors
//
// For each interest (key/corners) point
for (int k = 0; k < points.size(); k++)
{
int thetaIndex = 0;
// Estimate orientation
if (!isOrientationNormal)
{
// Orientation is not normalized, assign 0.
temp = points.get(k);
temp.setOrientation(0);
thetaIndex = 0;
points.set(k, temp);
}
else // if (IsOrientationNormal)
{
// Get intensity values in the unrotated patch
for (int i = 0; i < pointsValues.length; i++)
pointsValues[i] = mean(points.get(k).x, points.get(k).y, scaleIndex.get(k), 0, i);
int a = 0, b = 0;
for (int m = 0; m < orientationPairs.length; m++)
{
FastRetinaKeypointPattern.OrientationPair p = orientationPairs[m];
int delta = (pointsValues[p.i] - pointsValues[p.j]);
a += delta * (p.weight_dx) / 2048;
b += delta * (p.weight_dy) / 2048;
}
temp = points.get(k);
temp.setOrientation(Math.atan2(b, a) * (180.0 / Math.PI));
points.set(k, temp);
thetaIndex = (int)(CV_FREAK_NB_ORIENTATION * points.get(k).getOrientation() * (1 / 360.0) + 0.5);
if (thetaIndex < 0) // bound in interval
thetaIndex += CV_FREAK_NB_ORIENTATION;
if (thetaIndex >= CV_FREAK_NB_ORIENTATION)
thetaIndex -= CV_FREAK_NB_ORIENTATION;
}
// Extract descriptor at the computed orientation
for (int i = 0; i < pointsValues.length; i++)
pointsValues[i] = mean(points.get(k).x, points.get(k).y, scaleIndex.get(k), thetaIndex, i);
// Extract either the standard descriptors of 512-bits (64 bytes)
// or the extended descriptors of 1024-bits (128 bytes) length.
//
if (!isExtended)
{
temp = points.get(k);
temp.setDescriptor(new byte[64]);
for (int m = 0; m < descriptionPairs.length; m++)
{
FastRetinaKeypointPattern.DescriptionPair p = descriptionPairs[m];
byte[] descriptor = temp.getDescriptor();
if (pointsValues[p.i] > pointsValues[p.j])
descriptor[m / 8] |= (byte)(1 << m % 8);
else descriptor[m / 8] &= (byte)~(1 << m % 8);
}
}
else // if (Extended)
{
temp = points.get(k);
temp.setDescriptor(new byte[128]);
for (int i = 1, m = 0; i < pointsValues.length; i++)
{
for (int j = 0; j < i; j++, m++)
{
byte[] descriptor = temp.getDescriptor();
if (pointsValues[i] > pointsValues[j])
descriptor[m / 8] |= (byte)(1 << m % 8);
else descriptor[m / 8] &= (byte)~(1 << m % 8);
}
}
}
}
}
private int mean(double kx, double ky, int scale, int orientation, int pointIndex)
{
final int CV_FREAK_NB_ORIENTATION = FastRetinaKeypointPattern.Orientations;
final int CV_FREAK_NB_POINTS = FastRetinaKeypointPattern.Points;
// get point position in image
FastRetinaKeypointPattern.PatternPoint freak = pattern.lookupTable[
scale * CV_FREAK_NB_ORIENTATION * CV_FREAK_NB_POINTS
+ orientation * CV_FREAK_NB_POINTS + pointIndex];
double xf = freak.x + ky;
double yf = freak.y + kx;
int x = (int)(xf);
int y = (int)(yf);
int ret_val;
// get the sigma:
float radius = freak.sigma;
// calculate output:
if (radius < 0.5)
{
// interpolation multipliers:
int r_x = (int)((xf - x) * 1024);
int r_y = (int)((yf - y) * 1024);
int r_x_1 = (1024 - r_x);
int r_y_1 = (1024 - r_y);
//byte* ptr = (byte*)Image.ImageData.ToPointer() + x + y * imagecols;
// linear interpolation:
ret_val = (r_x_1 * r_y_1 * Image.getGray(y, x));
//ptr++;
ret_val += (r_x * r_y_1 * Image.getGray(y, x + 1));
//ptr += imagecols;
ret_val += (r_x * r_y * Image.getGray(y + 1, x + 1));
//ptr--;
ret_val += (r_x_1 * r_y * Image.getGray(y + 1, x));
return ((ret_val + 512) / 1024);
}
// calculate borders
int x_left = (int)(xf - radius + 0.5);
int y_top = (int)(yf - radius + 0.5);
int x_right = (int)(xf + radius + 1.5); //integral image is 1px wider
int y_bottom = (int)(yf + radius + 1.5); //integral image is 1px higher
ret_val = (int)Integral.getInternalData(y_bottom, x_right); //bottom right corner
ret_val -= (int)Integral.getInternalData(y_bottom, x_left);
ret_val += (int)Integral.getInternalData(y_top, x_left);
ret_val -= (int)Integral.getInternalData(y_top, x_right);
ret_val = ret_val / ((x_right - x_left) * (y_bottom - y_top));
return ret_val;
}
}
Ads help maintain this website.