/*
* Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.alg.filter.kernel;
import boofcv.struct.convolve.*;
import boofcv.struct.image.GrayF32;
import boofcv.struct.image.GrayI;
import boofcv.struct.image.GrayS32;
/**
* @author Peter Abeles
*/
public class KernelMath {
public static void scale( Kernel1D_F32 kernel , float value ) {
for( int i = 0; i < kernel.width; i++ ) {
kernel.data[i] *= value;
}
}
public static void scale( Kernel1D_F64 kernel , double value ) {
for( int i = 0; i < kernel.width; i++ ) {
kernel.data[i] *= value;
}
}
public static void divide( Kernel1D_F32 kernel , float value ) {
for( int i = 0; i < kernel.width; i++ ) {
kernel.data[i] /= value;
}
}
public static void divide( Kernel1D_F64 kernel , double value ) {
for( int i = 0; i < kernel.width; i++ ) {
kernel.data[i] /= value;
}
}
public static void divide( Kernel2D_F32 kernel , float value ) {
int N = kernel.width*kernel.width;
for( int i = 0; i < N; i++ ) {
kernel.data[i] /= value;
}
}
public static void divide( Kernel2D_F64 kernel , double value ) {
int N = kernel.width*kernel.width;
for( int i = 0; i < N; i++ ) {
kernel.data[i] /= value;
}
}
public static void fill( Kernel2D_F32 kernel , float value ) {
int N = kernel.width*kernel.width;
for( int i = 0; i < N; i++ ) {
kernel.data[i] = value;
}
}
public static void fill( Kernel2D_I32 kernel , int value ) {
int N = kernel.width*kernel.width;
for( int i = 0; i < N; i++ ) {
kernel.data[i] = value;
}
}
public static Kernel2D_F32 transpose( Kernel2D_F32 a ) {
Kernel2D_F32 b = new Kernel2D_F32( a.width );
for( int i = 0; i < a.width; i++ ) {
for( int j = 0; j < a.width; j++ ) {
b.set(j,i,a.get(i,j));
}
}
return b;
}
public static Kernel2D_I32 transpose( Kernel2D_I32 a ) {
Kernel2D_I32 b = new Kernel2D_I32( a.width );
for( int i = 0; i < a.width; i++ ) {
for( int j = 0; j < a.width; j++ ) {
b.set(j,i,a.get(i,j));
}
}
return b;
}
public static Kernel1D convolve1D( Kernel1D a , Kernel1D b ) {
if( a instanceof Kernel1D_I32 ) {
return convolve1D_I32((Kernel1D_I32)a,(Kernel1D_I32)b);
} else if( a instanceof Kernel1D_F32 ) {
return convolve1D_F32((Kernel1D_F32)a,(Kernel1D_F32)b);
} else {
throw new RuntimeException("Unknown kernel type");
}
}
public static Kernel1D_I32 convolve1D_I32(Kernel1D_I32 a , Kernel1D_I32 b ) {
int w = a.width+b.width-1;
Kernel1D_I32 ret = new Kernel1D_I32(w);
int end = w-(b.getWidth()-1);
int N = b.width-1;
int index = 0;
for( int j = -(b.getWidth()-1); j < end; j++ ) {
int sum = 0;
for( int k = 0; k < b.getWidth(); k++ ) {
if( j+k >= 0 && j+k < a.getWidth() ) {
int valB = b.data[N-k];
int valA = a.data[j+k];
sum += valB*valA;
}
}
ret.data[index++] = sum;
}
return ret;
}
public static Kernel1D_F32 convolve1D_F32(Kernel1D_F32 a , Kernel1D_F32 b ) {
int w = a.width+b.width-1;
Kernel1D_F32 ret = new Kernel1D_F32(w);
int end = w-(b.getWidth()-1);
int N = b.width-1;
int index = 0;
for( int j = -(b.getWidth()-1); j < end; j++ ) {
float sum = 0;
for( int k = 0; k < b.getWidth(); k++ ) {
if( j+k >= 0 && j+k < a.getWidth() ) {
float valB = b.data[N-k];
float valA = a.data[j+k];
sum += valB*valA;
}
}
ret.data[index++] = sum;
}
return ret;
}
public static Kernel2D convolve2D( Kernel2D a , Kernel2D b ) {
if( a instanceof Kernel2D_I32 ) {
return convolve2D((Kernel2D_I32)a,(Kernel2D_I32)b);
} else if( a instanceof Kernel2D_F32 ) {
return convolve2D((Kernel2D_F32)a,(Kernel2D_F32)b);
} else {
throw new RuntimeException("Unknown kernel type");
}
}
public static Kernel2D_I32 convolve2D( Kernel2D_I32 a , Kernel2D_I32 b ) {
int w = a.width+b.width-1;
int r = w/2;
Kernel2D_I32 ret = new Kernel2D_I32(w);
int aR = a.width/2;
int bR = b.width/2;
for( int y = -r; y <= r; y++ ) {
for( int x = -r; x <= r; x++ ) {
int sum = 0;
// go through kernel A
for( int y0 = -aR; y0 <= aR; y0++ ) {
// convert to kernel coordinates
int ay = -y0 + aR;
int by = y + y0 + bR;
if( by < 0 || by >= b.width )
continue;
for( int x0 = -aR; x0 <= aR; x0++ ) {
// convert to kernel coordinates
int ax = -x0 + aR;
int bx = x + x0 + bR;
if( bx < 0 || bx >= b.width )
continue;
sum += a.get(ax,ay) * b.get(bx,by);
}
}
ret.set(x+r,y+r,sum);
}
}
return ret;
}
public static Kernel2D_F32 convolve2D(Kernel2D_F32 a , Kernel2D_F32 b ) {
int w = a.width+b.width-1;
int r = w/2;
Kernel2D_F32 ret = new Kernel2D_F32(w);
int aR = a.width/2;
int bR = b.width/2;
for( int y = -r; y <= r; y++ ) {
for( int x = -r; x <= r; x++ ) {
float sum = 0;
// go through kernel A
for( int y0 = -aR; y0 <= aR; y0++ ) {
// convert to kernel coordinates
int ay = -y0 + aR;
int by = y + y0 + bR;
if( by < 0 || by >= b.width )
continue;
for( int x0 = -aR; x0 <= aR; x0++ ) {
// convert to kernel coordinates
int ax = -x0 + aR;
int bx = x + x0 + bR;
if( bx < 0 || bx >= b.width )
continue;
sum += a.get(ax,ay) * b.get(bx,by);
}
}
ret.set(x+r,y+r,sum);
}
}
return ret;
}
/**
* Convolve two 1D kernels together to form a 2D kernel.
*
* @param a Input vertical 1D kernel
* @param b Input horizontal 1D kernel
* @return Resulting 2D kernel
*/
public static Kernel2D convolve2D(Kernel1D a, Kernel1D b) {
if( a instanceof Kernel1D_I32 ) {
return convolve2D((Kernel1D_I32)a,(Kernel1D_I32)b);
} else if( a instanceof Kernel1D_F32 ) {
return convolve2D((Kernel1D_F32)a,(Kernel1D_F32)b);
} else if( a instanceof Kernel1D_F64 ) {
return convolve2D((Kernel1D_F64)a,(Kernel1D_F64)b);
} else {
throw new RuntimeException("Unknown kernel type");
}
}
/**
* Convolve two 1D kernels together to form a 2D kernel.
*
* @param a Input vertical 1D kernel
* @param b Input horizontal 1D kernel
* @return Resulting 2D kernel
*/
public static Kernel2D_F32 convolve2D(Kernel1D_F32 a, Kernel1D_F32 b) {
if( a.width != b.width )
throw new IllegalArgumentException("Only kernels with the same width supported");
if( a.offset != b.width/2 )
throw new IllegalArgumentException("Only kernels with the offset in the middle supported");
int w = a.width;
Kernel2D_F32 ret = new Kernel2D_F32(w);
int index = 0;
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.data[ index++ ] = a.data[i] * b.data[j];
}
}
return ret;
}
/**
* Convolve two 1D kernels together to form a 2D kernel.
*
* @param a Input vertical 1D kernel
* @param b Input horizontal 1D kernel
* @return Resulting 2D kernel
*/
public static Kernel2D_F64 convolve2D(Kernel1D_F64 a, Kernel1D_F64 b) {
if( a.width != b.width )
throw new IllegalArgumentException("Only kernels with the same width supported");
if( a.offset != b.width/2 )
throw new IllegalArgumentException("Only kernels with the offset in the middle supported");
int w = a.width;
Kernel2D_F64 ret = new Kernel2D_F64(w);
int index = 0;
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.data[ index++ ] = a.data[i] * b.data[j];
}
}
return ret;
}
/**
* Convolve two 1D kernels together to form a 2D kernel.
*
* @param a Input vertical 1D kernel
* @param b Input horizontal 1D kernel
* @return Resulting 2D kernel
*/
public static Kernel2D_I32 convolve2D(Kernel1D_I32 a, Kernel1D_I32 b) {
if( a.width != b.width )
throw new IllegalArgumentException("Only kernels with the same width supported");
if( a.offset != b.width/2 )
throw new IllegalArgumentException("Only kernels with the offset in the middle supported");
int w = a.width;
Kernel2D_I32 ret = new Kernel2D_I32(w);
int index = 0;
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.data[ index++ ] = a.data[i] * b.data[j];
}
}
return ret;
}
/**
* Normalizes the array such that it sums up to one.
*
* @param kernel The kernel being normalized.
*/
public static void normalizeSumToOne(Kernel1D_F32 kernel) {
float[] data = kernel.data;
float total = 0;
for (int i = 0; i < data.length; i++) total += data[i];
for (int i = 0; i < data.length; i++) data[i] /= total;
}
public static void normalizeSumToOne(Kernel1D_F64 kernel) {
double[] data = kernel.data;
double total = 0;
for (int i = 0; i < data.length; i++) total += data[i];
for (int i = 0; i < data.length; i++) data[i] /= total;
}
/**
* Normalizes the array such that it sums up to one.
*
* @param kernel The kernel being normalized.
*/
public static void normalizeSumToOne(Kernel2D_F32 kernel) {
float[] data = kernel.data;
float total = 0;
for (int i = 0; i < data.length; i++) total += data[i];
for (int i = 0; i < data.length; i++) data[i] /= total;
}
public static void normalizeSumToOne(Kernel2D_F64 kernel) {
double[] data = kernel.data;
double total = 0;
for (int i = 0; i < data.length; i++) total += data[i];
for (int i = 0; i < data.length; i++) data[i] /= total;
}
/**
* Normalizes the array such that the absolute value sums up to one.
*
* @param kernel The kernel being normalized.
*/
public static void normalizeAbsSumToOne(Kernel2D_F32 kernel) {
float[] data = kernel.data;
float total = 0;
for (int i = 0; i < data.length; i++) total += Math.abs(data[i]);
for (int i = 0; i < data.length; i++) data[i] /= total;
}
public static double sum(Kernel2D_F64 kernel) {
double[] data = kernel.data;
double total = 0;
for (int i = 0; i < data.length; i++) total += data[i];
return total;
}
public static void normalizeF(Kernel2D_F64 kernel) {
double[] data = kernel.data;
double norm = 0;
for (int i = 0; i < data.length; i++) norm += data[i]*data[i];
norm = Math.sqrt(norm);
for (int i = 0; i < data.length; i++) data[i] /= norm;
}
/**
* Normalizes it such that the largest element is equal to one
*/
public static void normalizeMaxOne(Kernel2D_F64 kernel) {
double max = -Double.MAX_VALUE;
int N = kernel.width*kernel.width;
for (int i = 0; i < N; i++) {
max = Math.max(max,kernel.data[i]);
}
for (int i = 0; i < N; i++) {
kernel.data[i] /= max;
}
}
public static GrayF32 convertToImage(Kernel2D_F32 kernel ) {
int w = kernel.getWidth();
GrayF32 ret = new GrayF32(w,w);
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.set(j,i,kernel.get(j,i));
}
}
return ret;
}
public static GrayS32 convertToImage(Kernel2D_I32 kernel ) {
int w = kernel.getWidth();
GrayS32 ret = new GrayS32(w,w);
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.set(j,i,kernel.get(j,i));
}
}
return ret;
}
public static Kernel2D_F32 convertToKernel( GrayF32 image ) {
int w = image.getWidth();
Kernel2D_F32 ret = new Kernel2D_F32(w);
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.set(j,i,image.get(j,i));
}
}
return ret;
}
public static Kernel2D_I32 convertToKernel( GrayI image ) {
int w = image.getWidth();
Kernel2D_I32 ret = new Kernel2D_I32(w);
for( int i = 0; i < w; i++ ) {
for( int j = 0; j < w; j++ ) {
ret.set(j,i,image.get(j,i));
}
}
return ret;
}
public static Kernel2D_I32 convert( Kernel2D_F32 original , float minFrac ) {
Kernel2D_I32 ret = new Kernel2D_I32(original.width);
convert( original.data,ret.data,original.width*original.width,minFrac);
return ret;
}
public static Kernel1D_I32 convert( Kernel1D_F32 original , float minFrac ) {
Kernel1D_I32 ret = new Kernel1D_I32(original.width, original.offset);
convert( original.data,ret.data,original.width,minFrac);
return ret;
}
public static Kernel1D_I32 convert( Kernel1D_F64 original , double minFrac ) {
Kernel1D_I32 ret = new Kernel1D_I32(original.width, original.offset);
convert( original.data,ret.data,original.width,minFrac);
return ret;
}
public static void convert( float input[] , int output[] , int size , float minFrac) {
float max = maxAbs(input,size);
float min = minAbs(input,size,max*minFrac);
for( int i = 0; i < size; i++ ) {
output[i] = (int)(input[i]/min);
}
}
public static void convert( double input[] , int output[] , int size , double minFrac) {
double max = maxAbs(input,size);
double min = minAbs(input,size,max*minFrac);
for( int i = 0; i < size; i++ ) {
output[i] = (int)(input[i]/min);
}
}
public static float maxAbs( float data[] , int size ) {
float max = 0;
for( int i = 0; i < size; i++ ) {
float v = Math.abs(data[i]);
if( v > max )
max = v;
}
return max;
}
public static double maxAbs( double data[] , int size ) {
double max = 0;
for( int i = 0; i < size; i++ ) {
double v = Math.abs(data[i]);
if( v > max )
max = v;
}
return max;
}
public static float minAbs( float data[] , int size , float minValue ) {
float min = Float.MAX_VALUE;
for( int i = 0; i < size; i++ ) {
float v = Math.abs(data[i]);
if( v < min && v >= minValue )
min = v;
}
return min;
}
public static double minAbs( double data[] , int size , double minValue ) {
double min = Float.MAX_VALUE;
for( int i = 0; i < size; i++ ) {
double v = Math.abs(data[i]);
if( v < min && v >= minValue )
min = v;
}
return min;
}
public static boolean isEqualsFrac( float expected[] , float found[] , int size , float fracTol , float zero ) {
for( int i = 0; i < size; i++ ) {
float norm = Math.max(Math.abs(expected[i]),Math.abs(found[i]));
if( norm < zero ) continue;
float diff = Math.abs(expected[i] - found[i])/norm;
if( diff > fracTol )
return false;
}
return true;
}
public static boolean isEquals( float expected[] , float found[] , int size , float tol ) {
for( int i = 0; i < size; i++ ) {
float diff = Math.abs(expected[i] - found[i]);
if( diff > tol )
return false;
}
return true;
}
public static boolean isEquals( int expected[] , int found[] , int size ) {
for( int i = 0; i < size; i++ ) {
float diff = Math.abs(expected[i] - found[i]);
if( diff > 0 )
return false;
}
return true;
}
}
Ads help maintain this website.