mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-16 21:36:35 +00:00
79 lines
3.4 KiB
Text
79 lines
3.4 KiB
Text
|
Duh, an 'easy' way to replicate Giess's behavior:
|
||
|
|
||
|
For each frame, you have to mutate it by a transform matrix. This is
|
||
|
easy, thought not cheap. First you precalculate the transform matrix how
|
||
|
you want it, based on whatever rotations or whatever you want.
|
||
|
|
||
|
The data stored in each spot on the matrix tells you how to transform a
|
||
|
single pixel. The simple case is dx,dy, where both are relatively small.
|
||
|
The probably ought to be a byte in any case, so you can scale the
|
||
|
transform matrix on slow machines. A more complex case is some trick
|
||
|
whereby a single pixel ends up splattered in several places. Idea below.
|
||
|
|
||
|
The matrix consists of some number of 8bit arrays of the same size as the
|
||
|
image. They'd probably be line-interleaved or better to help with cache
|
||
|
effects (which are VERY serious here). Each channel represents some
|
||
|
aspect of the transform. The first two would likely be dx and dy, the
|
||
|
third might be a multiplier if that wasn't done statically.
|
||
|
|
||
|
The idea: any number of transform sets could be applied, given available
|
||
|
processing power. Just set the static scalar or the multiplier matrices
|
||
|
so you don't completely swamp the output pixels.
|
||
|
|
||
|
Note that this is fastest in 8-bit, but theoretically could be applied to
|
||
|
32 bit. 15 and 16 are hard, since you can't easily apply the multipliers
|
||
|
unless they're 1/2^n, and even then it's significantly heavier (you'd have
|
||
|
to mask the top n bits of each color out).
|
||
|
|
||
|
This SCREAMS for MMX, in case you haven't figured it out yet.
|
||
|
Unfortunatley, MMX is only directly useful for the scalar matrix, unless
|
||
|
you do a trick where all the pixels in that fit in 64 bits (8 8bit, 4
|
||
|
16bit, or 2 32bit) are always moved in a group. This is very possible,
|
||
|
and might be a significant perf increase by being able to use MMX all the
|
||
|
way through. Otherwise you have to place each pixel by extracting the MMX
|
||
|
stuff back into normal registers, and that just plain sucks.
|
||
|
|
||
|
A pseudo-C implementation:
|
||
|
|
||
|
----- BEGIN -----
|
||
|
gint x,y; /* image x and y size */
|
||
|
guchar old_image[x][y]; /* original image */
|
||
|
guchar new_image[x][y]; /* new image */
|
||
|
gchar x_xform[x][y]; /* dx matrix */
|
||
|
gchar y_xform[x][y]; /* dy matrix */
|
||
|
guchar s_xform[x][y]; /* intensity scalar matrix */
|
||
|
guchar scalar; /* global scalar */
|
||
|
|
||
|
gint i,j; /* indixes */
|
||
|
gulong p; /* pixel value in question */
|
||
|
guchar u,v,w; /* modifier variables */
|
||
|
|
||
|
/* clear the new image, we don't want anything getting in the way */
|
||
|
/* NOT NECESSARILY A GOOD THING, THOUGH */
|
||
|
memset(new_image,0,x*y);
|
||
|
|
||
|
/* loop through all the lines in the image */
|
||
|
for (j=0;j<y;j++) {
|
||
|
/* loop through all the pixels in the line */
|
||
|
for (i=0;i<x;i++) {
|
||
|
p = old_image[i][j];
|
||
|
u = x_xform[i][j];
|
||
|
v = y_xform[i][j];
|
||
|
w = s_xform[i][j];
|
||
|
new_image[i+u][j+v] = (guchar)((p<<14) / (w * scalar));
|
||
|
}
|
||
|
}
|
||
|
----- END -----
|
||
|
|
||
|
Note that the above really, *REALLY* sucks performance-wise. Throw it a
|
||
|
80x60 image and it'll swamp my poor laptop. Also note that I simply set
|
||
|
the pixel value, not merge it. That means you'd better be sure your
|
||
|
transform matrix doesn't have overlapping destinations.
|
||
|
|
||
|
Other notes about the above code: x_xform and y_xform are signed chars,
|
||
|
which means pixels can move in all directions. The intensity matrix is
|
||
|
unsigned, with a range from 0 to 255, so is the global scalar. Note the
|
||
|
shift of 14bits (2 * 7bits), then divide by each. That means identity for
|
||
|
both scalars is at 128. The FP range of each is thus 0.0 to 2.0. Very
|
||
|
handy.
|