gstreamer/docs/random/vis-transform

79 lines
3.4 KiB
Text
Raw Normal View History

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.
Unfortunately, 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.