首页 > 解决方案 > Eliminate skewing effect in combined track and zoom

问题描述

I am writing for HTML5 Canvas, using it as a viewport on which I maintain a central origin and zoom level. I want to track and zoom to a region, but have encountered a naturally occurring effect that spoils the look I am trying to obtain. This question concerns how I might mitigate this while preserving a natural-looking effect.

Imagine I have a downwards-pointing camera mounted on the ceiling, and somewhere on the floor is a piece of paper. I move the camera at a constant speed along the ceiling until it is above the paper, while zooming at a linear rate so that the paper will eventually fill the rendered image. These actions occur simultaneously.

When doing this, an effect can be observed whereby the paper slides out of frame before it returns to centre. This is probably best explained visually, and kept to two dimensions:

img

This is not a good look. Consider the user requesting focus on something. Their conceptualization is that the entity is moving into view, and it is strange, then, that it appears to first move away before it comes closer.

The effect I wish for is of the target object only approaching the centre of the frame, and never retreating. I suppose the answer is to deform the rate of zoom somehow (or the rate of movement, though I would not prefer this) presumably as a function of the distances involved, or artificially adjust the zoom so the page is kept in frame. I would prefer help towards a solution along the lines of the former approach.


Update:

I think one answer might be to split the zoom part of the operation into two phases. Let the parameters of the problem inform a derivative function that yields the distance between the centres of target and viewport on the rendered output, and find the time at which this is the maximum. Do this for both axes and pick a time between the two: this is the boundary of the zoom phases. In the first phase, zoom to fit the paper just inside the boundary of the image. In the second phase, zoom to the paper to give the same result as before.

This intuitively seems better, but I still have two problems. I can doubtless find the equation for d at t, but my calculus is weak and I might end up sampling for the maximum rather than produce an inverse function to find it, which is what I'd really prefer. I also am not sure how to choose between the two maxima for finding the boundary time (although it may be that there is no 'right' answer to this question, and it is less of a worry to me). Any help with either problem, or any other insight into the broader challenge, will be very gratefully received.

标签: graphicsimage-rendering

解决方案


Ow so you got an SW implementation no HW camera involved ....

I was referring to the real skew effect in English called Rolling shutter: if you are obtaining image by moving real HW scanline camera (without TDI technology) then a skew+blur effect is appearing sliding the scan lines ... try to make a photo from a side window of a moving car the image will get skewed.

The effect you are describing has nothing to do with skew its just a mathematical "singularity" sorry I do not have any name therm for it.

As your camera is SW only you can affect both pan and zoom to your liking so I would just compute the zoom from camera FOV and pan position. I see it like this:

overview

So:

 I. a = FOV / zoom
II. tan(0.5*a) = (x1-x0) / h
------------------------
zoom = 0.5*FOV/atan( (x1-x0) / h )

Where h is the ceiling height, x0 is the camera (pan) position, x0 is paper edge position and FOV is field of view of your non zoomed camera...

[edit1] sliding the paper in and animation...

I ended up with this:

animation

Here the C++/VCL code for this:

//---------------------------------------------------------------------------
double x0,x1,w=50,h=200,FOVx=60.0*M_PI/180.0,zoom,pan;
double t=0; // animation parameter <0,1>
//---------------------------------------------------------------------------
void TMain::draw()
    {
    if (!_redraw) return;

    // clear buffer
    bmp->Canvas->Brush->Color=clBlack;
    bmp->Canvas->FillRect(TRect(0,0,xs,ys));

    double y0,y1,dx;

    // position side view onto screen based on its size xs,ys
    y0=0.5*(ys-h);
    y1=y0+h;
    x0=0.5*xs;
    x1=x0+(h*tan(0.5*FOVx));
    // compute zoom,pan from t
    pan=(x1-x0+(0.5*w))*t;
    zoom=0.5*FOVx/atan(((1.0-t)*(x1-x0)+(0.5*w*t))/h);
    // scene
    bmp->Canvas->Pen->Color=clBlue;
    bmp->Canvas->MoveTo( 0,y0);
    bmp->Canvas->LineTo(xs,y0);
    bmp->Canvas->MoveTo( 0,y1);
    bmp->Canvas->LineTo(xs,y1);
    // paper
    bmp->Canvas->Pen->Color=clRed;
    bmp->Canvas->MoveTo(x1,y1);
    bmp->Canvas->LineTo(x1+w,y1);
    // FOVx
    dx=h*tan(0.5*FOVx/zoom);
    bmp->Canvas->Pen->Color=clAqua;
    bmp->Canvas->MoveTo(x0+pan-dx,y1);
    bmp->Canvas->LineTo(x0+pan,y0);
    bmp->Canvas->LineTo(x0+pan+dx,y1);
    // points
    dx=4;
    bmp->Canvas->Pen->Color=clAqua;
    bmp->Canvas->Brush->Color=clBlue;
    bmp->Canvas->Ellipse(x0-dx,y0-dx,x0+dx,y0+dx);
    bmp->Canvas->Ellipse(x0+pan-dx,y0-dx,x0+pan+dx,y0+dx);
    bmp->Canvas->Ellipse(x1-dx,y1-dx,x1+dx,y1+dx);
    bmp->Canvas->Font->Color=clYellow;
    bmp->Canvas->Brush->Style=bsClear;
    bmp->Canvas->TextOutA(x0,y0-20,"x0");
    bmp->Canvas->TextOutA(x0+pan+20,y0+5,"x0+pan");
    bmp->Canvas->TextOutA(x1,y1+5,"x1");
    bmp->Canvas->Brush->Style=bsSolid;

    // render backbuffer
    Main->Canvas->Draw(0,0,bmp);
    _redraw=false;
    }
//---------------------------------------------------------------------------

If you ignore the rendering stuff this is what is important for you:

pan=(x1-x0+(0.5*w))*t;
zoom=0.5*FOVx/atan(((1.0-t)*(x1-x0)+(0.5*w*t))/h);

So I slightly changed the meaning of x1 (its the other edge of paper) and instead of x1 in the original equations above I used x1+w*t which means that the paper is not in view at start (t=0) but its touching it from outside and it is fully in view when (t=1). The rest is just the result of the substitution ...

The w is the paper width, t=<0.0,1.0> is the animation parameter and all the other values did not change meaning...

The animation is just incrementing the t by 0.02 in 150ms timer recorded by my GIF encoder (that is why its so choppy)


推荐阅读