对图像进行变形失真

老子叫甜甜 提交于 2020-08-18 06:37:47

实现参考

                       原图

#include <QApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
static double PID2   = 3.141592653 * 0.5;
static double param1 = 0.25;
static double param2 = 0.25;
static double param3 = 0.25;

int SIGN(float x) {
  if (x < 0)
    return -1;
  else
    return 1;
}

int Eval(int mapping, double x, double y, double *xnew, double *ynew) {
  double phi, radius, radius2;
  double xtmp, ytmp;
  double denom;

  /* Some things that may be needed */
  radius2 = x * x + y * y;
  radius  = sqrt(radius2);
  phi     = atan2(y, x);

  switch (mapping) {
  case 1:
    /*
       Square root radial function
       Normally clamped to radius <= 1
    */
    radius = sqrt(radius);
    *xnew  = radius * cos(phi);
    *ynew  = radius * sin(phi);
    break;
  case 2:
    /*
       arcsin radial function
    */
    if (radius > 1) return (FALSE);
    radius = asin(radius) / PID2;
    *xnew  = radius * cos(phi);
    *ynew  = radius * sin(phi);
    break;
  case 3:
    /*
       sin radial function
       Normally clamped to radius <= 1
    if (radius > 1)
       return(FALSE);
    */
    radius = sin(PID2 * radius);
    *xnew  = radius * cos(phi);
    *ynew  = radius * sin(phi);
    break;
  case 4:
    /*
       radius to a power, radial function
       Normally clamped to radius <= 1
    if (radius > 1)
       return(FALSE);
    */
    radius = pow(radius, param1);
    *xnew  = radius * cos(phi);
    *ynew  = radius * sin(phi);
    break;
  case 5:
    /*
       sin function cartesian function
    */
    *xnew = sin(PID2 * x);
    *ynew = sin(PID2 * y);
    break;
  case 6:
    /*
       square cartesian function
       Includes quadrant preserving
    */
    *xnew = x * x * SIGN(x);
    *ynew = y * y * SIGN(y);
    break;
  case 7:
    /*
       arc sine cartesian function
    */
    *xnew = asin(x) / PID2;
    *ynew = asin(y) / PID2;
    break;
  case 8:
    /*
       (1-ar^2) cartesian function
    */
    *xnew = x * (1 - param1 * radius2) / (1 - param1);
    *ynew = y * (1 - param1 * radius2) / (1 - param1);
    break;
  case 9:
    /*
       Method by H. Farid and A.C. Popescu
       Used for modest lens with good fit
    */
    denom = 1 - param1 * radius2;
    xtmp  = x / denom;
    ytmp  = y / denom;
    if (xtmp <= -1 || xtmp >= 1 || ytmp <= -1 || ytmp >= 1) return (FALSE);
    denom = 1 - param1 * (xtmp * xtmp + ytmp * ytmp);
    if (ABS(denom) < 0.000001) return (FALSE);
    *xnew = x / denom;
    *ynew = y / denom;
    break;
  case 10:
    /*
       Logarithmic relationship
       eg: fitted to test pattern with 2 parameters
    */
    radius = param1 * pow(10.0, param2 * radius) - param1;
    *xnew  = radius * cos(phi);
    *ynew  = radius * sin(phi);
    break;
  case 11:
    /*
       General third order polynomial
       eg: fitted to test pattern with 3 parameters
    */
    radius = param1 * radius2 * radius + param2 * radius2 + param3 * radius;
    *xnew  = radius * cos(phi);
    *ynew  = radius * sin(phi);
    break;
  case 12:
    /*
       Janez Pers, Stanislav Kovacic
       Alternative Model o Radial Distortion in Wide-Angle Lenses
       Single parameter model
    */
    radius = -0.5 * param1 * (exp(-2 * radius / param1) - 1) /
        (exp(-radius / param1));
    *xnew = radius * cos(phi);
    *ynew = radius * sin(phi);
    break;
  case 13:
    /*
       Image rotate by parameter1 in radians
    */
    *xnew = radius * cos(phi + param1);
    *ynew = radius * sin(phi + param1);
    break;
  case 0:
  default:
    /*
       Unity mapping
    */
    *xnew = x;
    *ynew = y;
    break;
  }

  return (TRUE);
}

void on_mouse(int event, int x, int y, int flags, void *ustc) {
  if (event ==
      cv::EVENT_LBUTTONDOWN) //左键按下
  {
    static int mapping = 1;
    cv::Mat mat        = *(Mat *)ustc;
    int width          = mat.cols;
    int height         = mat.rows;
    double scaleX      = 1.0;//控制视野
    double scaleY      = 1.0;//控制视野
    int newWidth       = width * 2;  //放大两倍
    int newHeight      = height * 2; //放大两倍
    Mat des(newHeight, newWidth, mat.type(), cv::Scalar(0, 0, 0));
    static int antialias = 1; //简单的抗锯齿,取值1,2,4,8,16......
    for (int i = 0; i < newHeight; ++i) {
      for (int j = 0; j < newWidth; ++j) {
        Vec3i vSum(0, 0, 0);
        for (int ai = 0; ai < antialias; ai++) {
          //先归一化像素坐标-1~1,x=2*i/width-1,y=2*j/width-1
          double nx = 2.0 * (j + ai / (double)antialias) / newWidth - 1;
          nx /= scaleX;
          for (int aj = 0; aj < antialias; aj++) {
            double ny = 2.0 * (i + aj / (double)antialias) / newHeight - 1;
            ny /= scaleY;
            double newNX, newNY;
            //从当前坐标反推原始图像坐标(先归一化的坐标)
            Eval(mapping, nx, ny, &newNX, &newNY);
            //转换为原始图像坐标
            int rx = ((newNX + 1) * width / 2.0);
            int ry = ((newNY + 1) * height / 2.0);
            if (rx < 0 || rx >= width || ry < 0 || ry >= height) { continue; }
            vSum += mat.at<Vec3b>(ry, rx);
          }
        }
        des.at<Vec3b>(i, j) = vSum / (antialias * antialias);
      }
    }
    cv::imshow("des", des);
    mapping++;
  } else if (event == cv::EVENT_LBUTTONUP) {
  }
}

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  cv::Mat mat = cv::imread("test0.bmp");
  cv::namedWindow("test");
  cv::setMouseCallback("test", on_mouse, &mat); //调用回调函数
  cv::imshow("test", mat);
  return a.exec();
}

下面图像是用不同的变换函数变换结果:

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!