第一行是提取有效区域后的鱼眼图;第二行就是展开图(第二张和第四张根据需要裁剪了一部分)
#include <iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include <opencv2/core/core.hpp>
using namespace std;
using namespace cv;
#define IMAGE_WIDTH 1000
#define IMAGE_HEIGHT 1000
#define mode 0 //mode=0是不需要重新生成映射yml
#define FOV_240 4.188790//FOV是240°
void ExtractFish(vector<cv::Mat>& fishes) {
for (int i = 1; i < 5; i++) {
cv::Mat input = cv::imread("./input/" + to_string(i) + ".png", 1);
cv::Mat mask = cv::imread("./input/Mask" + to_string(i) + ".png", 0);
//cv::Mat mask1 = cv::Mat::zeros(mask.size(), mask.type());
//for (int j = 0; j < mask1.rows; j++) {
// for (int k = 0; k < mask1.cols; k++) {
// if ((float)mask.at<uchar>(j, k) == 0) {
// mask1.at<uchar>(j, k) = (uchar)0.0;
// }
// else {
// mask1.at<uchar>(j, k) = (uchar)255.0;
// }
// //mask1.at<uchar>(j, k) =(uchar)(1.0 - (float)mask.at<uchar>(j, k));
// }
//}
//cv::imwrite("./out/Mask" + to_string(i) + ".png", mask1);
cv::Mat out;
input.copyTo(out, mask);
cv::Mat newbg = cv::Mat::zeros(1000, 1000, CV_8UC3);
if (i == 1) {
resize(out, out, cv::Size(1000, 1000));
cv::Rect rec(0, 0, out.cols, out.rows);
out.copyTo(newbg(rec));
resize(newbg, newbg, cv::Size(1000, 1000));
fishes.emplace_back(newbg);
cv::imwrite("./out/out" + to_string(i) + ".png", newbg);
}
else {
resize(out, out, cv::Size(1000, 1000));
fishes.emplace_back(out);
cv::imwrite("./out/out" + to_string(i) + ".png", out);
}
}
}
void writeMatToFile(cv::Mat& m, int width, int height)
{
std::ofstream fout("./out/step_240.yml");
if (!fout)
{
std::cout << "File Not Opened" << std::endl;
return;
}
int n = 0;
int t = 0;
fout << "%YAML:1.0" << std::endl;
fout << " " << "Xd: !!opencv-matrix" << std::endl;
fout << " " << "rows: " << width << std::endl;
fout << " " << "cols: " << height << std::endl;
fout << " " << "dt: f" << std::endl;
fout << " " << "data: [ ";
for (int i = 0; i<m.cols - 1; i++)
{
fout << m.at<float>(0, i) << ",";
n++;
if (n % 10 == 0)
{
fout << std::endl << " ";
}
}
fout << m.at<float>(0, m.cols - 1) << "]" << std::endl;
fout << " " << "Yd: !!opencv-matrix" << std::endl;
fout << " " << "rows: " << width << std::endl;
fout << " " << "cols: " << height << std::endl;
fout << " " << "dt: f" << std::endl;
fout << " " << "data: [ ";
for (int j = 0; j < m.cols - 1; j++)
{
fout << m.at<float>(1, j) << ",";
t++;
if (t % 10 == 0)
{
fout << std::endl << " ";
}
}
fout << m.at<float>(1, m.cols - 1) << "]" << std::endl;
}
void fish2Eqt(double x_dest, double y_dest, double* x_src, double* y_src, double Wd)
{
double phi1, phi2, theta1, theta2, dc, zcoor, p, _y, _z;
double v[3];
int theta = 20;
double cos0 = 1.0;//俯仰角cos
double sin0 = 0.0;//俯仰角sin
theta1 = FOV_240 * (x_dest / Wd);//-pi to pi
phi1 = CV_PI * (y_dest / Wd);//0 to pi
zcoor = sin(phi1);//z
v[0] = sin(theta1) * cos(phi1);//x
v[1] = cos(phi1) * cos(theta1);//y
_y = v[1] * cos0 - zcoor * sin0;
_z = v[1] * sin0 + zcoor * cos0;
dc = sqrt(_z * _z + v[0] * v[0]);
theta2 = atan2(_z, v[0]);
phi2 = atan2(dc, _y);
p = Wd * phi2 / FOV_240;
*x_src = p * cos(theta2);
*y_src = p * sin(theta2);
}
void fish_2D_map(cv::Mat &map_x, cv::Mat &map_y, int Hs, int Ws)
{
double x_d, y_d; // dest
double x_s, y_s; // source
double w2 = (double)Ws / 2.0 - 0.5;
double h2 = (double)Hs / 2.0 - 0.5;
Point2f temp, ttemp;
vector<Point2f> changepoints;
Mat fv = Mat::zeros(2, IMAGE_WIDTH*IMAGE_HEIGHT, CV_32F);
int t = 0;
for (int _y = 0; _y < Hs; _y++)
{
// y-coordinate in dest image relative to center
y_d = (double)_y - h2;//y_d代表相对于展开图中心位置的y坐标
for (int _x = 0; _x < Ws; _x++)
{
x_d = (double)_x - w2;//x_d代表相对于展开图中心位置的x坐标
// Convert fisheye coordinate to cartesian coordinate (equirectangular)
fish2Eqt(x_d, y_d, &x_s, &y_s, Ws);
//cout << x_d << endl;
x_s += w2;
y_s += h2;
// Create map
map_x.at<float>(_y, _x) = float(x_s);
map_y.at<float>(_y, _x) = float(y_s);
//map_x map_y是鱼眼展开图对应原鱼眼图xy位置
fv.at<float>(0, t) = x_s;
fv.at<float>(1, t) = y_s;
if (t < IMAGE_WIDTH*IMAGE_HEIGHT) {
t++;
}
}
}
writeMatToFile(fv, IMAGE_WIDTH, IMAGE_HEIGHT);
}
vector<cv::Mat> Unwarping(vector<cv::Mat>& fishes) {
cv::Rect rect(0, 0, 1000, 1000);
cv::Mat mls_map_x, mls_map_y;
cv::Mat map_x, map_y;
map_x = cv::Mat(IMAGE_HEIGHT, IMAGE_WIDTH, CV_32FC1);
map_y = cv::Mat(IMAGE_HEIGHT, IMAGE_WIDTH, CV_32FC1);
cv::Mat remapped[4];
vector<cv::Mat> vectorremapped;
cv::Mat Crop_remapped[4];
if (mode == 0) {
cv::FileStorage fs("./out/step_240.yml", cv::FileStorage::READ);
fs["Xd"] >> mls_map_x;
fs["Yd"] >> mls_map_y;
fs.release();
}
for (int i = 0; i < fishes.size(); i++) {
//需要重新生成yml时就取消fish_2D_map,注释remap。
if (mode == 1) {
fish_2D_map(map_x, map_y, IMAGE_HEIGHT, IMAGE_WIDTH);
}
else
{
remap(fishes[i], remapped[i], mls_map_x, mls_map_y, INTER_AREA, BORDER_CONSTANT, Scalar(0, 0, 0, 0));
imwrite("./out/Unwarp/" + to_string(i) + ".jpg", remapped[i]);
}
vectorremapped.emplace_back(remapped[i]);
}
return vectorremapped;
}
void main() {
vector<cv::Mat> fishes;
//根据掩膜抠出图像有效区域并重置大小
ExtractFish(fishes);
//图像展开
vector<cv::Mat> unwarpFish = Unwarping(fishes);
}