Ask Your Question
0

Creation of images with warp/distortion due to natural effects on camera lens.

asked 2015-03-10 10:35:51 -0600

Potato gravatar image

I am trying to take an image stream and make the images appear as though they have been taken from a relatively simple camera like a CCD camera. I have added some Gaussian and salt pepper noise to give it a 'normal' look.

My next step is to warp the images or distort them. In real time this could happen due to temperature changes and lens defects of the camera. My goal is to artificially recreate this. Note that the distortion would be extremely minimal but present nonetheless. Ideally, I would like the distortion to be per image in the stream and over the sequence of images as well.

So far I have tried using perspectiveTransform( ) and warpPerspective( ), but I cannot seem to get the right parameter adjustments. Can anyone help me with this? I have also thought of using the fish-eye but could only find OpenCV functions that 'undistort' or fix fish-eye image distortion and nothing that would add a fish eye distortion.

Any thoughts or ideas on other approaches I could take to solve this problem? Thank you.

edit retag flag offensive close merge delete

Comments

Can you provide more information: what is "I cannot seem to get the right parameter adjustments"?

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-03-10 10:47:07 -0600 )edit

By this I mean that the perspective transform when applied to the image, I cannot get it to transform minimally. The change is too large. I am not even sure that this approach is the right one.

Potato gravatar imagePotato ( 2015-03-10 11:02:49 -0600 )edit

here in the second answer there is some code that simulates the fisheye distortion. It is in the old C api but I don't think that it would be that hard to port it to the new C++. If I find some time, maybe I will try to do it myself.

theodore gravatar imagetheodore ( 2015-03-10 14:00:44 -0600 )edit

Thank you, I did find that link while researching but abandoned it for the same reason. (It was in the old C api) But it does seem to work and I will try to port it to c++ as well.

Potato gravatar imagePotato ( 2015-03-10 15:20:44 -0600 )edit

1 answer

Sort by » oldest newest most voted
4

answered 2015-03-14 15:07:29 -0600

theodore gravatar image

updated 2015-03-14 15:17:31 -0600

As I said since I found some time here is the port from the old C api to C++. In case also that someone will need it in the future:

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

using namespace std;
using namespace cv;

float calc_shift(float x1,float x2,float cx,float k)
{
    float thresh = 1;
    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);
  }
}

float getRadialX(float x,float y,float cx,float cy,float k, bool scale, Vec4f props)
{
    float result;
    if(scale)
    {
        float xshift = props[0];
        float yshift = props[1];
        float xscale = props[2];
        float yscale = props[3];

        x = (x*xscale+xshift);
        y = (y*yscale+yshift);
        result = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
    }else{
//        result = (cx+(x-cx)*(1+k*((x-cx)*(x-cx)+(y-cy)*(y-cy))));
//        or
        result = x+((x-cx)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
    }
    return result;
}

float getRadialY(float x,float y,float cx,float cy,float k, bool scale, Vec4f props)
{
    float result;
    if(scale)
    {
        float xshift = props[0];
        float yshift = props[1];
        float xscale = props[2];
        float yscale = props[3];

        x = (x*xscale+xshift);
        y = (y*yscale+yshift);
        result = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
    }else{
//        result = (cy+(y-cy)*(1+k*((x-cx)*(x-cx)+(y-cy)*(y-cy))));
//        or
        result = y+((y-cy)*k*((x-cx)*(x-cx)+(y-cy)*(y-cy)));
    }
    return result;
}

// Cx and Cy specify the coordinates from where the distorted image will have as initial point and 
// k specifies the distortion factor
void fishEye(InputArray _src, OutputArray _dst, double Cx, double Cy, double k, bool scale = true)
{
    // die if distortion parameters are not correct
    CV_Assert(Cx >= 0 && Cy >= 0 && k >= 0);

    Mat src = _src.getMat();
    // die if sample image is not the correct type
    //CV_Assert(src.type() == CV_8UC1 || src.type() == CV_8UC3);

    Mat mapx = Mat(src.size(), CV_32FC1);
    Mat mapy = Mat(src.size(), CV_32FC1);

    int w = src.cols;
    int h = src.rows;

    Vec4f props;
    float xShift = calc_shift(0, Cx - 1, Cx, k);
    props[0] = xShift;
    float newCenterX = w - Cx;
    float xShift2 = calc_shift(0, newCenterX - 1, newCenterX, k);

    float yShift = calc_shift(0, Cy - 1, Cy, k);
    props[1] = yShift;
    float newCenterY = w - Cy;
    float yShift2 = calc_shift(0, newCenterY - 1, newCenterY, k);

    float xScale = (w - xShift - xShift2) / w;
    props[2] = xScale;
    float yScale = (h - yShift - yShift2) / h;
    props[3] = yScale;

    float* p = mapx.ptr<float>(0);

    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {
            *p++ = getRadialX((float)x, (float)y, Cx, Cy, k, scale, props);
        }
    }

    p = mapy.ptr<float>(0);
    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {
            *p++ = getRadialY((float)x, (float)y, Cx, Cy, k, scale, props);
        }
    }

    remap(src, _dst, mapx, mapy, CV_INTER_LINEAR, BORDER_CONSTANT);

//    Mat(src).copyTo(_dst);
}

int main()
{
    Mat input = imread("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);

    if(!input.data || input.empty())
        cout << "Problem loading ...
(more)
edit flag offensive delete link more

Comments

laubsägearbeit ;9

berak gravatar imageberak ( 2015-03-14 15:41:54 -0600 )edit

@berak ????? (google translate did not help that much, :-p)

theodore gravatar imagetheodore ( 2015-03-14 16:08:58 -0600 )edit

translate it as : using a very fine tool to saw out the details

berak gravatar imageberak ( 2015-03-14 16:20:36 -0600 )edit

I see ;-)

theodore gravatar imagetheodore ( 2015-03-14 16:32:06 -0600 )edit

Thank you @theodore! This helps a lot!

Potato gravatar imagePotato ( 2015-03-16 09:03:28 -0600 )edit

@theodore at line if(res1>-thresh and res1 < thresh) it is && I think

LBerger gravatar imageLBerger ( 2015-10-05 04:00:59 -0600 )edit

@LBerger you can use the and keyword as an alternative for &&, source. It is the same for other keywords and operators as well ;-)

theodore gravatar imagetheodore ( 2015-10-05 05:23:50 -0600 )edit

I didn't know it. With visual studio 2013 (french version) it does not work. But it seems that it was introduced due to langauge problem

LBerger gravatar imageLBerger ( 2015-10-05 05:56:51 -0600 )edit

with the gcc here it works perfectly. It seems you learned something new today :-p

theodore gravatar imagetheodore ( 2015-10-05 07:23:49 -0600 )edit

Can any one explain the algorithm behind fisheye effect ! I didn't get the logic behind it.. :\

jukukulidr gravatar imagejukukulidr ( 2017-03-14 07:59:26 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2015-03-10 10:35:51 -0600

Seen: 4,561 times

Last updated: Mar 14 '15