OpenCV3入門(十四)圖像特效—擠壓、哈哈鏡、扭曲

  • 2020 年 3 月 16 日
  • 筆記

一、圖像擠壓特效

1、原理

圖像壓效果本質的圖像坐標的非線性變換,將圖像向內擠壓,擠壓的過程產生壓縮變形,從而形成的效果。

擠壓效果的實現是通過極坐標的形式,設圖像中心為O(x,y),某點距離中心O的距離為半徑R,非線性方式改變半徑R但不改變點的方向,就構成了圖像擠壓。也可以自定義加壓中心點,計算半徑方式相同。

圖像像素變換倍率使用 y=sqrt(x)。

 圖像上點P與圖像中心O的距離為R,圖像擠壓就是P點坐標映射到OP直線上的點R2位置,其中| OR2 |=sqrt(OP)*ratio。

 

2、實現

void Pinch(Mat& img, Mat& dst, int degree)  {      if (degree < 1) degree = 1;      if (degree > 32) degree = 32;        if (dst.empty())          dst.create(img.rows, img.cols, img.type());      dst = cv::Scalar::all(0);        int chns = img.channels();      int height = img.rows;      int width = img.cols;        int midX = width / 2;      int midY = height / 2;      int i, j, k;      int X, Y, offsetX, offsetY;      double radian, radius;  //弧和半徑        for (i = 0; i < height; i++)      {          for (j = 0; j < width; j++)          {              offsetX = j - midX;              offsetY = i - midY;                radian = atan2((double)offsetY, (double)offsetX);                // 半徑              radius = sqrtf((float)(offsetX*offsetX + offsetY * offsetY));              radius = sqrtf(radius)*degree;                X = (int)(radius*cos(radian)) + midX;              Y = (int)(radius*sin(radian)) + midY;                if (X < 0) X = 0;              if (X >= width) X = width - 1;              if (Y < 0) Y = 0;              if (Y >= height) Y = height - 1;                for (k = 0; k < chns; k++)              {                  dst.at<Vec3b>(i, j)[k] = img.at<Vec3b>(Y, X)[k];              }          }      }  }    Mat src_img;  Mat dst_img;  int rato = 15;    void call_back(int, void*)  {      Pinch(src_img, dst_img, rato);      imshow("Pinch圖", dst_img);  }    int main() {        src_img = imread("D:\WORK\5.OpenCV\LeanOpenCV\pic_src\pic18.bmp");      imshow("原圖", src_img);        Pinch(src_img, dst_img, rato);      imshow("Pinch圖", dst_img);        namedWindow("Pinch圖");      createTrackbar("Pinch倍率", "Pinch圖", &rato, 50, call_back);      call_back(rato, 0);        waitKey(0);  }

3、測試效果

測試1

測試2:不同倍率下棋盤格的擠壓效果。

 二、哈哈鏡特效

1、原理

 圖像坐標的非線性變換,實現k的根號與k的比值,sqrt(k)/k k1時總倍率為1,當k小於1時,總倍率為漸變倍率。

2、實現

void Pinch(Mat& img, Mat& dst, int x, int y, int degree)  {      if (dst.empty())          dst.create(img.rows, img.cols, img.type());        dst = cv::Scalar::all(0);      cout << "x,y " << x << " " << y << endl;        int chns = img.channels();      int height = img.rows;      int width = img.cols;        midX = x;      midY = y;      int R = 100;        int i, j, k;      int X, Y, offsetX, offsetY;      double radian, radius;  //弧和半徑        for (i = 0; i < height; i++)      {          for (j = 0; j < width; j++)          {              offsetX = j - midX;              offsetY = i - midY;               radian = atan2((double)offsetY, (double)offsetX);                // 半徑              radius = sqrtf((float)(offsetX*offsetX + offsetY * offsetY));              if (radius <= R &&  radius > 1) {                  float k = sqrtf(radius/R) * radius / R * degree;                  X = (int)( cos(radian) * k) + midX;                  Y = (int)( sin(radian) * k) +  midY;                    if (X < 0) X = 0;                  if (X >= width) X = width - 1;                  if (Y < 0) Y = 0;                  if (Y >= height) Y = height - 1;                    for (k = 0; k < chns; k++)                  {                      dst.at<Vec3b>(i, j)[k] = img.at<Vec3b>(Y, X)[k];                  }              }              else              {                  for (k = 0; k < chns; k++)                  {                      dst.at<Vec3b>(i, j)[k] = img.at<Vec3b>(i, j)[k];                  }              }          }      }        cout << " midX, midY " << midX << " " << midY << endl;  }

3、測試效果

測試1:哈哈鏡效果

測試2:大倍率呈現潛望鏡效果。

測試3:

三、圖像扭曲

對圖像的像素坐標進行正弦變換,映射到對應坐標就完成了圖像扭曲。關鍵代碼如下:

for (int j = 0; j < width; j++)  {      double temp =  degree * sin(1.0 * j / width  *  pi * T ); // [-degree,degree]      temp = degree + temp;  // [0, 2*degree]      for (int i = int(temp + 0.5); i < height + temp - 2 * degree; i++)      {          X = (int)((i - temp) *  (height) / (height - degree));          if (X >= img.rows)              X = img.rows - 1;          if (X < 0)              X = 0;            for (int c = 0; c < chns; c++)          {              dst.at<Vec3b>(i, j)[c] = img.at<Vec3b>(X, j)[c];          }      }  }

測試1:

測試2:

4、參考文獻

1、《學習OpenCV》,清華大學出版社,Gary Bradski, Adrian kaehler著

2、仿射變換

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.html

3、PhotoShop算法實現高級篇–擠壓特效(三十六)

https://blog.csdn.net/kezunhai/article/details/41873775

 

技術博客,轉載請註明。

https://www.cnblogs.com/pingwen/p/12503047.html