/*
* Copyright (C) 2009-2012 Samuel Audet
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, 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
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE.txt file that accompanied this code.
* 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 org.bytedeco.javacv;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import static org.bytedeco.javacpp.opencv_core.*;
/**
*
* @author Samuel Audet
*/
public class cvkernels extends org.bytedeco.javacpp.cvkernels {
private static class ParallelData {
KernelData data = null;
CvRect roi = new CvRect();
}
private static ThreadLocal<ParallelData[]> parallelData = new ThreadLocal<ParallelData[]>() {
@Override protected ParallelData[] initialValue() {
ParallelData[] pd = new ParallelData[Parallel.getNumThreads()];
for (int i = 0; i < pd.length; i++) {
pd[i] = new ParallelData();
}
return pd;
}
};
public static void multiWarpColorTransform(final KernelData data, final CvRect roi, final CvScalar fillColor) {
final int size = (int)data.capacity();
final ParallelData[] pd = parallelData.get();
// Copy all data to completely independent data sets
for (int i = 0; i < pd.length; i++) {
if (pd[i].data == null || pd[i].data.capacity() < size) {
pd[i].data = new KernelData(size);
for (int j = 0; j < size; j++) {
KernelData d = pd[i].data.position(j);
data.position(j);
if (data.dstDstDot() != null) {
d.dstDstDot(ByteBuffer.allocateDirect(data.dstDstDot().capacity()*8).
order(ByteOrder.nativeOrder()).asDoubleBuffer());
}
}
}
for (int j = 0; j < size; j++) {
KernelData d = pd[i].data.position(j);
d.put(data.position(j));
d.dstDstDot(d.dstDstDot()); // reset dstDstDot pointer
}
}
// Transform in parallel on multiple threads
final IplImage img = data.position(0).srcImg();
final int depth = img.depth();
final int x, y, w, h;
if (roi != null) {
x = roi.x(); y = roi.y();
w = roi.width(); h = roi.height();
} else {
x = 0; y = 0;
w = img.width(); h = img.height();
}
Parallel.loop(y, y+h, pd.length, new Parallel.Looper() {
public void loop(int from, int to, int looperID) {
CvRect r = pd[looperID].roi.x(x).y(from).width(w).height(to-from);
if (depth == IPL_DEPTH_32F) {
multiWarpColorTransform32F(pd[looperID].data.position(0), size, r, fillColor);
} else if (depth == IPL_DEPTH_8U) {
multiWarpColorTransform8U(pd[looperID].data.position(0), size, r, fillColor);
} else {
assert false;
}
}});
// Reduce data as required
for (int i = 0; i < size; i++) {
int dstCount = 0;
int dstCountZero = 0;
int dstCountOutlier = 0;
double srcDstDot = 0;
double[] dstDstDot = null;
if (data.dstDstDot() != null) {
dstDstDot = new double[data.dstDstDot().capacity()];
}
for (int j = 0; j < pd.length; j++) {
KernelData d = pd[j].data.position(i);
dstCount += d.dstCount();
dstCountZero += d.dstCountZero();
dstCountOutlier += d.dstCountOutlier();
srcDstDot += d.srcDstDot();
if (dstDstDot != null && d.dstDstDot() != null) {
for (int k = 0; k < dstDstDot.length; k++) {
dstDstDot[k] += d.dstDstDot().get(k);
}
}
}
data.position(i);
data.dstCount(dstCount);
data.dstCountZero(dstCountZero);
data.dstCountOutlier(dstCountOutlier);
data.srcDstDot(srcDstDot);
if (dstDstDot != null && data.dstDstDot() != null) {
data.dstDstDot().position(0);
data.dstDstDot().put(dstDstDot);
}
}
}
}