在我正在开发的Android应用程序中(使用OpenCV4Android)我有一个矩阵(Mat
对象),它包含整数值,另一个行矩阵是查找表。我需要创建一个第一个大小的新矩阵,其中每个值都用相应的查找表值替换(即newMat(x,y) = lookupTable(oldMat(x,y))
)。
对于初学者,我知道有一个Core.LUT()
函数,但它在这里没有用,因为我不一定使用CvType.CV_8U
类型Mat
,查找表可能大于256个值。我将主要使用单通道浮动(CvType.CV_32FC1
)。
我提出了这个解决方案:
// init matrices
Mat oldMat = initOldMat(); // contains values from 0 to k-1
Mat newMat = new Mat(oldMat.size(), oldMat.type());
Mat LUT = initLUT(); // a row matrix with k columns
// copying data from matrices to arrays
float[] oldMatArr = new float[(int)oldMat.total()];
oldMat.put(0,0,oldMarArr);
float[] lutArr= new float[(int)LUT.total()];
oldMat.put(0,0,lutArr);
// initialize array for the new matrix
float[] newMatArr = new float[oldMatArr.length];
// applying the LUT - see function below
applyLUTonData(oldMatArr, lutArr, newMatArr);
// copy the data to the new matrix
newMat.put(0, 0, newMatArr);
private void applyLUTonData(float[] inputData, float[] lut, float[] outputData) {
if (inputData.length != outputData.length) {
Log.e(TAG, "applyLUTonData: inputData.length != outputData.length", new IllegalArgumentException("inputData.length != outputData.length"));
}
if (Floats.min(inputData) < 0 || Floats.max(inputData) > lut.length) {
Log.e(TAG, "applyLUTonData: Invalid values in inputData", new IllegalArgumentException("Invalid values in inputData"));
}
for (int i = 0; i < inputData.length; i++) {
if (inputData[i] != Math.round(inputData[i])) { // not an int
Log.e(TAG, "applyLUTonData: inputData contains non-integers", new IllegalArgumentException("inputData contains non-integers"));
}
outputData[i] = lut[(int) inputData[i]];
}
}
注意:我知道inputData
包含浮点数有点奇怪。当然我可以将它转换为某种整数类型矩阵/数组,但我仍然无法使用Core.LUT
,因为我的LUT
可能包含非整数值。
它正常工作,非常好但效率非常低 - 此函数在嵌套for循环中调用,最多3*k
次(k
是LUT大小),这需要很多时间。所以,我正在寻找一种有效的方法来实现相同的功能。它可以使用Java或OpenCV解决方案(包括Guave等库) - 无论哪种方法都有效。
答案 0 :(得分:0)
我最终找到了一个解决方案 - 不是将Mat
对象转换为数组,而是将它们保存为Mat
,然后将它们传递给函数。我们的想法是将其“切片”为LUT中的值,一次处理每个值。例如 - 对于包含32个不同值的LUT,我将查看输入数据(包含0到31之间的整数),首先替换所有0,然后替换1,依此类推......
这是我的代码:
private static void applyLUTonData(Mat inputData, float[] LUT, Mat outputData, int nBins) {
if (inputData.rows() != outputData.rows() || inputData.cols() != outputData.cols()) {
Log.e(TAG, "applyLUTonData: inputData.size() != outputData.size()", new IllegalArgumentException("inputData.size() != outputData.size()"));
return;
}
if (LUT.length != nBins) {
Log.e(TAG, "applyLUTonData: Invalid length for LUT - " + nBins, new IllegalArgumentException("Invalid length for LUT - " + nBins));
return;
}
Core.MinMaxLocResult res = Core.minMaxLoc(inputData);
if (res.minVal < 0 || res.maxVal >= nBins) {
Log.e(TAG, "applyLUTonData: Invalid inputData values", new IllegalArgumentException("Invalid inputData values"));
return;
}
// here's the magic
Mat cmpMat = new Mat();
for (int i = 0; i < nBins; i++) {
Core.compare(inputData, new Scalar(i), cmpMat, Core.CMP_EQ);
outputData.setTo(new Scalar(LUT[i]), cmpMat);
}
cmpMat.release();
}
复杂性说,对于n像素图像,我的旧版本需要O(n)。具有大小为k的LUT的这个版本需要O(k),这对于通常情况k(&lt;&lt; Ñ