Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.misc;
import boofcv.BoofVerbose;
import boofcv.errors.BoofCheckFailure;
import boofcv.struct.Configuration;
import boofcv.struct.ImageRectangle;
import boofcv.struct.image.*;
import georegression.struct.GeoTuple;
import georegression.struct.point.Point2D_F64;
import org.ddogleg.struct.*;
import org.ejml.data.DMatrixRMaj;
import org.jetbrains.annotations.Nullable;
import pabeles.concurrency.ConcurrencyOps;
import pabeles.concurrency.GrowArray;
import java.io.*;
import java.lang.reflect.Method;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* Miscellaneous functions which have no better place to go.
*
* @author Peter Abeles
*/
@SuppressWarnings("rawtypes")
public class BoofMiscOps {
/**
* Number of characters in the class name prefix in verbose printing
*/
public static int VERBOSE_PREFIX_LENGTH = 6;
/**
* Prints a table explaining what the prefixes are
*/
public static boolean VERBOSE_PRINT_TABLE = true;
/**
* Computes the elapsed time in calling the provided function in nano seconds
*/
public static long timeNano( BoofLambdas.ProcessCall process ) {
long time0 = System.nanoTime();
process.process();
long time1 = System.nanoTime();
return time1 - time0;
}
public static void profile( BoofLambdas.ProcessCall process, String description ) {
long nano = timeNano(process);
System.out.println("Elapsed: " + (nano*1e-6) + " (ms) " + description);
}
public static String timeStr() {
return Instant.now()
.atOffset(ZoneOffset.UTC)
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.replace("T", " ");
}
public static String timeStr( long systemTimeMS ) {
return Instant.ofEpochMilli(systemTimeMS)
.atOffset(ZoneOffset.UTC)
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.replace("T", " ");
}
/**
* Checks to see if the passed in string starts with a ~ and if so it will replace it with the
* users home directory.
*/
public static String handlePathTilde( String path ) {
return path.replaceFirst("^~", System.getProperty("user.home"));
}
public static float bound( float value, float min, float max ) {
if (value <= min)
return min;
if (value >= max)
return max;
return value;
}
public static double bound( double value, double min, double max ) {
if (value <= min)
return min;
if (value >= max)
return max;
return value;
}
public static void offsetPixels( final List list, final double dx, final double dy ) {
for (int i = 0; i < list.size(); i++) {
Point2D_F64 p = list.get(i);
p.x += dx;
p.y += dy;
}
}
public static String[] toStringArray( List files ) {
String[] output = new String[files.size()];
for (int i = 0; i < files.size(); i++) {
output[i] = files.get(i).getPath();
}
return output;
}
/**
* Copies all of src into dst by appended it onto it
*/
public static >
void copyAll( FastAccess src, DogArray dst ) {
dst.reserve(dst.size + src.size);
for (int i = 0; i < src.size; i++) {
dst.grow().setTo(src.get(i));
}
}
public static List toFileList( String[] files ) {
List output = new ArrayList<>();
for (String s : files) { // lint:forbidden ignore_line
output.add(new File(s));
}
return output;
}
// Remove when Minimum Java version is 11
public static List asList( T... objects ) {
List list = new ArrayList<>();
for (int i = 0; i < objects.length; i++) {
list.add(objects[i]);
}
return list;
}
public static List toFileList( List files ) {
List output = new ArrayList<>();
for (String s : files) { // lint:forbidden ignore_line
output.add(new File(s));
}
return output;
}
public static int bitsToWords( int bits, int wordBits ) {
return (bits/wordBits) + (bits%wordBits == 0 ? 0 : 1);
}
public static int numBands( ImageBase img ) {
if (img instanceof ImageMultiBand) {
return ((ImageMultiBand)img).getNumBands();
} else {
return 1;
}
}
public static String milliToHuman( long milliseconds ) {
long second = (milliseconds/1000)%60;
long minute = (milliseconds/(1000*60))%60;
long hour = (milliseconds/(1000*60*60))%24;
long days = milliseconds/(1000*60*60*24);
return String.format("%03d:%02d:%02d:%02d (days:hrs:min:sec)", days, hour, minute, second);
}
public static double diffRatio( double a, double b ) {
return Math.abs(a - b)/Math.max(a, b);
}
/**
* Returns the number of digits in a number. E.g. 345 = 3, -345 = 4, 0 = 1
*/
public static int numDigits( int number ) {
if (number == 0)
return 1;
int adjustment = 0;
if (number < 0) {
adjustment = 1;
number = -number;
}
return adjustment + (int)Math.log10(number) + 1;
}
public static double pow2( double v ) {
return v*v;
}
public static float pow2( float v ) {
return v*v;
}
public static void sortFileNames( List images ) {
images.sort(new CompareStringNames());
}
public static void sortFilesByName( List images ) {
images.sort(Comparator.comparing(File::getName));
}
public static void printMethodInfo( Method target, PrintStream out ) {
Class[] types = target.getParameterTypes();
out.println("Method: " + target.getName() + " param.length = " + types.length);
out.print(" { ");
for (int i = 0; i < types.length; i++) {
out.print(types[i].getSimpleName() + " ");
}
out.println("}");
}
private static class CompareStringNames implements Comparator {
@Override
public int compare( String a, String b ) {
if (a.length() < b.length()) {
return -1;
} else if (a.length() > b.length()) {
return 1;
} else {
return a.compareTo(b);
}
}
}
public static String toString( Reader r ) {
char[] buff = new char[1024];
StringBuilder string = new StringBuilder();
try {
while (true) {
int size = r.read(buff);
if (size < 0)
break;
string.append(buff, 0, size);
}
return string.toString();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public static int countNotZero( int[] a, int size ) {
int ret = 0;
for (int i = 0; i < size; i++) {
if (a[i] != 0)
ret++;
}
return ret;
}
public static double[] convertTo_F64( int[] a ) {
double[] ret = new double[a.length];
for (int i = 0; i < a.length; i++) {
ret[i] = a[i];
}
return ret;
}
public static float[] convertTo_F32( double[] a, float[] ret ) {
if (ret == null)
ret = new float[a.length];
for (int i = 0; i < a.length; i++) {
ret[i] = (float)a[i];
}
return ret;
}
public static int[] convertTo_I32( double[] a, int[] ret ) {
if (ret == null)
ret = new int[a.length];
for (int i = 0; i < a.length; i++) {
ret[i] = (int)a[i];
}
return ret;
}
/**
* Bounds the provided rectangle to be inside the image.
*
* @param b An image.
* @param r Rectangle
*/
public static void boundRectangleInside( ImageBase b, ImageRectangle r ) {
if (r.x0 < 0)
r.x0 = 0;
if (r.x1 > b.width)
r.x1 = b.width;
if (r.y0 < 0)
r.y0 = 0;
if (r.y1 > b.height)
r.y1 = b.height;
}
public static double min( double a, double b, double c ) {
return Math.min(Math.min(a, b), c);
}
public static float min( float a, float b, float c ) {
return Math.min(Math.min(a, b), c);
}
public static int min( int a, int b, int c ) {
return Math.min(Math.min(a, b), c);
}
public static boolean isInside( ImageBase b, ImageRectangle r ) {
if (r.x0 < 0)
return false;
if (r.x1 > b.width)
return false;
if (r.y0 < 0)
return false;
return r.y1 <= b.height;
}
/**
* Returns true if the point is contained inside the image and 'radius' away from the image border.
*
* @param b Image
* @param x x-coordinate of point
* @param y y-coordinate of point
* @param radius How many pixels away from the border it needs to be to be considered inside
* @return true if the point is inside and false if it is outside
*/
public static boolean isInside( ImageBase b, int x, int y, int radius ) {
if (x - radius < 0)
return false;
if (x + radius >= b.width)
return false;
if (y - radius < 0)
return false;
return y + radius < b.height;
}
/**
* Returns true if the point is contained inside the image and 'radius' away from the image border.
*
* @param b Image
* @param x x-coordinate of point
* @param y y-coordinate of point
* @param radius How many pixels away from the border it needs to be to be considered inside
* @return true if the point is inside and false if it is outside
*/
public static boolean isInside( ImageBase b, float x, float y, float radius ) {
if (x - radius < 0)
return false;
if (x + radius > b.width - 1)
return false;
if (y - radius < 0)
return false;
return !(y + radius > b.height - 1);
}
/**
* Returns true if the point is contained inside the image and 'radius' away from the image border.
*
* @param b Image
* @param x x-coordinate of point
* @param y y-coordinate of point
* @param radius How many pixels away from the border it needs to be to be considered inside
* @return true if the point is inside and false if it is outside
*/
public static boolean isInside( ImageBase b, double x, double y, double radius ) {
if (x - radius < 0)
return false;
if (x + radius > b.width - 1)
return false;
if (y - radius < 0)
return false;
return !(y + radius > b.height - 1);
}
public static boolean isInside( ImageBase b, int x, int y, int radiusWidth, int radiusHeight ) {
if (x - radiusWidth < 0)
return false;
if (x + radiusWidth >= b.width)
return false;
if (y - radiusHeight < 0)
return false;
return y + radiusHeight < b.height;
}
public static boolean isInside( ImageBase b, int c_x, int c_y, int radius, double theta ) {
int r = radius;
float c = (float)Math.cos(theta);
float s = (float)Math.sin(theta);
// make sure the region is inside the image
if (!checkInBounds(b, c_x, c_y, -r, -r, c, s))
return false;
else if (!checkInBounds(b, c_x, c_y, -r, r, c, s))
return false;
else if (!checkInBounds(b, c_x, c_y, r, r, c, s))
return false;
else return checkInBounds(b, c_x, c_y, r, -r, c, s);
}
private static boolean checkInBounds( ImageBase b, int c_x, int c_y, int dx, int dy, float c, float s ) {
float x = c_x + c*dx - s*dy;
float y = c_y + s*dx + c*dy;
return b.isInBounds((int)x, (int)y);
}
public static boolean isInside( ImageBase b, float x, float y ) {
return x >= 0 && x < b.width && y >= 0 && y < b.height;
}
public static boolean isInside( ImageBase b, double x, double y ) {
return x >= 0 && x < b.width && y >= 0 && y < b.height;
}
public static boolean isInside( int width, int height, float x, float y ) {
return x >= 0 && x < width && y >= 0 && y < height;
}
public static boolean isInside( int width, int height, double x, double y ) {
return x >= 0 && x < width && y >= 0 && y < height;
}
/**
* Invokes wait until the elapsed time has passed. In the thread is interrupted, the interrupt is ignored.
*
* @param milli Length of desired pause in milliseconds.
*/
@SuppressWarnings({"EmptyCatch"})
public static void pause( long milli ) {
final Thread t = Thread.currentThread();
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < milli) {
synchronized (t) {
try {
long target = milli - (System.currentTimeMillis() - start);
if (target > 0)
t.wait(target);
} catch (InterruptedException ignore) {
}
}
}
}
public static void print( ImageGray a ) {
if (a.getDataType().isInteger()) {
print((GrayI)a);
} else if (a instanceof GrayF32) {
print((GrayF32)a);
} else {
print((GrayF64)a);
}
}
public static void print( GrayF64 a ) {
for (int y = 0; y < a.height; y++) {
for (int x = 0; x < a.width; x++) {
System.out.printf("%6.2f ", a.get(x, y));
}
System.out.println();
}
System.out.println();
}
public static void print( GrayF32 a ) {
for (int y = 0; y < a.height; y++) {
for (int x = 0; x < a.width; x++) {
System.out.printf("%6.2f ", a.get(x, y));
}
System.out.println();
}
System.out.println();
}
public static void print( InterleavedF32 a ) {
for (int y = 0; y < a.height; y++) {
for (int x = 0; x < a.width; x++) {
System.out.print("|");
for (int band = 0; band < a.numBands; band++) {
System.out.printf(" %6.2f", a.getBand(x, y, band));
}
System.out.print(" |");
}
System.out.println();
}
System.out.println();
}
public static void print( GrayI a ) {
for (int y = 0; y < a.height; y++) {
for (int x = 0; x < a.width; x++) {
System.out.printf("%4d ", a.get(x, y));
}
System.out.println();
}
System.out.println();
}
public static int[] convertArray( double[] input, int[] output ) {
if (output == null)
output = new int[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = (int)input[i];
}
return output;
}
public static long[] convertArray( double[] input, long[] output ) {
if (output == null)
output = new long[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = (long)input[i];
}
return output;
}
public static float[] convertArray( double[] input, float[] output ) {
if (output == null)
output = new float[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = (float)input[i];
}
return output;
}
public static double[] convertArray( float[] input, double[] output ) {
if (output == null)
output = new double[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = input[i];
}
return output;
}
public static int[] convertArray( float[] input, int[] output ) {
if (output == null)
output = new int[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = (int)input[i];
}
return output;
}
public static float[] convertArray( int[] input, float[] output ) {
if (output == null)
output = new float[input.length];
for (int i = 0; i < input.length; i++) {
output[i] = input[i];
}
return output;
}
public static void sleep( long milli ) {
try {
Thread.sleep(milli);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void checkTrue( boolean result ) {
checkTrue(result, "Assert failed.");
}
public static void checkTrue( boolean result, String message ) {
if (!result)
throw new BoofCheckFailure(message);
}
public static void checkEq( int valA, int valB ) {
checkEq(valA, valB, "not equals");
}
public static void checkEq( int valA, int valB, String message ) {
if (valA != valB)
throw new BoofCheckFailure(valA + " != " + valB + " " + message);
}
public static void checkSame( Object a, Object b ) {
checkSame(a, b, "");
}
public static void checkSame( Object a, Object b, String message ) {
if (a == b)
return;
throw new BoofCheckFailure("Objects not the same instance. " + message);
}
/**
* Checks to see if the passed in value is a fraction from 0 to 1.0, inclusive
*/
public static void checkFraction( double fraction, String message ) {
if (fraction < 0.0 || fraction > 1.0)
throw new BoofCheckFailure("Fraction out of range. " + fraction + " " + message);
}
public static void forIdx( List list, BoofLambdas.ProcessIndex func ) {
for (int i = 0; i < list.size(); i++) {
func.process(i, list.get(i));
}
}
/**
* Searches the list for the first index where the operation returns true. When a match is found it returns
* the index. Otherwise it returns -1 if no match is found.
*/
public static int indexOf( List list, BoofLambdas.Filter op ) {
for (int i = 0; i < list.size(); i++) {
if (op.keep(list.get(i))) {
return i;
}
}
return -1;
}
/**
* Extracts elements from a list and returns a list
*/
public static List collectList( List list, BoofLambdas.Extract func ) {
List out = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
In input = list.get(i);
out.add(func.process(input));
}
return out;
}
/**
* Returns a random number from min to max, inclusive.
*/
public static double uniform( double min, double max, Random rand ) {
return rand.nextDouble()*(max - min) + min;
}
/**
* Returns a random number from min to max, inclusive.
*/
public static float uniform( float min, float max, Random rand ) {
return rand.nextFloat()*(max - min) + min;
}
/** Returns the last element in the list. Does not check if the list is empty */
public static T tail( List list ) {
return list.get(list.size() - 1);
}
/** Returns and removes the last element in the list. Does not check if the list is empty */
public static T removeTail( List list ) {
return list.remove(list.size() - 1);
}
/** Safe way to convert an object to string which checks to see if object is null */
public static String toString( T o, BoofLambdas.ToString op ) {
if (o == null)
return "Null";
return op.process(o);
}
/**
* Finds the row at the specified column with the maximum absolute value
*
* @param A (input) matrix
* @param column column to inspect
* @return The row index
*/
public static int columnMaxAbsRow( DMatrixRMaj A, int column ) {
int selected = -1;
double largestValue = -1;
for (int row = 0; row < A.numRows; row++) {
double v = Math.abs(A.unsafe_get(row, column));
if (v > largestValue) {
largestValue = v;
selected = row;
}
}
return selected;
}
public static List createListFilled( int total, BoofLambdas.Factory factory ) {
List out = new ArrayList<>();
for (int i = 0; i < total; i++) {
out.add(factory.newInstance());
}
return out;
}
public static V getOrThrow( Map map, Object key ) throws IOException {
V value = (V)map.get(key);
if (value == null)
throw new IOException("Key not found in map. key=" + key);
return value;
}
/**
* Checks to see if the list contains duplicate items
*/
public static boolean containsDuplicates( List list ) {
Set set = new HashSet<>();
for (int i = 0; i < list.size(); i++) {
T o = list.get(i);
if (!set.add(o))
return true;
}
return false;
}
public static boolean[] checkDeclare( @Nullable DogArray_B queue, int length, boolean zero ) {
if (queue == null)
queue = new DogArray_B(length);
queue.resize(length);
if (zero)
queue.fill(false);
return queue.data;
}
public static byte[] checkDeclare( @Nullable DogArray_I8 queue, int length, boolean zero ) {
if (queue == null)
queue = new DogArray_I8(length);
queue.resize(length);
if (zero)
queue.fill((byte)0);
return queue.data;
}
public static int[] checkDeclare( @Nullable DogArray_I32 queue, int length, boolean zero ) {
if (queue == null)
queue = new DogArray_I32(length);
queue.resize(length);
if (zero)
queue.fill(0);
return queue.data;
}
public static float[] checkDeclare( @Nullable DogArray_F32 queue, int length, boolean zero ) {
if (queue == null)
queue = new DogArray_F32(length);
queue.resize(length);
if (zero)
queue.fill(0.0f);
return queue.data;
}
public static double[] checkDeclare( @Nullable DogArray_F64 queue, int length, boolean zero ) {
if (queue == null)
queue = new DogArray_F64(length);
queue.resize(length);
if (zero)
queue.fill(0.0);
return queue.data;
}
public static GrowArray checkDeclare( @Nullable GrowArray growable,
ConcurrencyOps.NewInstance factory ) {
growable = growable == null ? new GrowArray<>(factory) : growable;
growable.reset();
return growable;
}
/**
* Calculates the similarity (a number within 0 and 1) between two strings. This is case insensitive.
*
* Taken from stack overflow, which was taken from some place else.
*/
public static double similarity( String s1, String s2 ) {
String longer = s1, shorter = s2;
if (s1.length() < s2.length()) { // longer should always have greater length
longer = s2;
shorter = s1;
}
int longerLength = longer.length();
if (longerLength == 0) {
return 1.0; /* both strings are zero length */
}
return (longerLength - editDistance(longer, shorter))/(double)longerLength;
}
// Example implementation of the Levenshtein Edit Distance
// See http://rosettacode.org/wiki/Levenshtein_distance#Java
public static int editDistance( String s1, String s2 ) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
int[] costs = new int[s2.length() + 1];
for (int i = 0; i <= s1.length(); i++) {
int lastValue = i;
for (int j = 0; j <= s2.length(); j++) {
if (i == 0)
costs[j] = j;
else {
if (j > 0) {
int newValue = costs[j - 1];
if (s1.charAt(i - 1) != s2.charAt(j - 1))
newValue = Math.min(Math.min(newValue, lastValue),
costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
}
if (i > 0)
costs[s2.length()] = lastValue;
}
return costs[s2.length()];
}
/**
* Creates a copy of the passed in {@link Configuration}
*/
public static C copyConfig( C src ) {
try {
Class type = (Class)src.getClass();
C dst = type.getConstructor().newInstance();
type.getMethod("setTo", type).invoke(dst, src);
return dst;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Function which handles boilerplate for support recursive verbose print
*/
public static void verboseChildren( @Nullable PrintStream out, @Nullable Set configuration,
VerbosePrint... children ) {
// See how many tabs have already been added
int numIndents = 0;
PrintStream originalOut = out;
if (out instanceof PrintStreamInjectIndent) {
numIndents = ((PrintStreamInjectIndent)out).getIndentCount();
// This will keep the tabs, but remove previous modifications
originalOut = ((PrintStreamInjectIndent)out).getOriginalStream();
}
// If not cursive then do nothing
if (configuration == null || !configuration.contains(BoofVerbose.RECURSIVE)) {
return;
}
// If the output is null then its turning off print
if (out == null) {
for (int i = 0; i < children.length; i++) {
children[i].setVerbose(null, configuration);
}
return;
}
// Add tabs to children when in verbose mode
numIndents += 1;
for (int i = 0; i < children.length; i++) {
PrintStream tabbed = addPrefix(children[i], numIndents, originalOut);
children[i].setVerbose(tabbed, configuration);
}
}
public static String toStringLine( List list ) {
String out = "{ ";
for (int i = 0; i < list.size(); i++) {
out += "'" + list.get(i) + "' ";
}
return out + "}";
}
public static PrintStream addPrefix( VerbosePrint owner, PrintStream out ) {
return addPrefix(owner, 1, out);
}
public static PrintStream addPrefix( VerbosePrint owner, int numIndents, PrintStream out ) {
if (out == null || out instanceof PrintStreamInjectIndent)
return out;
String simpleName = owner.getClass().getSimpleName();
String pre = nameToShort(simpleName, VERBOSE_PREFIX_LENGTH);
if (VERBOSE_PRINT_TABLE)
out.println("Verbose: " + pre + " " + simpleName);
return new PrintStreamInjectIndent(pre, numIndents, out);
}
/**
* Assumes names are camel case and that the capital letters are important. Same for numbers
*/
public static String nameToShort( String name, int length ) {
String text = "";
for (int i = 0; i < name.length() && text.length() < length; i++) {
char c = name.charAt(i);
if (Character.isUpperCase(c) || Character.isDigit(c)) {
text += c;
}
}
if (text.length() < length) {
// Fill in unused characters with a dash. Makes it visually easier to see spacing between indents.
for (int i = text.length(); i < length; i++) {
text += "-";
}
}
return text;
}
public static Set hashSet( T... values ) {
HashSet ret = new HashSet<>();
for (int i = 0; i < values.length; i++) {
ret.add(values[i]);
}
return ret;
}
}