c++ - 使用opencv4将鱼眼图像转换为等距矩形图像
问题描述
我想使用 C++ 算法和 OpenCV4 将单个圆形鱼眼图像转换为 equirectangular 图像。
我正在使用此博客中描述的方法:http: //paulbourke.net/dome/dualfish2sphere/
我正在使用 Xcode 开发 MacOSX,我使用终端“ITerm2”来构建和执行我的代码。
代码如下:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
const double PI = 3.141592653589793;
const string PATH_IMAGE = "/Users/Kenza/Desktop/Xcode_cpp_opencv/PaulBourke2/PaulBourke2/Images/img1.jpg";
const int ESC = 27;
Point2f findCorrespondingFisheyePoint(int Xe, int Ye, double He, double We, double Hf, double Wf, double FOV){
Point2f fisheyePoint;
double Xfn, Yfn; //Normalized Cartesian Coordinates
double longitude, latitude, Px, Py, Pz; //Spherical Coordinates
double r, theta; //Polar coordinates
double Xpn, Ypn; //Normalized Polar coordinates
//Normalize Coordinates
Xfn = ( ( 2.0 * (double)Xe ) - We) / Wf;//Between -1 and 1
Yfn = ( ( 2.0 * (double)Ye ) - He) / Hf;//Between -1 and 1
//Normalize Coordinates to Spherical Coordinates
longitude = Xfn*PI; //Between -PI and PI (2*PI interval)
latitude = Yfn*(PI/2.0); //Between -PI/2 and PI/2 (PI interval)
Px = cos(latitude)*cos(longitude);
Py = cos(latitude)*sin(longitude);
Pz = sin(latitude);
//Spherical Coordinates to Polar Coordinates
r = 2.0 * atan2(sqrt(pow(Px,2)+pow(Pz,2)),Py)/FOV;
theta = atan2(Pz,-Px);
Xpn = r * cos(theta);
Ypn = r * sin(theta);
//Normalize Coordinates to CartesianImage Coordinates
fisheyePoint.x = (int)(((Xpn+1.0)*Wf)/2.0);
fisheyePoint.y = (int)(((Ypn+1.0)*Hf)/2.0);
return fisheyePoint;
}
int main(int argc, char** argv){
Mat fisheyeImage, equirectangularImage;
fisheyeImage = imread(PATH_IMAGE, CV_32FC1);
namedWindow("Fisheye Image", WINDOW_AUTOSIZE);
imshow("Fisheye Image", fisheyeImage);
while(waitKey(0) != ESC) {
//wait until the key ESC is pressed
}
//destroyWindow("Fisheye Image");
int Hf, Wf; //Height, width and FOV for the input image (=fisheyeImage)
double FOV;
int He, We; //Height and width for the outpout image (=EquirectangularImage)
Hf = fisheyeImage.size().height;
Wf = fisheyeImage.size().width;
FOV = PI; //FOV in radian
//We keep the same ratio for the image input and the image output
We = Wf;
He = Hf;
equirectangularImage.create(Hf, Wf, fisheyeImage.type()); //We create the outpout image (=EquirectangularImage)
//For each pixels of the ouput equirectangular Image
for (int Xe = 0; Xe <equirectangularImage.size().width; Xe++){
for (int Ye = 0; Ye <equirectangularImage.size().height; Ye++){
equirectangularImage.at<Vec3b>(Point(Xe,Ye)) = fisheyeImage.at<Vec3b>(findCorrespondingFisheyePoint(Xe, Ye, He, We, Hf, Wf, FOV)); //We find the corresponding point in the fisheyeImage
}
}
namedWindow("Equirectangular Image", WINDOW_AUTOSIZE);
imshow("Equirectangular Image",equirectangularImage);
while(waitKey(0) != ESC) {
//wait until the key ESC is pressed
}
destroyWindow("Fisheye Image");
imwrite("equirectangularImage.jpg", equirectangularImage);
return 0;
}
解决方案
使用此代码,我得到预期的结果:
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
const string PATH_IMAGE = "/Users/Kenza/Desktop/Xcode_cpp_opencv/Sos/Sos/Images/img1.jpg";
const int ESC = 27;
Point2f findCorrespondingFisheyePoint(int Xe, int Ye, int We, int He, float FOV){
Point2f fisheyePoint;
float theta, phi, r;
Point3f sphericalPoint;
theta = CV_PI * (Xe / ( (float) We ) - 0.5);
phi = CV_PI * (Ye / ( (float) He ) - 0.5);
sphericalPoint.x = cos(phi) * sin(theta);
sphericalPoint.y = cos(phi) * cos(theta);
sphericalPoint.z = sin(phi);
theta = atan2(sphericalPoint.z, sphericalPoint.x);
phi = atan2(sqrt(pow(sphericalPoint.x,2) + pow(sphericalPoint.z,2)), sphericalPoint.y);
r = ( (float) We ) * phi / FOV;
fisheyePoint.x = (int) ( 0.5 * ( (float) We ) + r * cos(theta) );
fisheyePoint.y = (int) ( 0.5 * ( (float) He ) + r * sin(theta) );
return fisheyePoint;
}
int main(int argc, char** argv){
Mat fisheyeImage, equirectangularImage;
int Wf, Hf;
float FOV;
int We, He;
fisheyeImage = imread(PATH_IMAGE, IMREAD_COLOR);
namedWindow("Fisheye Image");
imshow("fisheye Image", fisheyeImage);
Wf = fisheyeImage.size().width;
Hf = fisheyeImage.size().height;
FOV = (180 * CV_PI ) / 180;
We = Wf;
He = Hf;
while (waitKey(0) != ESC){
}
equirectangularImage.create(He, We, CV_8UC3);
for (int Xe = 0; Xe < We; Xe++){
for (int Ye = 0; Ye < He; Ye++){
Point2f fisheyePoint = findCorrespondingFisheyePoint(Xe, Ye, We, He, FOV);
if (fisheyePoint.x >= We || fisheyePoint.y >= He)
continue;
if (fisheyePoint.x < 0 || fisheyePoint.y < 0)
continue;
equirectangularImage.at<Vec3b>(Point(Xe, Ye)) = fisheyeImage.at<Vec3b>(fisheyePoint);
}
}
namedWindow("Equirectangular Image");
imshow("Equirectangular Image", equirectangularImage);
while (waitKey(0) != ESC){
}
imwrite("im2.jpg", equirectangularImage);
}
推荐阅读
- python - 使用异常处理进行调试
- ios - 如果某些东西符合 Codable ,它会永远无法被编码或解码吗?
- woocommerce - WooCommerce 3.8 到 5.x 更新,不再接受空属性
- xamarin - 如果没有这样的数据库,如何检查 Xamarin 中是否存在 SQLite 数据库文件并创建一个新的数据库文件?
- html - How to parse addresses from website specifying class in R?
- excel - 如何在excel中每21天增加一次日期
- webpack - 重复使用拆分包
- visual-studio-code - VS Code Insiders - 调试 Notebook Cell
- jquery - 通过下拉列表的'indexof'值获取对象键
- laravel-livewire - 通过 livewire 以自定义数据属性的值作为参数调用函数