柱面投影+球面投影算法源代码

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;

void CylindricalWarp()
{
    cv::Mat imgMat = cv::imread("/img/1.jpg");

    cv::namedWindow("Original", 0);
    cv::imshow("Original", imgMat);
    double r = imgMat.cols;
    int w = atan2(imgMat.cols / 2, r) * 2 * r;
    int h = imgMat.rows;
    cv::Mat destImgMat = cv::Mat::zeros(cv::Size(w, h), CV_8UC3);
    for (int y = 0; y < destImgMat.rows; y++)
    {
        for (int x = 0; x < destImgMat.cols; x++)
        {
            cv::Point2f current_pos(x, y);

            float point_x = r * tan(current_pos.x / r - atan2(w, 2 * r)) + w / 2;
            // float point_y = r * tan(current_pos.y / r - atan2(h, 2 * r)) + h / 2;
            float point_y = (current_pos.y - h / 2) * sqrt(r * r + (w / 2 - x) * (w / 2 - x)) / r + h / 2;
            cv::Point2f original_point(point_x, point_y);

            cv::Point2i top_left((int)(original_point.x), (int)(original_point.y)); //top left because of integer rounding

            //make sure the point is actually inside the original image
            if (top_left.x < 0 || top_left.x > imgMat.cols - 2 || top_left.y < 0 || top_left.y > imgMat.rows - 2)
            {
                continue;
            }

            //bilinear interpolation
            float dx = original_point.x - top_left.x;
            float dy = original_point.y - top_left.y;

            float weight_tl = (1.0 - dx) * (1.0 - dy);
            float weight_tr = (dx) * (1.0 - dy);
            float weight_bl = (1.0 - dx) * (dy);
            float weight_br = (dx) * (dy);
            for (int k = 0; k < 3; k++)
            {
                uchar value = weight_tl * imgMat.at<cv::Vec3b>(top_left)[k] +
                              weight_tr * imgMat.at<cv::Vec3b>(top_left.y, top_left.x + 1)[k] +
                              weight_bl * imgMat.at<cv::Vec3b>(top_left.y + 1, top_left.x)[k] +
                              weight_br * imgMat.at<cv::Vec3b>(top_left.y + 1, top_left.x + 1)[k];

                destImgMat.at<cv::Vec3b>(y, x)[k] = value;
            }
        }
    }

    cv::namedWindow("Cylindrical", 0);
    cv::imshow("Cylindrical", destImgMat);
    cv::waitKey(0);

    cv::imwrite("img/cyl_lena.jpg", destImgMat);
}
void SphericalProjection()
{
    cv::Mat imgMat = cv::imread("/img/1.jpg");

    cv::namedWindow("Original", 0);
    cv::imshow("Original", imgMat);
    double r = imgMat.cols / 2;
    int w = atan2(imgMat.cols / 2, r) * 2 * r;
    int h = atan2(imgMat.rows / 2, r) * 2 * r;
    // int w = imgMat.cols;
    // int h = imgMat.rows;
    // cout << cos(60 * CV_PI / 180) << endl;
    cv::Mat destImgMat = cv::Mat::zeros(cv::Size(w, h), CV_8UC3);
    for (int y = 0; y < destImgMat.rows; y++)
    {
        for (int x = 0; x < destImgMat.cols; x++)
        {
            cv::Point2f current_pos(x, y);
            // double length = r / sqrt(abs(powf(cos((current_pos.x - w / 2) * CV_PI / (r * 180)), 2) - powf(cos((current_pos.y - h / 2) * CV_PI / (r * 180)), 2)));
            double length = r * r / sqrt(r * r - (current_pos.x - w / 2) * (current_pos.x - w / 2) - (current_pos.y - h / 2) * (current_pos.y - h / 2));
            float point_x = sin((current_pos.x - w / 2) / r) * length + imgMat.cols / 2;
            float point_y = sin((current_pos.y - h / 2) / r) * length + imgMat.rows / 2;
            cv::Point2f original_point(point_x, point_y);

            cv::Point2i top_left((int)(original_point.x), (int)(original_point.y)); //top left because of integer rounding

            //make sure the point is actually inside the original image
            if (top_left.x < 0 || top_left.x > imgMat.cols - 2 || top_left.y < 0 || top_left.y > imgMat.rows - 2)
            {
                continue;
            }

            //bilinear interpolation
            float dx = original_point.x - top_left.x;
            float dy = original_point.y - top_left.y;

            float weight_tl = (1.0 - dx) * (1.0 - dy);
            float weight_tr = (dx) * (1.0 - dy);
            float weight_bl = (1.0 - dx) * (dy);
            float weight_br = (dx) * (dy);
            for (int k = 0; k < 3; k++)
            {
                uchar value = weight_tl * imgMat.at<cv::Vec3b>(top_left)[k] +
                              weight_tr * imgMat.at<cv::Vec3b>(top_left.y, top_left.x + 1)[k] +
                              weight_bl * imgMat.at<cv::Vec3b>(top_left.y + 1, top_left.x)[k] +
                              weight_br * imgMat.at<cv::Vec3b>(top_left.y + 1, top_left.x + 1)[k];

                destImgMat.at<cv::Vec3b>(y, x)[k] = value;
            }
        }
    }

    cv::namedWindow("Spherical", 0);
    cv::imshow("Spherical", destImgMat);
    cv::waitKey(0);

    cv::imwrite("img/spherical_projection.jpg", destImgMat);
}
int main()
{
    CylindricalWarp();
    SphericalProjection();
    return 0;
}

效果图如下:

                                                                                                                   原图像

                                                                                                                柱面投影变换

                                                                                                             球面投影变换

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值