coral / mtk-gstreamer / 91b88d3b7034812607e53de0f669830b7e5f6868 / . / docs / random / vis-transform

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