The use of OpenCV polar coordinate conversion function warpPolar

OPenCV version: 4.4

IDE:VS2019

Functional description

Remap the image to polar or semi-logarithmic polar coordinate space, this function is used to implement the polar coordinate transformation of the image.
insert image description here
Transform the image using the following transformation:
dst ( ρ , ϕ ) = src ( x , y ) dst(\rho , \phi ) = src(x,y)d s t ( p ,) _=src(x,y )
Dimension:
I ⃗ = ( x − center . x , y − center . y ) ϕ = K angle ⋅ angle ( I ⃗ ) ρ = { K lin ⋅ magnitude ( I ⃗ ) default K log ⋅ loge ( magnitude ( ); I ⃗ ) ) if semilog \begin{array}{l}\vec{I} = (x - center.x, \;y - center.y) \\ \phi = Kangle \cdot \texttt{angle} (\ vec{I}) \\ \rho = \left\{\begin{matrix} Clean \cdot \texttt{magnitude}(\vec{I}) & default \\ Wise \cdot log_e(\texttt{magnitude}(\ vec{I})) & if \; semilog \\\end{matrix}\right. \end{array}I =(xcenter.x,ycenter.y)ϕ=K a n g l eangle(I )r={ K l i nmagnitude(I )Cl o g _loge(magnitude(I ))defaultifsemilog

并且:
K a n g l e = d s i z e . h e i g h t / 2 Π K l i n = d s i z e . w i d t h / m a x R a d i u s K l o g = d s i z e . w i d t h / l o g e ( m a x R a d i u s ) \begin{array}{l} Kangle = dsize.height / 2\Pi \\ Klin = dsize.width / maxRadius \\ Klog = dsize.width / log_e(maxRadius) \\ \end{array} K a n g l e=dsize.height/2ΠK l i n=dsize.width/maxRadiusCl o g _=dsize.width/loge(maxRadius)

Linear and semi-logarithmic mapping
Polar coordinate mapping can be linear or semi-logarithmic, add one of WarpPolarMode to flags to determine polar coordinate mapping mode,.
Linear is the default mode.
The semi-logarithmic map mimics human "foveal" vision, allowing very high sharpness on the line of sight (central vision) and less sharpness in peripheral vision.

Options for dsize:

  • If both values ​​in dsize are <= 0 (default), the destination image will have (almost) the same source bounding circle area
    dsize . area ← ( max R adius 2 ⋅ Π ) dsize . width = cvRound ( max R adius ) dsize . height = cvRound ( max R adius ⋅ Π ) \begin{array}{l} dsize.area \leftarrow (maxRadius^2 \cdot \Pi) \\ dsize.width = \texttt{cvRound}(maxRadius) \ \dsize.height = \texttt{cvRound}(maxRadius \cdot \Pi) \\ \end{array}dsize.area(maxRadius2P )dsize.width=cvRound(maxRadius)dsize.height=cvRound(maxRadiusP ).
  • If only dsize.height <= 0, the target image area will be scaled proportionally to the bounding circle area by Kx * Kx:.
    dsize . height = cvRound ( dsize . width ⋅ Π ) \begin{array}{l} dsize.height = \texttt{cvRound}(dsize.width \cdot \Pi) \\ \end{array}dsize.height=cvRound(dsize.widthP ).
  • If all members of dsize have values ​​> 0, the destination image will have the given size, so the area of ​​the bounding circle will be scaled to dsize.

reverse mapping

You can get reverse mapping by adding WARP_INVERSE_MAP to flags.

 // 直接变换
 warpPolar(src, lin_polar_img, Size(),center, maxRadius, flags);                     
 // 线性极坐标
 warpPolar(src, log_polar_img, Size(),center, maxRadius, flags + WARP_POLAR_LOG);  
 // 半对数极坐标
 // 反变换
 warpPolar(lin_polar_img, recovered_lin_polar_img, src.size(), center, maxRadius, flags + WARP_INVERSE_MAP);
 warpPolar(log_polar_img, recovered_log_polar, src.size(), center, maxRadius, flags + WARP_POLAR_LOG + WARP_INVERSE_MAP);

In programming, the original coordinates are calculated from polar coordinates via (ρ, φ) −> (x, y):

 double angleRad, magnitude;
 double Kangle = dst.rows / CV_2PI;
 angleRad = phi / Kangle;
 if (flags & WARP_POLAR_LOG)
 {
    
    
     double Klog = dst.cols / std::log(maxRadius);
     magnitude = std::exp(rho / Klog);
 }
 else
 {
    
    
     double Klin = dst.cols / maxRadius;
     magnitude = rho / Klin;
 }
 int x = cvRound(center.x + magnitude * cos(angleRad));
 int y = cvRound(center.y + magnitude * sin(angleRad));

function prototype

void cv::warpPolar	(	InputArray 	src,
	OutputArray 	dst,
	Size 	dsize,
	Point2f 	center,
	double 	maxRadius,
	int 	flags 
)		

parameter

  • src source image.
  • dst destination image, same type as src.
  • dsize Destination image size (see description for valid options).
  • center The transformation center.
  • maxRadius The radius of the bounding circle to transform, which also determines the inverse magnitude scale parameter.
    The combination of flags interpolation method, InterpolationFlags + WarpPolarMode .
  • Added WARP_POLAR_LINEAR to select linear polar mapping (default)
  • Added WARP_POLAR_LOG to select semi-log polar mapping.
  • Add WARP_INVERSE_MAP to select reverse mapping

Note

  • This function does not support in-place conversion.
  • To calculate the magnitude and angle, cartToPolar is used internally, so angles are measured from 0 to 360 degrees with an accuracy of about 0.3 degrees.
  • This function uses remap . Due to limitations of the current implementation, the size of the input and output images should be smaller than 32767x32767.

See also
cv::remap

sample code

#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
int main(int argc, char** argv)
{
    
    
    VideoCapture capture;
    Mat log_polar_img, lin_polar_img, recovered_log_polar, recovered_lin_polar_img;
    CommandLineParser parser(argc, argv, "{@input|0| camera device number or video file path}");
    parser.about("\nThis program illustrates usage of Linear-Polar and Log-Polar image transforms\n");
    parser.printMessage();
    std::string arg = parser.get<std::string>("@input");
    //if (arg.size() == 1 && isdigit(arg[0]))
    //    capture.open(arg[0] - '0');
    //else
    //    capture.open(samples::findFileOrKeep(arg));
    capture.open("D:\\OpenCVtest\\video1.mp4");

    if (!capture.isOpened())
    {
    
    
        fprintf(stderr, "Could not initialize capturing...\n");
        return -1;
    }
    namedWindow("Linear-Polar", WINDOW_AUTOSIZE);
    namedWindow("Log-Polar", WINDOW_AUTOSIZE);
    namedWindow("Recovered Linear-Polar", WINDOW_AUTOSIZE);
    namedWindow("Recovered Log-Polar", WINDOW_AUTOSIZE);
    moveWindow("Linear-Polar", 20, 20);
    moveWindow("Log-Polar", 700, 20);
    moveWindow("Recovered Linear-Polar", 20, 350);
    moveWindow("Recovered Log-Polar", 700, 350);
    int flags = INTER_LINEAR + WARP_FILL_OUTLIERS;
    Mat src;
    for (;;)
    {
    
    
        capture >> src;
        if (src.empty())
            break;
        Point2f center((float)src.cols / 2, (float)src.rows / 2);
        double maxRadius = 0.7 * min(center.y, center.x);
#if 0 //deprecated
        double M = frame.cols / log(maxRadius);
        logPolar(frame, log_polar_img, center, M, flags);
        linearPolar(frame, lin_polar_img, center, maxRadius, flags);
        logPolar(log_polar_img, recovered_log_polar, center, M, flags + WARP_INVERSE_MAP);
        linearPolar(lin_polar_img, recovered_lin_polar_img, center, maxRadius, flags + WARP_INVERSE_MAP);
#endif
        // direct transform
        warpPolar(src, lin_polar_img, Size(), center, maxRadius, flags);                     // linear Polar
        warpPolar(src, log_polar_img, Size(), center, maxRadius, flags + WARP_POLAR_LOG);    // semilog Polar
        // inverse transform
        warpPolar(lin_polar_img, recovered_lin_polar_img, src.size(), center, maxRadius, flags + WARP_INVERSE_MAP);
        warpPolar(log_polar_img, recovered_log_polar, src.size(), center, maxRadius, flags + WARP_POLAR_LOG + WARP_INVERSE_MAP);
        // Below is the reverse transformation for (rho, phi)->(x, y) :
        Mat dst;
        if (flags & WARP_POLAR_LOG)
            dst = log_polar_img;
        else
            dst = lin_polar_img;
        //get a point from the polar image
        int rho = cvRound(dst.cols * 0.75);
        int phi = cvRound(dst.rows / 2.0);
        double angleRad, magnitude;
        double Kangle = dst.rows / CV_2PI;
        angleRad = phi / Kangle;
        if (flags & WARP_POLAR_LOG)
        {
    
    
            double Klog = dst.cols / std::log(maxRadius);
            magnitude = std::exp(rho / Klog);
        }
        else
        {
    
    
            double Klin = dst.cols / maxRadius;
            magnitude = rho / Klin;
        }
        int x = cvRound(center.x + magnitude * cos(angleRad));
        int y = cvRound(center.y + magnitude * sin(angleRad));
        drawMarker(src, Point(x, y), Scalar(0, 255, 0));
        drawMarker(dst, Point(rho, phi), Scalar(0, 255, 0));
        imshow("Src frame", src);
        imshow("Log-Polar", log_polar_img);
        imshow("Linear-Polar", lin_polar_img);
        imshow("Recovered Linear-Polar", recovered_lin_polar_img);
        imshow("Recovered Log-Polar", recovered_log_polar);
        if (waitKey(10) >= 0)
            break;
    }
    return 0;
}

operation result

Original:
insert image description here
Linear Polar Mapping:
insert image description here
Semi-Log Polar
insert image description here
Map Restored Linear Polar Map:
insert image description here
Recovered Semi-Log Polar Map
insert image description here

Guess you like

Origin blog.csdn.net/jndingxin/article/details/125682056