Android OpenCV undistort 图像从看似相同的 python 实现中产生不同的结果
Android OpenCV undistort image produces different results from a seemingly identical python implementation
我们有一个简单的 python 例程,它拍摄图像并通过调用 cv2.fisheye.undistortImage() 来消除失真。它根据输入图像和提供的相机矩阵产生预期的结果。
我将 python 功能移植到 Android。当输入相同的图像时,Android 版本不会产生相同的结果,我不明白为什么。我在港口遗漏了什么吗?
Python 来源(按预期工作)
cx = 960
cy = 540
val = 600
K = np.array([[ val, 0. , cx],
[ 0. , val , cy],
[ 0. , 0. , 1. ]])
# zero distortion coefficients work well for this image
D = np.array([0., 0., 0., 0.])
# use Knew to scale the output
Knew = K.copy()
Knew[(0,1), (0,1)] = 0.4 * Knew[(0,1), (0,1)]
img = cv2.imread('fisheye_sample.jpg')
img_undistorted = cv2.fisheye.undistortImage(img, K, D=D, Knew=Knew)
cv2.imwrite('fisheye_sample_undistorted.jpg', img_undistorted)
现在,python代码移植到Android如下:
Android端口(未产生预期结果)
float fishVal = 600.0f;
float cX = 960;
float cY = 540;
Mat K = new Mat(3, 3, CvType.CV_32FC1);
K.put(0, 0, new float[]{fishVal, 0, cX});
K.put(1, 0, new float[]{0, fishVal, cY});
K.put(2, 0, new float[]{0, 0, 1});
Mat D = new Mat(1, 4, CvType.CV_32FC1);
D.put(0, 0, new float[]{0, 0, 0, 0});
Mat Knew = K.clone();
Knew.put(0, 0, new float[]{fishVal * 0.4f, 0.0f, cX});
Knew.put(1, 0, new float[]{0.0f, fishVal * 0.4f, cY});
Knew.put(2, 0, new float[]{0.0f, 0.0f, 1.0f});
Mat dst = new Mat(greyScaleMat.rows(), greyScaleMat.cols(), greyScaleMat.type());
Imgproc.undistort(greyScaleMat, dst, K, D, Knew);
给定一个恒定的输入,我希望这两个实现产生相同的输出。这没有发生。 Python 版本做了一些不失真,但 Android 版本似乎忽略了一些输入参数。我没有看到的 Android 端口有问题吗?
输入图像
Python 输出图像(正确!)
下图没有像预期的那样失真
Android 输出图像(不正确!)
当运行通过Android函数如上所述时,没有执行不失真。相反,图像根据 Knew 矩阵按比例缩小。关于如何解释这种差异的任何想法?
经过多方摸索、论坛搜索和源代码调查,我找到了答案。
原来 Imgproc.undistort()
的实现是 而不是 和 cv2.fisheye.UndistortImage()
一样
Java/JNI 世界中的等价物是 Calib3d.undistortImage()
。调用该函数时,输出与 python 版本相同。
必须将 Android 的 OpenCV 升级到高于 3 的版本才能使用此功能。
我们有一个简单的 python 例程,它拍摄图像并通过调用 cv2.fisheye.undistortImage() 来消除失真。它根据输入图像和提供的相机矩阵产生预期的结果。
我将 python 功能移植到 Android。当输入相同的图像时,Android 版本不会产生相同的结果,我不明白为什么。我在港口遗漏了什么吗?
Python 来源(按预期工作)
cx = 960
cy = 540
val = 600
K = np.array([[ val, 0. , cx],
[ 0. , val , cy],
[ 0. , 0. , 1. ]])
# zero distortion coefficients work well for this image
D = np.array([0., 0., 0., 0.])
# use Knew to scale the output
Knew = K.copy()
Knew[(0,1), (0,1)] = 0.4 * Knew[(0,1), (0,1)]
img = cv2.imread('fisheye_sample.jpg')
img_undistorted = cv2.fisheye.undistortImage(img, K, D=D, Knew=Knew)
cv2.imwrite('fisheye_sample_undistorted.jpg', img_undistorted)
现在,python代码移植到Android如下:
Android端口(未产生预期结果)
float fishVal = 600.0f;
float cX = 960;
float cY = 540;
Mat K = new Mat(3, 3, CvType.CV_32FC1);
K.put(0, 0, new float[]{fishVal, 0, cX});
K.put(1, 0, new float[]{0, fishVal, cY});
K.put(2, 0, new float[]{0, 0, 1});
Mat D = new Mat(1, 4, CvType.CV_32FC1);
D.put(0, 0, new float[]{0, 0, 0, 0});
Mat Knew = K.clone();
Knew.put(0, 0, new float[]{fishVal * 0.4f, 0.0f, cX});
Knew.put(1, 0, new float[]{0.0f, fishVal * 0.4f, cY});
Knew.put(2, 0, new float[]{0.0f, 0.0f, 1.0f});
Mat dst = new Mat(greyScaleMat.rows(), greyScaleMat.cols(), greyScaleMat.type());
Imgproc.undistort(greyScaleMat, dst, K, D, Knew);
给定一个恒定的输入,我希望这两个实现产生相同的输出。这没有发生。 Python 版本做了一些不失真,但 Android 版本似乎忽略了一些输入参数。我没有看到的 Android 端口有问题吗?
输入图像
Python 输出图像(正确!)
下图没有像预期的那样失真
经过多方摸索、论坛搜索和源代码调查,我找到了答案。
原来 Imgproc.undistort()
的实现是 而不是 和 cv2.fisheye.UndistortImage()
Java/JNI 世界中的等价物是 Calib3d.undistortImage()
。调用该函数时,输出与 python 版本相同。
必须将 Android 的 OpenCV 升级到高于 3 的版本才能使用此功能。