Just My Life & My Work

許多影像處理軟體都會提供濾鏡效果,其中之一的效果是魚眼鏡頭(Fisheye Lens),會寫程式且對影像處理感興趣的人,多少會想知道如何實做魚眼效果,所以我就動手來做做看囉!

標準的魚眼鏡頭可以由數學式子推導,詳細內容可參照Fisheye Projection

網路上已經有人實做出來,所以我直接拿來玩:P前提示要先安裝OpenCV喔!

/**
	Theme: Simulate Fisheye Lens
	Compiler: Dev C++ 4.9.9.2
	Date: 101/01/03
	Author: HappyMan
	Blog: https://cg2010studio.wordpress.com/
*/
#include <cv.h>
#include <highgui.h>
#include <math.h>
#include <unistd.h>
#include <getopt.h>
#include <iostream>
void sampleImage(const IplImage* arr, float idx0, float idx1, CvScalar& res){
  if(idx0<0 || idx1<0 || idx0>(cvGetSize(arr).height-1) || idx1>(cvGetSize(arr).width-1)){
    res.val[0]=0;
    res.val[1]=0;
    res.val[2]=0;
    res.val[3]=0;
    return;
  }
  float idx0_fl=floor(idx0);
  float idx0_cl=ceil(idx0);
  float idx1_fl=floor(idx1);
  float idx1_cl=ceil(idx1);

  CvScalar s1=cvGet2D(arr,(int)idx0_fl,(int)idx1_fl);
  CvScalar s2=cvGet2D(arr,(int)idx0_fl,(int)idx1_cl);
  CvScalar s3=cvGet2D(arr,(int)idx0_cl,(int)idx1_cl);
  CvScalar s4=cvGet2D(arr,(int)idx0_cl,(int)idx1_fl);
  float x = idx0 - idx0_fl;
  float y = idx1 - idx1_fl;
  res.val[0]= s1.val[0]*(1-x)*(1-y) + s2.val[0]*(1-x)*y + s3.val[0]*x*y + s4.val[0]*x*(1-y);
  res.val[1]= s1.val[1]*(1-x)*(1-y) + s2.val[1]*(1-x)*y + s3.val[1]*x*y + s4.val[1]*x*(1-y);
  res.val[2]= s1.val[2]*(1-x)*(1-y) + s2.val[2]*(1-x)*y + s3.val[2]*x*y + s4.val[2]*x*(1-y);
  res.val[3]= s1.val[3]*(1-x)*(1-y) + s2.val[3]*(1-x)*y + s3.val[3]*x*y + s4.val[3]*x*(1-y);
}
float xscale;
float yscale;
float xshift;
float yshift;
float getRadialX(float x,float y,float cx,float cy,float k){
  x = (x*xscale+xshift);
  y = (y*yscale+yshift);
  float res = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
  return res;
}
float getRadialY(float x,float y,float cx,float cy,float k){
  x = (x*xscale+xshift);
  y = (y*yscale+yshift);
  float res = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
  return res;
}
float thresh = 1;
float calc_shift(float x1,float x2,float cx,float k){
  float x3 = x1+(x2-x1)*0.5;
  float res1 = x1+((x1-cx)*k*((x1-cx)*(x1-cx)));
  float res3 = x3+((x3-cx)*k*((x3-cx)*(x3-cx)));
  //  std::cerr<<"x1: "<<x1<<" - "<<res1<<" x3: "<<x3<<" - "<<res3<<std::endl;
  if(res1>-thresh and res1 < thresh)
    return x1;
  if(res3<0){
    return calc_shift(x3,x2,cx,k);
  }
  else{
    return calc_shift(x1,x3,cx,k);
  }
}
int main(int argc, char** argv){
  IplImage* src = cvLoadImage( argv[1], 1 );
  IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
  IplImage* dst2 = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
  float K=atof(argv[3]);
  float centerX=atoi(argv[4]);
  float centerY=atoi(argv[5]);
  int width = cvGetSize(src).width;
  int height = cvGetSize(src).height;

  xshift = calc_shift(0,centerX-1,centerX,K);
  float newcenterX = width-centerX;
  float xshift_2 = calc_shift(0,newcenterX-1,newcenterX,K);

  yshift = calc_shift(0,centerY-1,centerY,K);
  float newcenterY = height-centerY;
  float yshift_2 = calc_shift(0,newcenterY-1,newcenterY,K);
  //  scale = (centerX-xshift)/centerX;
  xscale = (width-xshift-xshift_2)/width;
  yscale = (height-yshift-yshift_2)/height;

  std::cerr<<xshift<<" "<<yshift<<" "<<xscale<<" "<<yscale<<std::endl;
  std::cerr<<cvGetSize(src).height<<std::endl;
  std::cerr<<cvGetSize(src).width<<std::endl;

  for(int j=0;j<cvGetSize(dst).height;j++){
    for(int i=0;i<cvGetSize(dst).width;i++){
      CvScalar s;
      float x = getRadialX((float)i,(float)j,centerX,centerY,K);
      float y = getRadialY((float)i,(float)j,centerX,centerY,K);
      sampleImage(src,y,x,s);
      cvSet2D(dst,j,i,s);
    }
  }
#if 0
  cvNamedWindow( "Source1", 1 );
  cvShowImage( "Source1", dst);
  cvWaitKey(0);
#endif
  cvSaveImage(argv[2],dst,0);
#if 0
  for(int j=0;j<cvGetSize(src).height;j++){
    for(int i=0;i<cvGetSize(src).width;i++){
      CvScalar s;
      sampleImage(src,j+0.25,i+0.25,s);
      cvSet2D(dst,j,i,s);
    }
  }
  cvNamedWindow( "Source1", 1 );
  cvShowImage( "Source1", src);
  cvWaitKey(0);
#endif
}

編譯後產生執行檔,可以直接在命令提示字元中下指令,格式有五個參數:|input image| |output image| |K which controlls amount of distortion (typically try values around 0.001)| |x coordinate of center of distortion| |y coordinate of center of distortion|

我使用黑白相間的棋盤,來看看魚眼效果如何。

C:\test>xx chessboard.jpg “1 382 382.jpg" 1 382 382
374.785 374.785 0.0188681 0.0188867
764
765

C:\test>xx chessboard.jpg “0.1 382 382.jpg" 0.1 382 382
366.571 366.571 0.0403572 0.040391
764
765

C:\test>xx chessboard.jpg “0.01 382 382.jpg" 0.01 382 382
349.281 349.281 0.0855572 0.0856518
764
765

C:\test>xx chessboard.jpg “0.001 382 382.jpg" 0.001 382 382
314.027 314.027 0.177814 0.177939
764
765

C:\test>xx chessboard.jpg “0.0001 382 382.jpg" 0.0001 382 382
246.776 246.776 0.353744 0.35399
764
765

例子:xx是執行檔的名字,chessboard.jpg是輸入影像名稱,"0.001 382 382.jpg"是輸出影像名字,0.001是變形參數,382 382分別是x和y的變形中心點。

變形參數大於0.001效果就變得很奇怪,0表示無任何變形。原本想要使用負數來表現反魚眼效果,可惜該數學模式沒辦法做到。

參考:Fisheye ProjectionHow to simulate fisheye lens effect by openCV?

Comments on: "[OpenCV] 模擬魚眼鏡頭 (Simulate Fisheye Lens)" (12)

  1. 張哲誠 的大頭貼

    你好,請問有辦法將做出來的魚眼效果圖形是圓形的嗎?

  2. Christian Louboutin Heels 的大頭貼

    It’s hard to find educated people in this particular topic, however, you sound like
    you know what you’re talking about! Thanks

  3. 藤木 的大頭貼

    你好 上面的影片我已經公開權限嚕 我後來用朋友的小筆電WIN XP系統 跑 但她不會停 就黑色螢幕過就沒有停下 請問 是還缺什麼設定的地方 還是有哪邊要更新?
    WIN XP 執行過程

    在此感謝您的撥空回答

    • HappyMan 的大頭貼

      我知道你哪裡有問題了,確實我也會發生你影片中當掉的樣子,並出現訊息:
      This application has requested the Runtime to terminate it in an unusual way.
      Please contact the application’s support team for more information.

      你可以創一個資料夾像這個路徑:C:\Temp
      接著把程式檔丟進去,
      編譯完之後會出現.exe檔,
      表示成功編譯,
      那要怎麼成功執行呢?
      就是打開命令提示字元,
      到該路徑底下,
      然後打五個參數上去,如:
      test.exe chessboard.jpg result.jpg 0.0001 382 382

      test.exe為程式編譯成功後產生的執行檔
      chessboard.jpg為實驗用的影像檔
      result.jpg為程式執行完之後產生的影像檔
      後面三個參數請參考文章中的說明喔~

      總言之,就是我這個程式碼適用在「命令提示字元」下執行:)

      你螢幕錄影的軟體叫什麼名字呀?我也想用~

  4. 藤木 的大頭貼

    你好,我是一個學生,想請問一下 此code 真的可以執行? 我確定安裝好 dev c++ 和 OpenCV 2.0 也可以順利完成 Dev-C++4.9.9.2 安裝 OpenCV 2.0 這個網址 順利開啟圖片 但這次我直接複製 上面的魚眼透鏡 卻在執行時 會當機出現錯誤訊息 ?
    我有把圖拍下
    https://docs.google.com/open?id=0B86KqjDQBh8lNi1EZjFvSFBaMEk

  5. Node 的大頭貼

    您好,我是一個目前在做影像相關研究的學生

    剛好需要模擬魚眼的功能,但這篇code我並無法使用

    問題應該是出在unistd.h以及getopt.h這兩個標頭檔上

    請問在windows環境下有沒有什麼解決辦法?

    在此先感謝您的撥空回答

隨意留個言吧:)~

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料

標籤雲