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

boofcv.alg.flow.HornSchunck 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) 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.flow;

import boofcv.alg.InputSanityCheck;
import boofcv.struct.flow.ImageFlow;
import boofcv.struct.image.ImageBase;
import boofcv.struct.image.ImageType;

/**
 * 

* This is Horn-Schunck's well known work [1] for dense optical flow estimation. It is based off the following * equation Ex*u + Ey*v + Et = 0, where (u,v) is the estimated flow for a single pixel, and (Ex,Ey) is the pixel's * gradient and Et is the grave in intensity value. It is assumed that each pixel maintains a constant intensity * and that changes in flow are smooth. This implementation is faithful to the original * work and does not make any effort to improve its performance using more modern techniques. *

* *

* [1] Horn, Berthold K., and Brian G. Schunck. "Determining optical flow." * 1981 Technical Symposium East. International Society for Optics and Photonics, 1981. *

* * @author Peter Abeles */ public abstract class HornSchunck, D extends ImageBase> { // used to weight the error of image brightness and smoothness of velocity flow protected float alpha2; // Number of iterations protected int numIterations; // storage for the average flow protected ImageFlow averageFlow = new ImageFlow(1, 1); // If the output should be cleared each time a new image is processed or used as an initial estimate protected boolean resetOutput = true; // storage for derivatives protected D derivX; protected D derivY; protected D derivT; /** * Constructor * * @param alpha Larger values place more importance on flow smoothness consistency over brightness consistency. Try 20 * @param numIterations Number of iterations. Try 1000 */ protected HornSchunck( float alpha, int numIterations, ImageType derivType ) { this.alpha2 = alpha*alpha; this.numIterations = numIterations; derivX = derivType.createImage(1, 1); derivY = derivType.createImage(1, 1); derivT = derivType.createImage(1, 1); } /** * changes the maximum number of iterations * * @param numIterations maximum number of iterations */ public void setNumIterations( int numIterations ) { this.numIterations = numIterations; } /** * Computes dense optical flow from the first image's gradient and the difference between * the second and the first image. * * @param image1 First image * @param image2 Second image * @param output Found dense optical flow */ public void process( T image1, T image2, ImageFlow output ) { InputSanityCheck.checkSameShape(image1, image2); derivX.reshape(image1.width, image1.height); derivY.reshape(image1.width, image1.height); derivT.reshape(image1.width, image1.height); averageFlow.reshape(output.width, output.height); if (resetOutput) output.fillZero(); computeDerivX(image1, image2, derivX); computeDerivY(image1, image2, derivY); computeDerivT(image1, image2, derivT); findFlow(derivX, derivY, derivT, output); } protected abstract void computeDerivX( T image1, T image2, D derivX ); protected abstract void computeDerivY( T image1, T image2, D derivY ); protected abstract void computeDerivT( T image1, T image2, D derivT ); /** * Inner function for computing optical flow */ protected abstract void findFlow( D derivX, D derivY, D derivT, ImageFlow output ); /** * Computes average flow using an 8-connect neighborhood for the inner image */ protected static void innerAverageFlow( ImageFlow flow, ImageFlow averageFlow ) { int endX = flow.width - 1; int endY = flow.height - 1; for (int y = 1; y < endY; y++) { int index = flow.width*y + 1; for (int x = 1; x < endX; x++, index++) { ImageFlow.D average = averageFlow.data[index]; ImageFlow.D f0 = flow.data[index - 1]; ImageFlow.D f1 = flow.data[index + 1]; ImageFlow.D f2 = flow.data[index - flow.width]; ImageFlow.D f3 = flow.data[index + flow.width]; ImageFlow.D f4 = flow.data[index - 1 - flow.width]; ImageFlow.D f5 = flow.data[index + 1 - flow.width]; ImageFlow.D f6 = flow.data[index - 1 + flow.width]; ImageFlow.D f7 = flow.data[index + 1 + flow.width]; average.x = 0.1666667f*(f0.x + f1.x + f2.x + f3.x) + 0.08333333f*(f4.x + f5.x + f6.x + f7.x); average.y = 0.1666667f*(f0.y + f1.y + f2.y + f3.y) + 0.08333333f*(f4.y + f5.y + f6.y + f7.y); } } } /** * Computes average flow using an 8-connect neighborhood for the image border */ protected static void borderAverageFlow( ImageFlow flow, ImageFlow averageFlow ) { for (int y = 0; y < flow.height; y++) { computeBorder(flow, averageFlow, 0, y); computeBorder(flow, averageFlow, flow.width - 1, y); } for (int x = 1; x < flow.width - 1; x++) { computeBorder(flow, averageFlow, x, 0); computeBorder(flow, averageFlow, x, flow.height - 1); } } protected static void computeBorder( ImageFlow flow, ImageFlow averageFlow, int x, int y ) { ImageFlow.D average = averageFlow.get(x, y); ImageFlow.D f0 = getExtend(flow, x - 1, y); ImageFlow.D f1 = getExtend(flow, x + 1, y); ImageFlow.D f2 = getExtend(flow, x, y - 1); ImageFlow.D f3 = getExtend(flow, x, y + 1); ImageFlow.D f4 = getExtend(flow, x - 1, y - 1); ImageFlow.D f5 = getExtend(flow, x + 1, y - 1); ImageFlow.D f6 = getExtend(flow, x - 1, y + 1); ImageFlow.D f7 = getExtend(flow, x + 1, y + 1); average.x = 0.1666667f*(f0.x + f1.x + f2.x + f3.x) + 0.08333333f*(f4.x + f5.x + f6.x + f7.x); average.y = 0.1666667f*(f0.y + f1.y + f2.y + f3.y) + 0.08333333f*(f4.y + f5.y + f6.y + f7.y); } protected static ImageFlow.D getExtend( ImageFlow flow, int x, int y ) { if (x < 0) x = 0; else if (x >= flow.width) x = flow.width - 1; if (y < 0) y = 0; else if (y >= flow.height) y = flow.height - 1; return flow.unsafe_get(x, y); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy