You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mlt/src/modules/effectv/image.c

308 lines
5.8 KiB

/*
* EffecTV - Realtime Digital Video Effector
* Copyright (C) 2001-2006 FUKUCHI Kentaro
*
* image.c: utilities for image processing.
*
*/
#include <string.h>
#include <stdlib.h>
#include "utils.h"
/*
* Collection of background subtraction functions
*/
/* checks only fake-Y value */
/* In these function Y value is treated as R*2+G*4+B. */
int image_set_threshold_y(int threshold)
{
int y_threshold = threshold * 7; /* fake-Y value is timed by 7 */
return y_threshold;
}
void image_bgset_y(RGB32 *background, const RGB32 *src, int video_area, int y_threshold)
{
int i;
int R, G, B;
const RGB32 *p;
short *q;
p = src;
q = (short *)background;
for(i=0; i<video_area; i++) {
/* FIXME: endianess */
R = ((*p)&0xff0000)>>(16-1);
G = ((*p)&0xff00)>>(8-2);
B = (*p)&0xff;
*q = (short)(R + G + B);
p++;
q++;
}
}
void image_bgsubtract_y(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, int y_threshold)
{
int i;
int R, G, B;
const RGB32 *p;
short *q;
unsigned char *r;
int v;
p = src;
q = (short *)background;
r = diff;
for(i=0; i<video_area; i++) {
/* FIXME: endianess */
R = ((*p)&0xff0000)>>(16-1);
G = ((*p)&0xff00)>>(8-2);
B = (*p)&0xff;
v = (R + G + B) - (int)(*q);
*r = ((v + y_threshold)>>24) | ((y_threshold - v)>>24);
p++;
q++;
r++;
}
/* The origin of subtraction function is;
* diff(src, dest) = (abs(src - dest) > threshold) ? 0xff : 0;
*
* This functions is transformed to;
* (threshold > (src - dest) > -threshold) ? 0 : 0xff;
*
* (v + threshold)>>24 is 0xff when v is less than -threshold.
* (v - threshold)>>24 is 0xff when v is less than threshold.
* So, ((v + threshold)>>24) | ((threshold - v)>>24) will become 0xff when
* abs(src - dest) > threshold.
*/
}
/* Background image is refreshed every frame */
void image_bgsubtract_update_y(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, int y_threshold)
{
int i;
int R, G, B;
const RGB32 *p;
short *q;
unsigned char *r;
int v;
p = src;
q = (short *)background;
r = diff;
for(i=0; i<video_area; i++) {
/* FIXME: endianess */
R = ((*p)&0xff0000)>>(16-1);
G = ((*p)&0xff00)>>(8-2);
B = (*p)&0xff;
v = (R + G + B) - (int)(*q);
*q = (short)(R + G + B);
*r = ((v + y_threshold)>>24) | ((y_threshold - v)>>24);
p++;
q++;
r++;
}
}
/* checks each RGB value */
/* The range of r, g, b are [0..7] */
RGB32 image_set_threshold_RGB(int r, int g, int b)
{
unsigned char R, G, B;
RGB32 rgb_threshold;
R = G = B = 0xff;
R = R<<r;
G = G<<g;
B = B<<b;
rgb_threshold = (RGB32)(R<<16 | G<<8 | B);
return rgb_threshold;
}
void image_bgset_RGB(RGB32 *background, const RGB32 *src, int video_area)
{
int i;
RGB32 *p;
p = background;
for(i=0; i<video_area; i++) {
*p++ = (*src++) & 0xfefefe;
}
}
void image_bgsubtract_RGB(unsigned char *diff, const RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold)
{
int i;
const RGB32 *p, *q;
unsigned a, b;
unsigned char *r;
p = src;
q = background;
r = diff;
for(i=0; i<video_area; i++) {
a = (*p++)|0x1010100;
b = *q++;
a = a - b;
b = a & 0x1010100;
b = b - (b>>8);
b = b ^ 0xffffff;
a = a ^ b;
a = a & rgb_threshold;
*r++ = (0 - a)>>24;
}
}
void image_bgsubtract_update_RGB(unsigned char *diff, RGB32 *background, const RGB32 *src, int video_area, RGB32 rgb_threshold)
{
int i;
const RGB32 *p;
RGB32 *q;
unsigned a, b;
unsigned char *r;
p = src;
q = background;
r = diff;
for(i=0; i<video_area; i++) {
a = *p|0x1010100;
b = *q&0xfefefe;
*q++ = *p++;
a = a - b;
b = a & 0x1010100;
b = b - (b>>8);
b = b ^ 0xffffff;
a = a ^ b;
a = a & rgb_threshold;
*r++ = (0 - a)>>24;
}
}
/* noise filter for subtracted image. */
void image_diff_filter(unsigned char *diff2, const unsigned char *diff, int width, int height)
{
int x, y;
const unsigned char *src;
unsigned char *dest;
unsigned int count;
unsigned int sum1, sum2, sum3;
src = diff;
dest = diff2 + width +1;
for(y=1; y<height-1; y++) {
sum1 = src[0] + src[width] + src[width*2];
sum2 = src[1] + src[width+1] + src[width*2+1];
src += 2;
for(x=1; x<width-1; x++) {
sum3 = src[0] + src[width] + src[width*2];
count = sum1 + sum2 + sum3;
sum1 = sum2;
sum2 = sum3;
*dest++ = (0xff*3 - count)>>24;
src++;
}
dest += 2;
}
}
/* Y value filters */
void image_y_over(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold)
{
int i;
int R, G, B, v;
unsigned char *p = diff;
for(i = video_area; i>0; i--) {
R = ((*src)&0xff0000)>>(16-1);
G = ((*src)&0xff00)>>(8-2);
B = (*src)&0xff;
v = y_threshold - (R + G + B);
*p = (unsigned char)(v>>24);
src++;
p++;
}
}
void image_y_under(unsigned char *diff, const RGB32 *src, int video_area, int y_threshold)
{
int i;
int R, G, B, v;
unsigned char *p = diff;
for(i = video_area; i>0; i--) {
R = ((*src)&0xff0000)>>(16-1);
G = ((*src)&0xff00)>>(8-2);
B = (*src)&0xff;
v = (R + G + B) - y_threshold;
*p = (unsigned char)(v>>24);
src++;
p++;
}
}
/* tiny edge detection */
void image_edge(unsigned char *diff2, const RGB32 *src, int width, int height, int y_threshold)
{
int x, y;
unsigned char *p, *q;
int r, g, b;
int ar, ag, ab;
int w;
p = (unsigned char *)src;
q = diff2;
w = width * sizeof(RGB32);
for(y=0; y<height - 1; y++) {
for(x=0; x<width - 1; x++) {
b = p[0];
g = p[1];
r = p[2];
ab = abs(b - p[4]);
ag = abs(g - p[5]);
ar = abs(r - p[6]);
ab += abs(b - p[w]);
ag += abs(g - p[w+1]);
ar += abs(r - p[w+2]);
b = ab+ag+ar;
if(b > y_threshold) {
*q = 255;
} else {
*q = 0;
}
q++;
p += 4;
}
p += 4;
*q++ = 0;
}
memset(q, 0, width);
}
/* horizontal flipping */
void image_hflip(const RGB32 *src, RGB32 *dest, int width, int height)
{
int x, y;
src += width - 1;
for(y=0; y<height; y++) {
for(x=0; x<width; x++) {
*dest++ = *src--;
}
src += width * 2;
}
}