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.
308 lines
5.8 KiB
308 lines
5.8 KiB
15 years ago
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
}
|
||
|
|