All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.alg.transform.census.CensusTransform Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

The newest version!
/*
 * Copyright (c) 2020, 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.census;

import boofcv.alg.InputSanityCheck;
import boofcv.alg.transform.census.impl.ImplCensusTransformBorder;
import boofcv.alg.transform.census.impl.ImplCensusTransformInner;
import boofcv.alg.transform.census.impl.ImplCensusTransformInner_MT;
import boofcv.concurrency.BoofConcurrency;
import boofcv.misc.BoofMiscOps;
import boofcv.struct.border.ImageBorder_F32;
import boofcv.struct.border.ImageBorder_S32;
import boofcv.struct.image.*;
import georegression.struct.point.Point2D_I32;
import org.ddogleg.struct.DogArray;
import org.ddogleg.struct.DogArray_I32;
import org.ddogleg.struct.FastAccess;
import org.jetbrains.annotations.Nullable;

/**
 * 

The Census Transform [1] computes a bit mask for each pixel in the image. If a neighboring pixel is greater than the * center pixel in a region that bit is set to 1. A 3x3 region 9radius=1) is encoded in 8-bits and a 5x5 region * (radius=2) in 24-bits. To compute the error between two pixels simply compute the hamming distance. The * hamming distance for an input can be computed using DescriptorDistance.hamming().

* *

DEVELOPMENT NOTE: See if this can be speed up by only comparing each pixel with another once. * Code will be complex

* *

* [1] Zabih, Ramin, and John Woodfill. "Non-parametric local transforms for computing visual correspondence." * European conference on computer vision. Springer, Berlin, Heidelberg, 1994. *

* * @author Peter Abeles */ public class CensusTransform { public static DogArray createBlockSamples( int radius ) { DogArray samples = new DogArray<>(Point2D_I32::new); int w = radius*2 + 1; samples.reserve(w*w - 1); for (int y = -radius; y <= radius; y++) { for (int x = -radius; x <= radius; x++) { if (x == 0 && y == 0) // don't sample the center continue; samples.grow().setTo(x, y); } } return samples; } public static DogArray createBlockSamples( int radiusX, int radiusY ) { DogArray samples = new DogArray<>(Point2D_I32::new); int wx = radiusX*2 + 1; int wy = radiusY*2 + 1; samples.reserve(wx*wy - 1); for (int y = -radiusY; y <= radiusY; y++) { for (int x = -radiusX; x <= radiusX; x++) { if (x == 0 && y == 0) // don't sample the center continue; samples.grow().setTo(x, y); } } return samples; } public static DogArray createCircleSamples() { DogArray samples = new DogArray<>(Point2D_I32::new); for (int row = 0; row < 9; row++) { int col0 = row <= 4 ? Math.max(0, 3 - row) : row - 5; int col1 = 9 - col0; for (int col = col0; col < col1; col++) { if (row == 4 && col == 4) continue; samples.grow().setTo(row - 4, col - 4); } } return samples; } /** * Census transform for local 3x3 region around each pixel. * * @param input Input image * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void dense3x3( final GrayU8 input, final GrayU8 output, @Nullable ImageBorder_S32 border ) { InputSanityCheck.checkReshape(input, output); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.dense3x3(input, output); } else { ImplCensusTransformInner.dense3x3(input, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.dense3x3_U8(border, output); } } /** * Census transform for local 3x3 region around each pixel. * * @param input Input image * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void dense3x3( final GrayU16 input, final GrayU8 output, @Nullable ImageBorder_S32 border ) { InputSanityCheck.checkReshape(input, output); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.dense3x3(input, output); } else { ImplCensusTransformInner.dense3x3(input, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.dense3x3_U8(border, output); } } /** * Census transform for local 3x3 region around each pixel. * * @param input Input image * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void dense3x3( final GrayF32 input, final GrayU8 output, @Nullable ImageBorder_F32 border ) { InputSanityCheck.checkReshape(input, output); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.dense3x3(input, output); } else { ImplCensusTransformInner.dense3x3(input, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.dense3x3_F32(border, output); } } /** * Census transform for local 5x5 region around each pixel. * * @param input Input image * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void dense5x5( final GrayU8 input, final GrayS32 output, @Nullable ImageBorder_S32 border ) { InputSanityCheck.checkReshape(input, output); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.dense5x5(input, output); } else { ImplCensusTransformInner.dense5x5(input, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.dense5x5_U8(border, output); } } /** * Census transform for local 5x5 region around each pixel. * * @param input Input image * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void dense5x5( final GrayU16 input, final GrayS32 output, @Nullable ImageBorder_S32 border ) { InputSanityCheck.checkReshape(input, output); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.dense5x5(input, output); } else { ImplCensusTransformInner.dense5x5(input, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.dense5x5_U8(border, output); } } /** * Census transform for local 5x5 region around each pixel. * * @param input Input image * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void dense5x5( final GrayF32 input, final GrayS32 output, @Nullable ImageBorder_F32 border ) { InputSanityCheck.checkReshape(input, output); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.dense5x5(input, output); } else { ImplCensusTransformInner.dense5x5(input, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.dense5x5_F32(border, output); } } /** * Census transform for an arbitrary region specified by the provided sample points * * @param input Input image * @param sample Relative coordinates that are sampled when computing the * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void sample_S64( final GrayU8 input, final FastAccess sample, final GrayS64 output, @Nullable ImageBorder_S32 border, @Nullable DogArray_I32 workSpace ) { output.reshape(input.width, input.height); // Precompute the offset in array indexes for the sample points if (workSpace == null) workSpace = new DogArray_I32(); int borderRadius = computeRadiusWorkspace(input, sample, workSpace); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.sample_S64(input, borderRadius, workSpace, output); } else { ImplCensusTransformInner.sample_S64(input, borderRadius, workSpace, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.sample_S64(border, borderRadius, sample, output); } } /** * Census transform for an arbitrary region specified by the provided sample points * * @param input Input image * @param sample Relative coordinates that are sampled when computing the * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void sample_S64( final GrayU16 input, final FastAccess sample, final GrayS64 output, @Nullable ImageBorder_S32 border, @Nullable DogArray_I32 workSpace ) { output.reshape(input.width, input.height); // Precompute the offset in array indexes for the sample points if (workSpace == null) workSpace = new DogArray_I32(); int borderRadius = computeRadiusWorkspace(input, sample, workSpace); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.sample_S64(input, borderRadius, workSpace, output); } else { ImplCensusTransformInner.sample_S64(input, borderRadius, workSpace, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.sample_S64(border, borderRadius, sample, output); } } /** * Census transform for an arbitrary region specified by the provided sample points * * @param input Input image * @param sample Relative coordinates that are sampled when computing the * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void sample_S64( final GrayF32 input, final FastAccess sample, final GrayS64 output, @Nullable ImageBorder_F32 border, @Nullable DogArray_I32 workSpace ) { output.reshape(input.width, input.height); // Precompute the offset in array indexes for the sample points if (workSpace == null) workSpace = new DogArray_I32(); int borderRadius = computeRadiusWorkspace(input, sample, workSpace); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.sample_S64(input, borderRadius, workSpace, output); } else { ImplCensusTransformInner.sample_S64(input, borderRadius, workSpace, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.sample_S64(border, borderRadius, sample, output); } } /** * Census transform for an arbitrary region specified by the provided sample points * * @param input Input image * @param sample Relative coordinates that are sampled when computing the * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void sample_IU16( final GrayU8 input, final FastAccess sample, final InterleavedU16 output, @Nullable ImageBorder_S32 border, @Nullable DogArray_I32 workSpace ) { // Compute the number of 16-bit values that are needed to store int numBlocks = BoofMiscOps.bitsToWords(sample.size, 16); output.reshape(input.width, input.height, numBlocks); // Precompute the offset in array indexes for the sample points if (workSpace == null) workSpace = new DogArray_I32(); int borderRadius = computeRadiusWorkspace(input, sample, workSpace); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.sample_IU16(input, borderRadius, workSpace, output); } else { ImplCensusTransformInner.sample_IU16(input, borderRadius, workSpace, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.sample_IU16(border, borderRadius, sample, output); } } /** * Census transform for an arbitrary region specified by the provided sample points * * @param input Input image * @param sample Relative coordinates that are sampled when computing the * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void sample_IU16( final GrayU16 input, final FastAccess sample, final InterleavedU16 output, @Nullable ImageBorder_S32 border, @Nullable DogArray_I32 workSpace ) { // Compute the number of 16-bit values that are needed to store int numBlocks = BoofMiscOps.bitsToWords(sample.size, 16); output.reshape(input.width, input.height, numBlocks); // Precompute the offset in array indexes for the sample points if (workSpace == null) workSpace = new DogArray_I32(); int borderRadius = computeRadiusWorkspace(input, sample, workSpace); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.sample_IU16(input, borderRadius, workSpace, output); } else { ImplCensusTransformInner.sample_IU16(input, borderRadius, workSpace, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.sample_IU16(border, borderRadius, sample, output); } } /** * Census transform for an arbitrary region specified by the provided sample points * * @param input Input image * @param sample Relative coordinates that are sampled when computing the * @param output Census transformed output image * @param border (Nullable) How the border is handled */ public static void sample_IU16( final GrayF32 input, final FastAccess sample, final InterleavedU16 output, @Nullable ImageBorder_F32 border, @Nullable DogArray_I32 workSpace ) { // Compute the number of 16-bit values that are needed to store int numBlocks = BoofMiscOps.bitsToWords(sample.size, 16); output.reshape(input.width, input.height, numBlocks); // Precompute the offset in array indexes for the sample points if (workSpace == null) workSpace = new DogArray_I32(); int borderRadius = computeRadiusWorkspace(input, sample, workSpace); if (BoofConcurrency.USE_CONCURRENT) { ImplCensusTransformInner_MT.sample_IU16(input, borderRadius, workSpace, output); } else { ImplCensusTransformInner.sample_IU16(input, borderRadius, workSpace, output); } if (border != null) { border.setImage(input); ImplCensusTransformBorder.sample_IU16(border, borderRadius, sample, output); } } /** * @param input (Input) Input image * @param sample (Input) Points being sampled * @param workSpace (Output) Stores the offsets from current point that need to be sampled * @return The maximum distance away (x and y) that a point is sampled */ private static int computeRadiusWorkspace( ImageBase input, FastAccess sample, DogArray_I32 workSpace ) { int radius = 0; workSpace.resize(sample.size); for (int i = 0; i < sample.size; i++) { Point2D_I32 p = sample.get(i); workSpace.data[i] = p.y*input.stride + p.x; radius = Math.max(radius, Math.abs(p.x)); radius = Math.max(radius, Math.abs(p.y)); } return radius; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy