private void build(int octaves, float scale)
{
lookupTable = new PatternPoint[Scales * Orientations * Points];
double scaleStep = Math.Pow(2.0, (double)(octaves) / Scales);
step = (float)(Scales / (Constants.Log2 * octaves));
// pattern definition, radius normalized to 1.0 (outer point position + sigma = 1.0)
// number of points on each concentric circle (from outer to inner)
int[] n = { 6, 6, 6, 6, 6, 6, 6, 1 };
double bigR = 2.0 / 3.0; // bigger radius
double smallR = 2.0 / 24.0; // smaller radius
double unitSpace = ((bigR - smallR) / 21.0); // define spaces between concentric circles (from center to outer: 1,2,3,4,5,6)
double[] radius =
{
bigR, bigR - 6 * unitSpace, // radii of the concentric circles (from outer to inner)
bigR - 11 * unitSpace, bigR - 15 * unitSpace,
bigR - 18 * unitSpace, bigR - 20 * unitSpace,
smallR, 0.0
};
double[] sigma =
{
radius[0]/2.0, radius[1]/2.0,
radius[2]/2.0, radius[3]/2.0, // sigma of the pattern points (each group of 6
radius[4]/2.0, radius[5]/2.0, // points on a concentric circle has same sigma)
radius[6]/2.0, radius[6]/2.0
};
// fill the lookup table
for (int scaleIdx = 0; scaleIdx < Scales; scaleIdx++)
{
patternSizes[scaleIdx] = 0;
double scalingFactor = Math.Pow(scaleStep, scaleIdx);
for (int orientationIdx = 0; orientationIdx < Orientations; orientationIdx++)
{
// orientation of the pattern
double theta = orientationIdx * 2 * Math.PI / Orientations;
int pointIdx = 0;
for (int i = 0; i < 8; i++)
{
for (int k = 0; k < n[i]; k++)
{
// Compute orientation offset so that groups
// of points on each circles become staggered
//
double beta = Math.PI / n[i] * (i % 2);
double alpha = k * 2 * Math.PI / n[i] + beta + theta;
// Add the point to the pattern look-up table
var point = new PatternPoint(
(float)(radius[i] * Math.Cos(alpha) * scalingFactor * scale),
(float)(radius[i] * Math.Sin(alpha) * scalingFactor * scale),
(float)(sigma[i] * scalingFactor * scale));
lookupTable[scaleIdx * Orientations * Points
+ orientationIdx * Points + pointIdx] = point;
// adapt the sizeList if necessary
int sizeMax = (int)Math.Ceiling((radius[i] + sigma[i]) * scalingFactor * scale) + 1;
if (patternSizes[scaleIdx] < sizeMax)
patternSizes[scaleIdx] = sizeMax;
pointIdx++;
}
}
}
}
// build the list of orientation pairs
orientationPairs[0].i = 0; orientationPairs[0].j = 3; orientationPairs[1].i = 1; orientationPairs[1].j = 4; orientationPairs[2].i = 2; orientationPairs[2].j = 5;
orientationPairs[3].i = 0; orientationPairs[3].j = 2; orientationPairs[4].i = 1; orientationPairs[4].j = 3; orientationPairs[5].i = 2; orientationPairs[5].j = 4;
orientationPairs[6].i = 3; orientationPairs[6].j = 5; orientationPairs[7].i = 4; orientationPairs[7].j = 0; orientationPairs[8].i = 5; orientationPairs[8].j = 1;
orientationPairs[9].i = 6; orientationPairs[9].j = 9; orientationPairs[10].i = 7; orientationPairs[10].j = 10; orientationPairs[11].i = 8; orientationPairs[11].j = 11;
orientationPairs[12].i = 6; orientationPairs[12].j = 8; orientationPairs[13].i = 7; orientationPairs[13].j = 9; orientationPairs[14].i = 8; orientationPairs[14].j = 10;
orientationPairs[15].i = 9; orientationPairs[15].j = 11; orientationPairs[16].i = 10; orientationPairs[16].j = 6; orientationPairs[17].i = 11; orientationPairs[17].j = 7;
orientationPairs[18].i = 12; orientationPairs[18].j = 15; orientationPairs[19].i = 13; orientationPairs[19].j = 16; orientationPairs[20].i = 14; orientationPairs[20].j = 17;
orientationPairs[21].i = 12; orientationPairs[21].j = 14; orientationPairs[22].i = 13; orientationPairs[22].j = 15; orientationPairs[23].i = 14; orientationPairs[23].j = 16;
orientationPairs[24].i = 15; orientationPairs[24].j = 17; orientationPairs[25].i = 16; orientationPairs[25].j = 12; orientationPairs[26].i = 17; orientationPairs[26].j = 13;
orientationPairs[27].i = 18; orientationPairs[27].j = 21; orientationPairs[28].i = 19; orientationPairs[28].j = 22; orientationPairs[29].i = 20; orientationPairs[29].j = 23;
orientationPairs[30].i = 18; orientationPairs[30].j = 20; orientationPairs[31].i = 19; orientationPairs[31].j = 21; orientationPairs[32].i = 20; orientationPairs[32].j = 22;
orientationPairs[33].i = 21; orientationPairs[33].j = 23; orientationPairs[34].i = 22; orientationPairs[34].j = 18; orientationPairs[35].i = 23; orientationPairs[35].j = 19;
orientationPairs[36].i = 24; orientationPairs[36].j = 27; orientationPairs[37].i = 25; orientationPairs[37].j = 28; orientationPairs[38].i = 26; orientationPairs[38].j = 29;
orientationPairs[39].i = 30; orientationPairs[39].j = 33; orientationPairs[40].i = 31; orientationPairs[40].j = 34; orientationPairs[41].i = 32; orientationPairs[41].j = 35;
orientationPairs[42].i = 36; orientationPairs[42].j = 39; orientationPairs[43].i = 37; orientationPairs[43].j = 40; orientationPairs[44].i = 38; orientationPairs[44].j = 41;
for (int m = 0; m < orientationPairs.Length; m++)
{
float dx = lookupTable[orientationPairs[m].i].x - lookupTable[orientationPairs[m].j].x;
float dy = lookupTable[orientationPairs[m].i].y - lookupTable[orientationPairs[m].j].y;
float norm_sq = (dx * dx + dy * dy);
orientationPairs[m].weight_dx = (int)((dx / (norm_sq)) * 4096.0 + 0.5);
orientationPairs[m].weight_dy = (int)((dy / (norm_sq)) * 4096.0 + 0.5);
}
// build the list of description pairs
var allPairs = new List<DescriptionPair>();
for (int i = 1; i < Points; i++)
for (int j = 0; j < i; j++)
allPairs.Add(new DescriptionPair(i, j));
// default selected pairs
for (int i = 0; i < descriptionPairs.Length; i++)
descriptionPairs[i] = allPairs[CV_FREAK_DEF_PAIRS[i]];
}