/*
* Copyright (C) 2009,2010,2011 Samuel Audet
*
* This file is part of JavaCV.
*
* JavaCV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* JavaCV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JavaCV. If not, see <http://www.gnu.org/licenses/>.
*/
package com.googlecode.javacv;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;
import com.googlecode.javacv.Parallel.Looper;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
/**
*
* @author Samuel Audet
*/
public class JavaCV {
public static final double
SQRT2 = 1.41421356237309504880,
FLT_EPSILON = 1.19209290e-7F,
DBL_EPSILON = 2.2204460492503131e-16;
// this is basically cvGetPerspectiveTransform() using CV_LU instead of
// CV_SVD, because the latter gives inaccurate results...
private static ThreadLocal<CvMat>
A8x8 = CvMat.createThreadLocal(8, 8),
b8x1 = CvMat.createThreadLocal(8, 1),
x8x1 = CvMat.createThreadLocal(8, 1);
public static CvMat getPerspectiveTransform(double[] src, double[] dst, CvMat map_matrix) {
// creating and releasing matrices via NIO here in this function
// can easily become a bottleneck, so we use ThreadLocal references
CvMat A = A8x8.get();
CvMat b = b8x1.get();
CvMat x = x8x1.get();
for(int i = 0; i < 4; ++i ) {
A.put(i*8+0, src[i*2]); A.put((i+4)*8+3, src[i*2]);
A.put(i*8+1, src[i*2+1]); A.put((i+4)*8+4, src[i*2+1]);
A.put(i*8+2, 1); A.put((i+4)*8+5, 1);
A.put(i*8+3, 0); A.put(i*8+4, 0); A.put(i*8+5, 0);
A.put((i+4)*8+0, 0); A.put((i+4)*8+1, 0); A.put((i+4)*8+2, 0);
A.put(i*8+6, -src[i*2] *dst[i*2]);
A.put(i*8+7, -src[i*2+1]*dst[i*2]);
A.put((i+4)*8+6, -src[i*2] *dst[i*2+1]);
A.put((i+4)*8+7, -src[i*2+1]*dst[i*2+1]);
b.put(i, dst[i*2]);
b.put(i+4, dst[i*2+1]);
}
cvSolve(A, b, x, CV_LU);
map_matrix.put(x.get());
map_matrix.put(8, 1);
return map_matrix;
}
public static void perspectiveTransform(double[] src, double[] dst, CvMat map_matrix) {
double[] mat = map_matrix.get();
for (int j = 0; j < src.length; j += 2) {
double x = src[j], y = src[j + 1];
double w = x*mat[6] + y*mat[7] + mat[8];
if (Math.abs(w) > FLT_EPSILON) {
w = 1.0/w;
dst[j] = (x*mat[0] + y*mat[1] + mat[2])*w;
dst[j+1] = (x*mat[3] + y*mat[4] + mat[5])*w;
} else {
dst[j] = dst[j+1] = 0;
}
}
}
private static ThreadLocal<CvMat>
A3x3 = CvMat.createThreadLocal(3, 3), b3x1 = CvMat.createThreadLocal(3, 1);
public static CvMat getPlaneParameters(double[] src, double[] dst,
CvMat invSrcK, CvMat dstK, CvMat R, CvMat t, CvMat n) {
CvMat A = A3x3.get(), b = b3x1.get();
double[] x = new double[6], y = new double[6];
perspectiveTransform(src, x, invSrcK);
cvInvert(dstK, A);
perspectiveTransform(dst, y, A);
for (int i = 0; i < 3; i++) {
A.put(i, 0, (t.get(2)*y[i*2] - t.get(0))*x[i*2 ]);
A.put(i, 1, (t.get(2)*y[i*2] - t.get(0))*x[i*2+1]);
A.put(i, 2, t.get(2)*y[i*2] - t.get(0));
b.put(i, (R.get(2, 0)*x[i*2] + R.get(2, 1)*x[i*2+1] + R.get(2, 2))*y[i*2] -
(R.get(0, 0)*x[i*2] + R.get(0, 1)*x[i*2+1] + R.get(0, 2)));
}
cvSolve(A, b, n, CV_LU);
return n;
}
private static ThreadLocal<CvMat>
n3x1 = CvMat.createThreadLocal(3, 1);
public static CvMat getPerspectiveTransform(double[] src, double[] dst,
CvMat invSrcK, CvMat dstK, CvMat R, CvMat t, CvMat H) {
CvMat n = n3x1.get();
getPlaneParameters(src, dst, invSrcK, dstK, R, t, n);
// H = R - t*n^T
cvGEMM(t, n, -1, R, 1, H, CV_GEMM_B_T);
// H = dstK * H * srcK^-1
cvMatMul(dstK, H, H);
cvMatMul(H, invSrcK, H);
return H;
}
private static ThreadLocal<CvMat>
H3x3 = CvMat.createThreadLocal(3, 3);
public static void perspectiveTransform(double[] src, double[] dst,
CvMat invSrcK, CvMat dstK, CvMat R, CvMat t, CvMat n, boolean invert) {
CvMat H = H3x3.get();
// H = R - t*n^T
cvGEMM(t, n, -1, R, 1, H, CV_GEMM_B_T);
// H = dstK * H * srcK^-1
cvMatMul(dstK, H, H);
cvMatMul(H, invSrcK, H);
if (invert) {
cvInvert(H, H);
}
perspectiveTransform(src, dst, H);
}
// Algorithms for Plane-Based Pose Estimation, Peter Sturm
// This assumes plane parameters n == z axis.
private static ThreadLocal<CvMat>
M3x2 = CvMat.createThreadLocal(3, 2), S2x2 = CvMat.createThreadLocal(2, 2),
U3x2 = CvMat.createThreadLocal(3, 2), V2x2 = CvMat.createThreadLocal(2, 2);
public static void HtoRt(CvMat H, CvMat R, CvMat t) {
CvMat M = M3x2.get(), S = S2x2.get(),
U = U3x2.get(), V = V2x2.get();
M.put(H.get(0), H.get(1),
H.get(3), H.get(4),
H.get(6), H.get(7));
cvSVD(M, S, U, V, CV_SVD_V_T);
double lambda = S.get(3);
t.put(H.get(2)/lambda, H.get(5)/lambda, H.get(8)/lambda);
cvMatMul(U, V, M);
R.put(M.get(0), M.get(1), M.get(2)*M.get(5) - M.get(3)*M.get(4),
M.get(2), M.get(3), M.get(1)*M.get(4) - M.get(0)*M.get(5),
M.get(4), M.get(5), M.get(0)*M.get(3) - M.get(1)*M.get(2));
}
private static ThreadLocal<CvMat>
R13x3 = CvMat.createThreadLocal(3, 3), R23x3 = CvMat.createThreadLocal(3, 3),
t13x1 = CvMat.createThreadLocal(3, 1), t23x1 = CvMat.createThreadLocal(3, 1),
n13x1 = CvMat.createThreadLocal(3, 1), n23x1 = CvMat.createThreadLocal(3, 1),
H13x3 = CvMat.createThreadLocal(3, 3), H23x3 = CvMat.createThreadLocal(3, 3);
public static double HnToRt(CvMat H, CvMat n, CvMat R, CvMat t) {
CvMat S = S3x3.get(), U = U3x3.get(), V = V3x3.get();
cvSVD(H, S, U, V, 0);
CvMat R1 = R13x3.get(), R2 = R23x3.get(),
t1 = t13x1.get(), t2 = t23x1.get(),
n1 = n13x1.get(), n2 = n23x1.get(),
H1 = H13x3.get(), H2 = H23x3.get();
double zeta = homogToRt(S, U, V, R1, t1, n1, R2, t2, n2);
// H = (R^-1 * H)/s2
cvGEMM(R1, H, 1/S.get(4), null, 0, H1, CV_GEMM_A_T);
cvGEMM(R2, H, 1/S.get(4), null, 0, H2, CV_GEMM_A_T);
// H = H - I
H1.put(0, H1.get(0)-1); H1.put(4, H1.get(4)-1); H1.put(8, H1.get(8)-1);
H2.put(0, H2.get(0)-1); H2.put(4, H2.get(4)-1); H2.put(8, H2.get(8)-1);
// Now H should ~= -tn^T, so extract "average" t
double d = Math.abs (n.get(0)) + Math.abs (n.get(1)) + Math.abs (n.get(2));
double s[] = { -Math.signum(n.get(0)), -Math.signum(n.get(1)), -Math.signum(n.get(2)) };
t1.put(0.0, 0.0, 0.0);
t2.put(0.0, 0.0, 0.0);
for (int i = 0; i < 3; i++) {
t1.put(0, t1.get(0) + s[i]*H1.get(i) /d);
t1.put(1, t1.get(1) + s[i]*H1.get(i+3)/d);
t1.put(2, t1.get(2) + s[i]*H1.get(i+6)/d);
t2.put(0, t2.get(0) + s[i]*H2.get(i) /d);
t2.put(1, t2.get(1) + s[i]*H2.get(i+3)/d);
t2.put(2, t2.get(2) + s[i]*H2.get(i+6)/d);
}
// H = H + tn^T
cvGEMM(t1, n, 1, H1, 1, H1, CV_GEMM_B_T);
cvGEMM(t2, n, 1, H2, 1, H2, CV_GEMM_B_T);
// take what's left as the error of the model,
// this either indicates inaccurate camera matrix K or normal vector n
double err1 = cvNorm(H1);
double err2 = cvNorm(H2);
double err;
if (err1 < err2) {
if (R != null) {
R.put(R1);
}
if (t != null) {
t.put(t1);
}
err = err1;
} else {
if (R != null) {
R.put(R2);
}
if (t != null) {
t.put(t2);
}
err = err2;
}
return err;
}
// Ported to Java/OpenCV from
// Bill Triggs. Autocalibration from Planar Scenes. In 5th European Conference
// on Computer Vision (ECCV ’98), volume I, pages 89–105. Springer-Verlag, 1998.
private static ThreadLocal<CvMat>
S3x3 = CvMat.createThreadLocal(3, 3),
U3x3 = CvMat.createThreadLocal(3, 3),
V3x3 = CvMat.createThreadLocal(3, 3);
public static double homogToRt(CvMat H,
CvMat R1, CvMat t1, CvMat n1,
CvMat R2, CvMat t2, CvMat n2) {
CvMat S = S3x3.get(), U = U3x3.get(), V = V3x3.get();
cvSVD(H, S, U, V, 0);
double zeta = homogToRt(S, U, V, R1, t1, n1, R2, t2, n2);
return zeta;
}
public static double homogToRt(CvMat S, CvMat U, CvMat V,
CvMat R1, CvMat t1, CvMat n1,
CvMat R2, CvMat t2, CvMat n2) {
double s1 = S.get(0)/S.get(4);
double s3 = S.get(8)/S.get(4);
double zeta = s1-s3;
double a1 = Math.sqrt(1 - s3*s3);
double b1 = Math.sqrt(s1*s1 - 1);
double[] ab = unitize(a1, b1);
double[] cd = unitize(1+s1*s3, a1*b1);
double[] ef = unitize(-ab[1]/s1, -ab[0]/s3);
R1.put(cd[0],0,cd[1], 0,1,0, -cd[1],0,cd[0]);
cvGEMM(U , R1, 1, null, 0, R1, 0);
cvGEMM(R1, V, 1, null, 0, R1, CV_GEMM_B_T);
R2.put(cd[0],0,-cd[1], 0,1,0, cd[1],0,cd[0]);
cvGEMM(U , R2, 1, null, 0, R2, 0);
cvGEMM(R2, V, 1, null, 0, R2, CV_GEMM_B_T);
double[] v1 = { V.get(0), V.get(3), V.get(6) };
double[] v3 = { V.get(2), V.get(5), V.get(8) };
double sign1 = 1, sign2 = 1;
for (int i = 2; i >= 0; i--) {
n1.put(i, sign1*(ab[1]*v1[i] - ab[0]*v3[i]));
n2.put(i, sign2*(ab[1]*v1[i] + ab[0]*v3[i]));
t1.put(i, sign1*(ef[0]*v1[i] + ef[1]*v3[i]));
t2.put(i, sign2*(ef[0]*v1[i] - ef[1]*v3[i]));
if (i == 2) {
if (n1.get(2) < 0) {
n1.put(2, -n1.get(2));
t1.put(2, -t1.get(2));
sign1 = -1;
}
if (n2.get(2) < 0) {
n2.put(2, -n2.get(2));
t2.put(2, -t2.get(2));
sign2 = -1;
}
}
}
return zeta;
}
public static double[] unitize(double a, double b) {
double norm = Math.sqrt(a*a + b*b);
if (norm > FLT_EPSILON) {
a = a / norm;
b = b / norm;
}
return new double[] { a, b };
}
public static void adaptiveBinarization(final IplImage src, final IplImage sumimage,
final IplImage sqsumimage, final IplImage dst, final boolean invert,
final int minwindow, final int maxwindow, final double varmultiplier, final double k) {
final int w = src.width();
final int h = src.height();
final int srcdepth = src.depth();
// final IplImage graysrc;
// if (src.nChannels() > 1) {
// cvCvtColor(src, dst, CV_BGR2GRAY);
// graysrc = dst;
// } else {
// graysrc = src;
// }
// compute integral images
cvIntegral(src, sumimage, sqsumimage, null);
final DoubleBuffer sumbuf = sumimage.getByteBuffer().asDoubleBuffer();
final DoubleBuffer sqsumbuf = sqsumimage.getByteBuffer().asDoubleBuffer();
final int sumstep = sumimage.widthStep();
final int sqsumstep = sqsumimage.widthStep();
final ByteBuffer srcbuf = src.getByteBuffer();
final ByteBuffer dstbuf = dst.getByteBuffer();
final int srcstep = src.widthStep();
final int dststep = dst.widthStep();
// try to detect a reasonable maximum and minimum intensity
// for thresholds instead of simply 0 and 255...
double totalmean = sumbuf.get((h-1)*sumstep/8 + (w-1)) -
sumbuf.get((h-1)*sumstep/8) -
sumbuf.get(w-1) + sumbuf.get(0);
totalmean /= w*h;
double totalsqmean = sqsumbuf.get((h-1)*sqsumstep/8 + (w-1)) -
sqsumbuf.get((h-1)*sqsumstep/8) -
sqsumbuf.get(w-1) + sqsumbuf.get(0);
totalsqmean /= w*h;
double totalvar = totalsqmean - totalmean*totalmean;
//double totaldev = Math.sqrt(totalvar);
//System.out.println(totaldev);
final double targetvar = totalvar*varmultiplier;
//for (int y = 0; y < h; y++) {
Parallel.loop(0, h, new Looper() {
public void loop(int from, int to, int looperID) {
for (int y = from; y < to; y++) {
for (int x = 0; x < w; x++) {
double var = 0, mean = 0, sqmean = 0;
int upperlimit = maxwindow;
int lowerlimit = minwindow;
int window = upperlimit; // start with maxwindow
while (upperlimit - lowerlimit > 2) {
int x1 = Math.max(x-window/2, 0);
int x2 = Math.min(x+window/2+1, w);
int y1 = Math.max(y-window/2, 0);
int y2 = Math.min(y+window/2+1, h);
mean = sumbuf.get(y2*sumstep/8 + x2) -
sumbuf.get(y2*sumstep/8 + x1) -
sumbuf.get(y1*sumstep/8 + x2) +
sumbuf.get(y1*sumstep/8 + x1);
mean /= window*window;
sqmean = sqsumbuf.get(y2*sqsumstep/8 + x2) -
sqsumbuf.get(y2*sqsumstep/8 + x1) -
sqsumbuf.get(y1*sqsumstep/8 + x2) +
sqsumbuf.get(y1*sqsumstep/8 + x1);
sqmean /= window*window;
var = sqmean - mean*mean;
// if we're at maximum window size, but variance is
// too low anyway, let's break out immediately
if (window == upperlimit && var < targetvar) {
break;
}
// otherwise, start binary search
if (var > targetvar) {
upperlimit = window;
} else {
lowerlimit = window;
}
window = lowerlimit + (upperlimit-lowerlimit)/2;
window = (window/2)*2 + 1;
}
double value = 0;
if (srcdepth == IPL_DEPTH_8U) {
value = srcbuf.get(y*srcstep + x) & 0xFF;
} else if (srcdepth == IPL_DEPTH_32F) {
value = srcbuf.getFloat(y*srcstep + 4*x);
} else if (srcdepth == IPL_DEPTH_64F) {
value = srcbuf.getDouble(y*srcstep + 8*x);
} else {
//cvIntegral() does not support other image types, so we
//should not be able to get here...
assert(false);
}
if (invert) {
//double threshold = 255 - (255 - mean) * (1 + 0.1*(Math.sqrt(var)/128 - 1));
double threshold = 255 - (255 - mean) * k;
dstbuf.put(y*dststep + x, (value < threshold ? (byte)0xFF : (byte)0x00));
} else {
//double threshold = mean * (1 + k*(Math.sqrt(var)/128 - 1));
double threshold = mean * k;
dstbuf.put(y*dststep + x, (value > threshold ? (byte)0xFF : (byte)0x00));
}
}
}
}});
}
public static void hysteresisThreshold(IplImage srcImage, IplImage dstImage,
double highThresh, double lowThresh, double maxValue) {
int highThreshold = (int)Math.round(highThresh);
int lowThreshold = (int)Math.round(lowThresh);
byte lowValue = 0;
byte medValue = (byte)Math.round(maxValue/2);
byte highValue = (byte)Math.round(maxValue);
int height = srcImage.height();
int width = srcImage.width();
ByteBuffer srcData = srcImage.getByteBuffer();
ByteBuffer dstData = dstImage.getByteBuffer();
int srcStep = srcImage.widthStep();
int dstStep = dstImage.widthStep();
int srcIndex = 0;
int dstIndex = 0;
//
// first pass forward
//
// first line
int i = 0;
int in = srcData.get(srcIndex+i)&0xFF;
if (in >= highThreshold) {
dstData.put(dstIndex+i, highValue);
} else if (in < lowThreshold) {
dstData.put(dstIndex+i, lowValue);
} else {
dstData.put(dstIndex+i, medValue);
}
for (i = 1; i < width-1; i++) {
in = srcData.get(srcIndex+i)&0xFF;
if (in >= highThreshold) {
dstData.put(dstIndex+i, highValue);
} else if (in < lowThreshold) {
dstData.put(dstIndex+i, lowValue);
} else {
byte prev = dstData.get(dstIndex+i-1);
if (prev == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, medValue);
}
}
}
i = width-1;
in = srcData.get(srcIndex+i)&0xFF;
if (in >= highThreshold) {
dstData.put(dstIndex+i, highValue);
} else if (in < lowThreshold) {
dstData.put(dstIndex+i, lowValue);
} else {
byte prev = dstData.get(dstIndex+i-1);
if (prev == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, medValue);
}
}
height--;
// other lines
while (height-- > 0) {
srcIndex += srcStep;
dstIndex += dstStep;
// first column
i = 0;
in = srcData.get(srcIndex+i)&0xFF;
if (in >= highThreshold) {
dstData.put(dstIndex+i, highValue);
} else if (in < lowThreshold) {
dstData.put(dstIndex+i, lowValue);
} else {
byte prev1 = dstData.get(dstIndex+i-dstStep);
byte prev2 = dstData.get(dstIndex+i-dstStep+1);
if (prev1 == highValue || prev2 == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, medValue);
}
}
// other columns
for (i = 1; i < width-1; i++) {
in = srcData.get(srcIndex+i)&0xFF;
if (in >= highThreshold) {
dstData.put(dstIndex+i, highValue);
} else if (in < lowThreshold) {
dstData.put(dstIndex+i, lowValue);
} else {
byte prev1 = dstData.get(dstIndex+i-1);
byte prev2 = dstData.get(dstIndex+i-dstStep-1);
byte prev3 = dstData.get(dstIndex+i-dstStep);
byte prev4 = dstData.get(dstIndex+i-dstStep+1);
if (prev1 == highValue || prev2 == highValue ||
prev3 == highValue || prev4 == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, medValue);
}
}
}
// last column
i = width-1;
in = srcData.get(srcIndex+i)&0xFF;
if (in >= highThreshold) {
dstData.put(dstIndex+i, highValue);
} else if (in < lowThreshold) {
dstData.put(dstIndex+i, lowValue);
} else {
byte prev1 = dstData.get(dstIndex+i-1);
byte prev2 = dstData.get(dstIndex+i-dstStep-1);
byte prev3 = dstData.get(dstIndex+i-dstStep);
if (prev1 == highValue || prev2 == highValue ||
prev3 == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, medValue);
}
}
}
height = srcImage.height();
width = srcImage.width();
dstIndex = (height-1)*dstStep;
//
// second pass backward
//
// first (actually last) line
i = width-1;
if (dstData.get(dstIndex+i) == medValue) {
dstData.put(dstIndex+i, lowValue);
}
for (i = width-2; i > 0 ; i--) {
if (dstData.get(dstIndex+i) == medValue) {
if (dstData.get(dstIndex+i+1) == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, lowValue);
}
}
}
i = 0;
if (dstData.get(dstIndex+i) == medValue) {
if (dstData.get(dstIndex+i+1) == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, lowValue);
}
}
height--;
// other lines
while (height-- > 0) {
dstIndex -= dstStep;
// first column
i = width-1;
if (dstData.get(dstIndex+i) == medValue) {
if (dstData.get(dstIndex+i+dstStep) == highValue ||
dstData.get(dstIndex+i+dstStep-1) == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, lowValue);
}
}
// other columns
for (i = width-2; i > 0 ; i--) {
if (dstData.get(dstIndex+i) == medValue) {
if (dstData.get(dstIndex+i+1) == highValue ||
dstData.get(dstIndex+i+dstStep+1) == highValue ||
dstData.get(dstIndex+i+dstStep) == highValue ||
dstData.get(dstIndex+i+dstStep-1) == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, lowValue);
}
}
}
// last column
i = 0;
if (dstData.get(dstIndex+i) == medValue) {
if (dstData.get(dstIndex+i+1) == highValue ||
dstData.get(dstIndex+i+dstStep+1) == highValue ||
dstData.get(dstIndex+i+dstStep) == highValue) {
dstData.put(dstIndex+i, highValue);
} else {
dstData.put(dstIndex+i, lowValue);
}
}
}
}
// clamps image intensities between min and max...
public static void minMaxS(IplImage src, double min, double max, IplImage dst) {
switch (src.depth()) {
case IPL_DEPTH_8U: {
ByteBuffer sb = src.getByteBuffer();
ByteBuffer db = dst.getByteBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, (byte)Math.max(Math.min(sb.get(i) & 0xFF,max),min));
}
break; }
case IPL_DEPTH_16U: {
ShortBuffer sb = src.getByteBuffer().asShortBuffer();
ShortBuffer db = dst.getByteBuffer().asShortBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, (short)Math.max(Math.min(sb.get(i) & 0xFFFF,max),min));
}
break; }
case IPL_DEPTH_32F: {
FloatBuffer sb = src.getByteBuffer().asFloatBuffer();
FloatBuffer db = dst.getByteBuffer().asFloatBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, (float)Math.max(Math.min(sb.get(i),max),min));
}
break; }
case IPL_DEPTH_8S: {
ByteBuffer sb = src.getByteBuffer();
ByteBuffer db = dst.getByteBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, (byte)Math.max(Math.min(sb.get(i),max),min));
}
break; }
case IPL_DEPTH_16S: {
ShortBuffer sb = src.getByteBuffer().asShortBuffer();
ShortBuffer db = dst.getByteBuffer().asShortBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, (short)Math.max(Math.min(sb.get(i),max),min));
}
break; }
case IPL_DEPTH_32S: {
IntBuffer sb = src.getByteBuffer().asIntBuffer();
IntBuffer db = dst.getByteBuffer().asIntBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, (int)Math.max(Math.min(sb.get(i),max),min));
}
break; }
case IPL_DEPTH_64F: {
DoubleBuffer sb = src.getByteBuffer().asDoubleBuffer();
DoubleBuffer db = dst.getByteBuffer().asDoubleBuffer();
for (int i = 0; i < sb.capacity(); i++) {
db.put(i, Math.max(Math.min(sb.get(i),max),min));
}
break; }
default: assert(false);
}
}
// vector norm
public static double norm(double[] v) {
return norm(v, 2.0);
}
public static double norm(double[] v, double p) {
double norm = 0;
if (p == 1.0) {
for (double e : v) {
norm += Math.abs(e);
}
} else if (p == 2.0) {
for (double e : v) {
norm += e*e;
}
norm = Math.sqrt(norm);
} else if (p == Double.POSITIVE_INFINITY) {
for (double e : v) {
e = Math.abs(e);
if (e > norm) {
norm = e;
}
}
} else if (p == Double.NEGATIVE_INFINITY) {
norm = Double.MAX_VALUE;
for (double e : v) {
e = Math.abs(e);
if (e < norm) {
norm = e;
}
}
} else {
for (double e : v) {
norm += Math.pow(Math.abs(e), p);
}
norm = Math.pow(norm, 1/p);
}
return norm;
}
// induced norm
public static double norm(CvMat A) {
return norm(A, 2.0);
}
public static double norm(CvMat A, double p) {
return norm(A, p, null);
}
public static double norm(CvMat A, double p, CvMat W) {
double norm = -1;
if (p == 1.0) {
int cols = A.cols(), rows = A.rows();
for (int j = 0; j < cols; j++) {
double n = 0;
for (int i = 0; i < rows; i++) {
n += Math.abs(A.get(i, j));
}
norm = Math.max(n, norm);
}
} else if (p == 2.0) {
int size = Math.min(A.rows(), A.cols());
if (W == null || W.rows() != size || W.cols() != 1) {
W = CvMat.create(size, 1);
}
cvSVD(A, W, null, null, 0);
norm = W.get(0); // largest singular value
} else if (p == Double.POSITIVE_INFINITY) {
int rows = A.rows(), cols = A.cols();
for (int i = 0; i < rows; i++) {
double n = 0;
for (int j = 0; j < cols; j++) {
n += Math.abs(A.get(i, j));
}
norm = Math.max(n, norm);
}
} else {
assert(false);
}
return norm;
}
public static double cond(CvMat A) {
return cond(A, 2.0);
}
public static double cond(CvMat A, double p) {
return cond(A, p, null);
}
public static double cond(CvMat A, double p, CvMat W) {
double cond = -1;
if (p == 2.0) {
int size = Math.min(A.rows(), A.cols());
if (W == null || W.rows() != size || W.cols() != 1) {
W = CvMat.create(size, 1);
}
cvSVD(A, W, null, null, 0);
cond = W.get(0)/W.get(W.length()-1); // largest/smallest singular value
} else {
// should put something faster here if we're really serious
// about using something other than the 2-norm
int rows = A.rows(), cols = A.cols();
if (W == null || W.rows() != rows || W.cols() != cols) {
W = CvMat.create(rows, cols);
}
CvMat Ainv = W;
cvInvert(A, Ainv);
cond = norm(A, p)*norm(Ainv, p);
}
return cond;
}
public static double randn(CvRNG state, double sigma) {
return randn(state, cvRealScalar(sigma));
}
private static ThreadLocal<CvMat>
values1x1 = CvMat.createThreadLocal(1, 1);
public static double randn(CvRNG state, CvScalar sigma) {
CvMat values = values1x1.get();
cvRandArr(state, values, CV_RAND_NORMAL, CvScalar.ZERO, sigma);
double res = values.get(0);
return res;
}
public static double median(double[] doubles) {
double[] sorted = doubles.clone();
Arrays.sort(sorted);
if (doubles.length%2 == 0) {
return (sorted[doubles.length/2 - 1] + sorted[doubles.length/2])/2;
} else {
return sorted[doubles.length/2];
}
}
public static <T extends Object> T median(T[] objects) {
T[] sorted = objects.clone();
Arrays.sort(sorted);
return sorted[sorted.length/2];
}
public static void fractalTriangleWave(double[] line, int i, int j, double a) {
fractalTriangleWave(line, i, j, a, -1);
}
public static void fractalTriangleWave(double[] line, int i, int j, double a, int roughness) {
int m = (j-i)/2+i;
if (i == j || i == m) {
return;
}
line[m] = (line[i]+line[j])/2 + a;
if (roughness > 0 && line.length > roughness*(j-i)) {
fractalTriangleWave(line, i, m, 0, roughness);
fractalTriangleWave(line, m, j, 0, roughness);
} else {
fractalTriangleWave(line, i, m, a/SQRT2, roughness);
fractalTriangleWave(line, m, j, -a/SQRT2, roughness);
}
}
public static void fractalTriangleWave(IplImage image, CvMat H) {
fractalTriangleWave(image, H, -1);
}
public static void fractalTriangleWave(IplImage image, CvMat H, int roughness) {
assert (image.depth() == IPL_DEPTH_32F);
double[] line = new double[image.width()];
fractalTriangleWave(line, 0, line.length/2, 1, roughness);
fractalTriangleWave(line, line.length/2, line.length-1, -1, roughness);
double[] minMax = { Double.MAX_VALUE, Double.MIN_VALUE };
int height = image.height();
int width = image.width();
int channels = image.nChannels();
int step = image.widthStep();
int start = 0;
if (image.roi() != null) {
height = image.roi().height();
width = image.roi().width();
start = image.roi().yOffset()*step/4 + image.roi().xOffset()*channels;
}
FloatBuffer fb = image.getFloatBuffer(start);
double[] h = H == null ? null : H.get();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
for (int z = 0; z < channels; z++) {
double sum = 0.0;
if (h == null) {
sum += line[x];
} else {
double x2 = (h[0]*x + h[1]*y + h[2])/(h[6]*x + h[7]*y + h[8]);
while (x2 < 0) {
x2 += line.length;
}
int xi2 = (int)x2;
double xn = x2 - xi2;
sum += line[ xi2 %line.length]*(1-xn) +
line[(xi2+1)%line.length]*xn;
}
minMax[0] = Math.min(minMax[0], sum);
minMax[1] = Math.max(minMax[1], sum);
fb.put(y*step/4 + x*channels + z, (float)sum);
}
}
}
cvConvertScale(image, image, 1/(minMax[1]-minMax[0]),
-minMax[0]/(minMax[1]-minMax[0]));
}
public static void main(String[] args) {
String timestamp = JavaCV.class.getPackage().getImplementationVersion();
if (timestamp == null) {
timestamp = "unknown";
}
System.out.println(
"JavaCV build timestamp " + timestamp + "\n" +
"Copyright (C) 2009,2010,2011 Samuel Audet <samuel.audet@gmail.com>\n" +
"Project site: http://code.google.com/p/javacv/\n\n" +
"Licensed under the GNU General Public License version 2 (GPLv2) with Classpath exception.\n" +
"Please refer to LICENSE.txt or http://www.gnu.org/licenses/ for details.");
System.exit(0);
}
}