boofcv.alg.transform.ii.DerivativeIntegralImage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of boofcv-ip Show documentation
Show all versions of boofcv-ip Show documentation
BoofCV is an open source Java library for real-time computer vision and robotics applications.
/*
* Copyright (c) 2021, 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.transform.ii;
import boofcv.struct.image.GrayF32;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Functions related to image derivatives in integral images.
*
* @author Peter Abeles
*/
public class DerivativeIntegralImage {
/**
* Creates a kernel for a symmetric box derivative.
*
* @param r Radius of the box. width is 2*r+1
* @return Kernel Kernel for derivative.
*/
public static IntegralKernel kernelDerivX( int r, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 2);
ret.blocks[0].setTo(-r - 1, -r - 1, -1, r);
ret.blocks[1].setTo(0, -r - 1, r, r);
ret.scales[0] = -1;
ret.scales[1] = 1;
return ret;
}
@NotNull private static IntegralKernel checkDeclareKernel( @Nullable IntegralKernel ret, int numBlocks ) {
if (ret == null)
ret = new IntegralKernel(numBlocks);
else
ret.resizeBlocks(numBlocks);
return ret;
}
/**
* Creates a kernel for a symmetric box derivative.
*
* @param r Radius of the box. width is 2*r+1
* @return Kernel Kernel for derivative.
*/
public static IntegralKernel kernelDerivY( int r, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 2);
ret.blocks[0].setTo(-r - 1, -r - 1, r, -1);
ret.blocks[1].setTo(-r - 1, 0, r, r);
ret.scales[0] = -1;
ret.scales[1] = 1;
return ret;
}
/**
* Creates a kernel for the Haar wavelet "centered" around the target pixel.
*
* @param r Radius of the box. width is 2*r
* @return Kernel for a Haar x-axis wavelet.
*/
public static IntegralKernel kernelHaarX( int r, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 2);
ret.blocks[0].setTo(-r, -r, 0, r);
ret.blocks[1].setTo(0, -r, r, r);
ret.scales[0] = -1;
ret.scales[1] = 1;
return ret;
}
/**
* Creates a kernel for the Haar wavelet "centered" around the target pixel.
*
* @param r Radius of the box. width is 2*r
* @return Kernel for a Haar y-axis wavelet.
*/
public static IntegralKernel kernelHaarY( int r, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 2);
ret.blocks[0].setTo(-r, -r, r, 0);
ret.blocks[1].setTo(-r, 0, r, r);
ret.scales[0] = -1;
ret.scales[1] = 1;
return ret;
}
public static IntegralKernel kernelDerivXX( int size, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 2);
// lobe size
int blockW = size/3;
// horizontal band size
int blockH = size - blockW - 1;
int r1 = blockW/2;
int r2 = blockW + r1;
int r3 = blockH/2;
ret.blocks[0].setTo(-r2 - 1, -r3 - 1, r2, r3);
ret.blocks[1].setTo(-r1 - 1, -r3 - 1, r1, r3);
ret.scales[0] = 1;
ret.scales[1] = -3;
return ret;
}
public static IntegralKernel kernelDerivYY( int size, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 2);
int blockW = size/3;
int blockH = size - blockW - 1;
int r1 = blockW/2;
int r2 = blockW + r1;
int r3 = blockH/2;
ret.blocks[0].setTo(-r3 - 1, -r2 - 1, r3, r2);
ret.blocks[1].setTo(-r3 - 1, -r1 - 1, r3, r1);
ret.scales[0] = 1;
ret.scales[1] = -3;
return ret;
}
public static IntegralKernel kernelDerivXY( int size, @Nullable IntegralKernel ret ) {
ret = checkDeclareKernel(ret, 4);
int block = size/3;
ret.blocks[0].setTo(-block - 1, -block - 1, -1, -1);
ret.blocks[1].setTo(0, -block - 1, block, -1);
ret.blocks[2].setTo(0, 0, block, block);
ret.blocks[3].setTo(-block - 1, 0, -1, block);
ret.scales[0] = 1;
ret.scales[1] = -1;
ret.scales[2] = 1;
ret.scales[3] = -1;
return ret;
}
public static void derivXX( GrayF32 input, GrayF32 output, int size ) {
int blockW = size/3;
int blockH = size - blockW - 1;
int radiusW = size/2;
int radiusH = blockH/2;
int blockW2 = 2*blockW;
int blockW3 = 3*blockW;
int endY = input.height - radiusH;
int endX = input.width - radiusW;
for (int y = radiusH + 1; y < endY; y++) {
int indexTop = input.startIndex + (y - radiusH - 1)*input.stride;
int indexBottom = indexTop + blockH*input.stride;
int indexDst = output.startIndex + y*output.stride + radiusW + 1;
for (int x = radiusW + 1; x < endX; x++, indexTop++, indexBottom++, indexDst++) {
float sum = input.data[indexBottom + blockW3] - input.data[indexTop + blockW3] - input.data[indexBottom] + input.data[indexTop];
sum -= 3*(input.data[indexBottom + blockW2] - input.data[indexTop + blockW2] - input.data[indexBottom + blockW] + input.data[indexTop + blockW]);
output.data[indexDst] = sum;
}
}
}
public static void derivYY( GrayF32 input, GrayF32 output, int size ) {
int blockH = size/3;
int blockW = size - blockH - 1;
int radiusH = size/2;
int radiusW = blockW/2;
int rowOff1 = blockH*input.stride;
int rowOff2 = 2*rowOff1;
int rowOff3 = 3*rowOff1;
int endY = input.height - radiusH;
int endX = input.width - radiusW;
for (int y = radiusH + 1; y < endY; y++) {
int indexL = input.startIndex + (y - radiusH - 1)*input.stride;
int indexR = indexL + blockW;
int indexDst = output.startIndex + y*output.stride + radiusW + 1;
for (int x = radiusW + 1; x < endX; x++, indexL++, indexR++, indexDst++) {
float sum = input.data[indexR + rowOff3] - input.data[indexL + rowOff3] - input.data[indexR] + input.data[indexL];
sum -= 3*(input.data[indexR + rowOff2] - input.data[indexL + rowOff2] - input.data[indexR + rowOff1] + input.data[indexL + rowOff1]);
output.data[indexDst] = sum;
}
}
}
public static void derivXY( GrayF32 input, GrayF32 output, int size ) {
int block = size/3;
int endY = input.height - block;
int endX = input.width - block;
for (int y = block + 1; y < endY; y++) {
int indexY1 = input.startIndex + (y - block - 1)*input.stride;
int indexY2 = indexY1 + block*input.stride;
int indexY3 = indexY2 + input.stride;
int indexY4 = indexY3 + block*input.stride;
int indexDst = output.startIndex + y*output.stride + block + 1;
for (int x = block + 1; x < endX; x++, indexY1++, indexY2++, indexY3++, indexY4++, indexDst++) {
int x3 = block + 1;
int x4 = x3 + block;
float sum = input.data[indexY2 + block] - input.data[indexY1 + block] - input.data[indexY2] + input.data[indexY1];
sum -= input.data[indexY2 + x4] - input.data[indexY1 + x4] - input.data[indexY2 + x3] + input.data[indexY1 + x3];
sum += input.data[indexY4 + x4] - input.data[indexY3 + x4] - input.data[indexY4 + x3] + input.data[indexY3 + x3];
sum -= input.data[indexY4 + block] - input.data[indexY3 + block] - input.data[indexY4] + input.data[indexY3];
output.data[indexDst] = sum;
}
}
}
}