mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-14 11:50:02 +01:00
2018 lines
44 KiB
C
2018 lines
44 KiB
C
/*
|
|
* Linux VeeJay
|
|
*
|
|
* Copyright(C)2002 Niels Elburg <elburg@hio.hen.nl>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License , or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 , USA.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include <math.h>
|
|
#include <libvje/internal.h>
|
|
#include <libvjmem/vjmem.h>
|
|
#include "common.h"
|
|
#ifdef STRICT_CHECKING
|
|
#include <assert.h>
|
|
#endif
|
|
|
|
|
|
extern void veejay_msg(int type, const char format[], ...);
|
|
|
|
char **vje_build_param_list( int num, ... )
|
|
{
|
|
va_list args;
|
|
char **list;
|
|
char *tmp = NULL;
|
|
list = (char**) vj_malloc(sizeof(char*) * (num+1) );
|
|
|
|
va_start( args, num );
|
|
|
|
int i;
|
|
for( i = 0; i <num; i ++ ) {
|
|
tmp = (char*) va_arg( args,char*);
|
|
#ifdef STRICT_CHECKING
|
|
assert( tmp != NULL );
|
|
#endif
|
|
// if(tmp==NULL)
|
|
// continue;
|
|
list[i] = strdup(tmp);
|
|
}
|
|
list[num] = NULL;
|
|
va_end(args);
|
|
return list;
|
|
}
|
|
static inline void linearBlend(unsigned char *src, int stride)
|
|
{
|
|
int x;
|
|
for (x=0; x<8; x++)
|
|
{
|
|
src[0 ] = (src[0 ] + 2*src[stride ] + src[stride*2])>>2;
|
|
src[stride ] = (src[stride ] + 2*src[stride*2] + src[stride*3])>>2;
|
|
src[stride*2] = (src[stride*2] + 2*src[stride*3] + src[stride*4])>>2;
|
|
src[stride*3] = (src[stride*3] + 2*src[stride*4] + src[stride*5])>>2;
|
|
src[stride*4] = (src[stride*4] + 2*src[stride*5] + src[stride*6])>>2;
|
|
src[stride*5] = (src[stride*5] + 2*src[stride*6] + src[stride*7])>>2;
|
|
src[stride*6] = (src[stride*6] + 2*src[stride*7] + src[stride*8])>>2;
|
|
src[stride*7] = (src[stride*7] + 2*src[stride*8] + src[stride*9])>>2;
|
|
|
|
src++;
|
|
}
|
|
//#endif
|
|
}
|
|
|
|
|
|
matrix_t matrix_placementA(int photoindex, int size, int w , int h)
|
|
{
|
|
matrix_t m;
|
|
m.w = (photoindex % size) * (w/size);
|
|
m.h = (photoindex / size) * (h/size);
|
|
return m;
|
|
}
|
|
|
|
matrix_t matrix_placementB(int photoindex, int size, int w , int h)
|
|
{
|
|
matrix_t m;
|
|
m.w = (photoindex/size) * (w/size);
|
|
m.h = (photoindex % size) * (h/size);
|
|
return m;
|
|
}
|
|
|
|
matrix_t matrix_placementC(int photoindex, int size, int w , int h)
|
|
{
|
|
matrix_t m;
|
|
int n = size*size-1;
|
|
m.w = ((n-photoindex) % size) * (w/size);
|
|
m.h = ((n-photoindex) / size) * (h/size);
|
|
return m;
|
|
}
|
|
|
|
matrix_t matrix_placementD(int photoindex, int size, int w , int h)
|
|
{
|
|
matrix_t m;
|
|
int n = size*size-1;
|
|
m.w = ((n-photoindex) / size) * (w/size);
|
|
m.h = ((n-photoindex) % size) * (h/size);
|
|
return m;
|
|
}
|
|
|
|
matrix_f get_matrix_func(int type)
|
|
{
|
|
if(type==0)
|
|
return &matrix_placementA;
|
|
if(type==1)
|
|
return &matrix_placementB;
|
|
if(type==2)
|
|
return &matrix_placementC;
|
|
return &matrix_placementD;
|
|
}
|
|
|
|
|
|
int power_of(int size)
|
|
{
|
|
int power = 1;
|
|
while( size-- )
|
|
power *= 2;
|
|
|
|
return power;
|
|
}
|
|
|
|
int max_power(int w)
|
|
{
|
|
int i=1;
|
|
while(power_of(i) < w)
|
|
i++;
|
|
return i;
|
|
}
|
|
/* some parts (linearBlend() and deinterlace() from :
|
|
*
|
|
* Simple xawtv deinterlacing plugin - linear blend
|
|
*
|
|
* CAVEATS: Still some interlacing effects in high motion perhaps
|
|
* Some ghosting in instant transitions, slightly noticeable
|
|
*
|
|
* BENEFITS: NO DROP IN FRAMERATE =]
|
|
* Looks absolutely beautiful
|
|
* Doesn't lower framerate
|
|
* Oh and did I mention it doesn't lower framerate?
|
|
* Plus, its MMX'itized now, so it really doesn't lower framerate.
|
|
*
|
|
* AUTHORS:
|
|
* Conrad Kreyling <conrad@conrad.nerdland.org>
|
|
* Patrick Barrett <yebyen@nerdland.org>
|
|
*
|
|
* This is licenced under the GNU GPL until someone tells me I'm stealing code
|
|
* and can't do that ;) www.gnu.org for any version of the license.
|
|
*
|
|
* Based on xawtv-3.72/libng/plugins/flt-nop.c (also GPL)
|
|
* Linear blend deinterlacing algorithm adapted from mplayer's libpostproc
|
|
*/
|
|
|
|
|
|
|
|
void deinterlace(uint8_t *data, int w, int h, int v)
|
|
{
|
|
int x,y;
|
|
uint8_t *src;
|
|
for(y=1; y < h-8; y+=8)
|
|
{
|
|
for(x=0; x < w; x+=8)
|
|
{
|
|
src = data + x + y * w;
|
|
linearBlend(src, w);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void frameborder_yuvdata(uint8_t * input_y, uint8_t * input_u,
|
|
uint8_t * input_v, uint8_t * putin_y,
|
|
uint8_t * putin_u, uint8_t * putin_v, int width,
|
|
int height, int top, int bottom, int left,
|
|
int right, int shift_h, int shift_v)
|
|
{
|
|
|
|
int line, x;
|
|
int input_active_width;
|
|
int input_active_height;
|
|
uint8_t *rightvector;
|
|
shift_h = 0;
|
|
shift_v = 0;
|
|
input_active_height = height - top - bottom;
|
|
input_active_width = width - left - right;
|
|
|
|
/* Y component TOP */
|
|
for (line = 0; line < top; line++) {
|
|
for (x = 0; x < width; x++) {
|
|
*(input_y + x) = *(putin_y + x);
|
|
}
|
|
//memcpy (input_y, putin_y, width);
|
|
input_y += width;
|
|
putin_y += width;
|
|
}
|
|
rightvector = input_y + left + input_active_width;
|
|
/* Y component LEFT AND RIGHT */
|
|
for (line = 0; line < input_active_height; line++) {
|
|
for (x = 0; x < left; x++) {
|
|
*(input_y + x) = *(putin_y + x);
|
|
}
|
|
//memcpy (input_y, putin_y, left);
|
|
for (x = 0; x < right; x++) {
|
|
*(rightvector + x) =
|
|
*(putin_y + left + input_active_width + x);
|
|
}
|
|
//memcpy (rightvector, putin_y + left + input_active_width, right);
|
|
input_y += width;
|
|
rightvector += width;
|
|
putin_y += width;
|
|
}
|
|
/* Y component BOTTOM */
|
|
for (line = 0; line < bottom; line++) {
|
|
for (x = 0; x < width; x++)
|
|
*(input_y + x) = *(putin_y + x);
|
|
|
|
//memcpy (input_y, putin_y, width);
|
|
input_y += width;
|
|
putin_y += width;
|
|
}
|
|
|
|
|
|
/* U component TOP */
|
|
for (line = 0; line < (top >> shift_v); line++) {
|
|
for (x = 0; x < (width >> shift_h); x++) {
|
|
*(input_u + x) = *(putin_u + x);
|
|
}
|
|
//memcpy (input_u, putin_u, width >> 1);
|
|
input_u += width >> shift_h;
|
|
putin_u += width >> shift_h;
|
|
}
|
|
|
|
rightvector = input_u + ((left + input_active_width) >> shift_h);
|
|
for (line = 0; line < (input_active_height >> shift_v); line++) {
|
|
//memcpy (input_u, putin_u, left >> 1);
|
|
for (x = 0; x < (left >> shift_h); x++) {
|
|
*(input_u + x) = *(putin_u + x);
|
|
}
|
|
//memcpy (rightvector, putin_u + ((left + input_active_width)>>1) , right >> 1);
|
|
for (x = 0; x < (right >> shift_h); x++) {
|
|
*(rightvector + x) = *(putin_u +
|
|
((left + input_active_width + x) >> shift_h));
|
|
|
|
}
|
|
input_u += width >> shift_h;
|
|
rightvector += width >> shift_h;
|
|
putin_u += width >> shift_h;
|
|
}
|
|
|
|
for (line = 0; line < (bottom >> shift_v); line++) {
|
|
for (x = 0; x < (width >> shift_h); x++)
|
|
*(input_u + x) = *(putin_u + x);
|
|
//memcpy (input_u, putin_u, width >> 1);
|
|
input_u += width >> shift_h;
|
|
putin_u += width >> shift_h;
|
|
}
|
|
|
|
/* V component Top */
|
|
for (line = 0; line < (top >> shift_v); line++) {
|
|
//memcpy (input_v, putin_v, width >> 1);
|
|
for (x = 0; x < (width >> shift_h); x++) {
|
|
*(input_v + x) = *(putin_v + x);
|
|
}
|
|
input_v += width >> shift_h;
|
|
putin_v += width >> shift_h;
|
|
}
|
|
/* Left and Right */
|
|
rightvector = input_v + ((left + input_active_width) >> shift_h);
|
|
for (line = 0; line < (input_active_height >> shift_v); line++) {
|
|
for (x = 0; x < (left >> shift_h); x++)
|
|
*(input_v + x) = *(putin_v + x);
|
|
|
|
//memcpy (input_v, putin_v, left >> 1);
|
|
//memcpy (rightvector, putin_v + ((left+input_active_width)>>1), right >> 1);
|
|
for (x = 0; x < (right >> shift_h); x++)
|
|
*(rightvector + x) =
|
|
*(putin_v + ((left + input_active_width + x) >> shift_h));
|
|
|
|
input_v += width >> shift_h;
|
|
rightvector += width >> shift_h;
|
|
putin_v += width >> shift_h;
|
|
}
|
|
/* Bottom */
|
|
for (line = 0; line < (bottom >> shift_v); line++) {
|
|
//memcpy (input_v, putin_v, width >> 1);
|
|
for (x = 0; x < (width >> shift_h); x++)
|
|
*(input_v + x) = *(putin_v + x);
|
|
input_v += width >> shift_h;
|
|
putin_v += width >> shift_h;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**********************************************************************************************
|
|
*
|
|
* frameborder_yuvdata, based upon blackborder_yuvdata.
|
|
* instead of making the borders black, fill it with pixels coming from the second YUV420 frame.
|
|
**********************************************************************************************/
|
|
void ffframeborder_yuvdata(uint8_t * input_y, uint8_t * input_u,
|
|
uint8_t * input_v, uint8_t * putin_y,
|
|
uint8_t * putin_u, uint8_t * putin_v, int width,
|
|
int height, int top, int bottom, int left,
|
|
int right, int wshift, int hshift)
|
|
{
|
|
|
|
int line, x;
|
|
int input_active_width = (height - top - bottom);
|
|
int input_active_height = (width - left -right);
|
|
uint8_t *rightvector;
|
|
int uv_top = top >> hshift;
|
|
int uv_bottom = bottom >> hshift;
|
|
int uv_left = left >> wshift;
|
|
int uv_right = right >> wshift;
|
|
int uv_width = width >> wshift;
|
|
int uv_height = height >> hshift;
|
|
int uv_input_active_height = uv_height - uv_top - uv_bottom;
|
|
int uv_input_active_width = uv_width - uv_left - uv_right;
|
|
|
|
/* Y component TOP */
|
|
|
|
if(top)
|
|
{
|
|
for (line = 0; line < top; line++) {
|
|
for (x = 0; x < width; x++) {
|
|
*(input_y + x) = *(putin_y + x);
|
|
}
|
|
//memcpy (input_y, putin_y, width);
|
|
input_y += width;
|
|
putin_y += width;
|
|
}
|
|
}
|
|
|
|
if(left && right)
|
|
{
|
|
rightvector = input_y + left + input_active_width;
|
|
/* Y component LEFT AND RIGHT */
|
|
for (line = 0; line < input_active_height; line++) {
|
|
for (x = 0; x < left; x++) {
|
|
*(input_y + x) = *(putin_y + x);
|
|
}
|
|
//memcpy (input_y, putin_y, left);
|
|
for (x = 0; x < right; x++) {
|
|
*(rightvector + x) =
|
|
*(putin_y + left + input_active_width + x);
|
|
}
|
|
//memcpy (rightvector, putin_y + left + input_active_width, right);
|
|
input_y += width;
|
|
rightvector += width;
|
|
putin_y += width;
|
|
}
|
|
}
|
|
|
|
|
|
/* Y component BOTTOM */
|
|
if(bottom)
|
|
{
|
|
for (line = 0; line < bottom; line++) {
|
|
for (x = 0; x < width; x++)
|
|
*(input_y + x) = *(putin_y + x);
|
|
|
|
//memcpy (input_y, putin_y, width);
|
|
input_y += width;
|
|
putin_y += width;
|
|
}
|
|
}
|
|
|
|
|
|
/* U V components */
|
|
/* U component TOP */
|
|
|
|
if(uv_top)
|
|
{
|
|
for (line = 0; line < uv_top; line++)
|
|
{
|
|
for (x = 0; x < uv_width; x++)
|
|
{
|
|
*(input_u + x) = *(putin_u + x);
|
|
}
|
|
input_u += uv_width;
|
|
putin_u += uv_width;
|
|
}
|
|
}
|
|
|
|
|
|
if(left && right)
|
|
{
|
|
rightvector = input_u + uv_left + uv_input_active_width;
|
|
for (line = 0; line < uv_input_active_height; line++)
|
|
{
|
|
//memcpy (input_u, putin_u, left >> 1);
|
|
for (x = 0; x < uv_left; x++)
|
|
{
|
|
*(input_u + x) = *(putin_u + x);
|
|
}
|
|
//memcpy (rightvector, putin_u + ((left + input_active_width)>>1) , right >> 1);
|
|
for (x = 0; x < uv_right; x++)
|
|
{
|
|
*(rightvector + x) = *(putin_u +
|
|
uv_left + uv_input_active_width + x );
|
|
|
|
}
|
|
input_u += uv_width;
|
|
rightvector += uv_width;
|
|
putin_u += uv_width;
|
|
}
|
|
}
|
|
|
|
if(uv_bottom)
|
|
{
|
|
for (line = 0; line < uv_bottom; line++)
|
|
{
|
|
for (x = 0; x < uv_width; x++)
|
|
*(input_u + x) = *(putin_u + x);
|
|
input_u += uv_width;
|
|
putin_u += uv_width;
|
|
}
|
|
}
|
|
|
|
/* V component Top */
|
|
if(uv_top)
|
|
{
|
|
for (line = 0; line < uv_top; line++)
|
|
{
|
|
for (x = 0; x < uv_width; x++)
|
|
*(input_v + x) = *(putin_v + x);
|
|
input_v += uv_width;
|
|
putin_v += uv_width;
|
|
}
|
|
}
|
|
|
|
if(uv_left && uv_right)
|
|
{
|
|
/* Left and Right */
|
|
rightvector = input_v + uv_left + uv_input_active_width;
|
|
for (line = 0; line < uv_input_active_height; line++)
|
|
{
|
|
for (x = 0; x < uv_left; x++)
|
|
*(input_v + x) = *(putin_v + x);
|
|
|
|
for (x = 0; x < uv_right; x++)
|
|
*(rightvector + x) =
|
|
*(putin_v + uv_left + uv_input_active_width + x);
|
|
|
|
input_v += uv_width;
|
|
rightvector += uv_width;
|
|
putin_v += uv_width;
|
|
|
|
}
|
|
}
|
|
|
|
if(uv_bottom)
|
|
{
|
|
/* Bottom */
|
|
for (line = 0; line < uv_bottom; line++) {
|
|
for (x = 0; x < uv_width; x++)
|
|
*(input_v + x) = *(putin_v + x);
|
|
input_v += uv_width;
|
|
putin_v += uv_width;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void blackborder_yuvdata(uint8_t * input_y, uint8_t * input_u,
|
|
uint8_t * input_v, int width, int height, int top,
|
|
int bottom, int left, int right, int wshift, int hshift, int color)
|
|
{
|
|
int line, x;
|
|
int input_active_width;
|
|
int input_active_height;
|
|
uint8_t *rightvector;
|
|
uint8_t colorY = bl_pix_get_color_y(color);
|
|
uint8_t colorCb= bl_pix_get_color_cb(color);
|
|
uint8_t colorCr= bl_pix_get_color_cr(color);
|
|
input_active_height = height - top - bottom;
|
|
input_active_width = width - left - right;
|
|
|
|
/* Y component TOP */
|
|
for (line = 0; line < top; line++) {
|
|
for (x = 0; x < width; x++) {
|
|
*(input_y + x) = colorY;
|
|
}
|
|
//memcpy (input_y, putin_y, width);
|
|
input_y += width;
|
|
}
|
|
rightvector = input_y + left + input_active_width;
|
|
/* Y component LEFT AND RIGHT */
|
|
for (line = 0; line < input_active_height; line++) {
|
|
for (x = 0; x < left; x++) {
|
|
*(input_y + x) = colorY;
|
|
}
|
|
//memcpy (input_y, putin_y, left);
|
|
for (x = 0; x < right; x++) {
|
|
*(rightvector + x) = colorY;
|
|
}
|
|
//memcpy (rightvector, putin_y + left + input_active_width, right);
|
|
input_y += width;
|
|
rightvector += width;
|
|
}
|
|
/* Y component BOTTOM */
|
|
for (line = 0; line < bottom; line++) {
|
|
for (x = 0; x < width; x++)
|
|
*(input_y + x) = colorY;
|
|
|
|
//memcpy (input_y, putin_y, width);
|
|
input_y += width;
|
|
}
|
|
|
|
|
|
/* U component TOP */
|
|
for (line = 0; line < (top >> hshift); line++) {
|
|
for (x = 0; x < (width >> wshift); x++) {
|
|
*(input_u + x) = colorCb;
|
|
}
|
|
//memcpy (input_u, putin_u, width >> 1);
|
|
input_u += width >> wshift;
|
|
}
|
|
|
|
rightvector = input_u + ((left + input_active_width) >> wshift);
|
|
for (line = 0; line < (input_active_height >> hshift); line++) {
|
|
//memcpy (input_u, putin_u, left >> 1);
|
|
for (x = 0; x < (left >> wshift); x++) {
|
|
*(input_u + x) = colorCb;
|
|
}
|
|
//memcpy (rightvector, putin_u + ((left + input_active_width)>>1) , right >> 1);
|
|
for (x = 0; x < (right >> wshift); x++) {
|
|
*(rightvector + x) = colorCb;
|
|
}
|
|
input_u += width >> wshift;
|
|
rightvector += width >> wshift;
|
|
}
|
|
|
|
for (line = 0; line < (bottom >> hshift); line++) {
|
|
for (x = 0; x < (width >> wshift); x++)
|
|
*(input_u + x) = colorCb;
|
|
//memcpy (input_u, putin_u, width >> 1);
|
|
input_u += width >> wshift;
|
|
}
|
|
|
|
/* V component Top */
|
|
for (line = 0; line < (top >> hshift); line++) {
|
|
//memcpy (input_v, putin_v, width >> 1);
|
|
for (x = 0; x < (width >> wshift); x++) {
|
|
*(input_v + x) = colorCr;
|
|
}
|
|
input_v += width >> wshift;
|
|
}
|
|
/* Left and Right */
|
|
rightvector = input_v + ((left + input_active_width) >> wshift);
|
|
for (line = 0; line < (input_active_height >> hshift); line++) {
|
|
for (x = 0; x < (left >> wshift); x++)
|
|
*(input_v + x) = colorCr;
|
|
|
|
//memcpy (input_v, putin_v, left >> 1);
|
|
//memcpy (rightvector, putin_v + ((left+input_active_width)>>1), right >> 1);
|
|
for (x = 0; x < (right >> wshift); x++)
|
|
*(rightvector + x) =colorCr;
|
|
|
|
input_v += width >> wshift;
|
|
rightvector += width >> wshift;
|
|
}
|
|
/* Bottom */
|
|
for (line = 0; line < (bottom >> hshift); line++) {
|
|
//memcpy (input_v, putin_v, width >> 1);
|
|
for (x = 0; x < (width >> wshift); x++)
|
|
*(input_v + x) = colorCr;
|
|
input_v += width >> wshift;
|
|
}
|
|
}
|
|
|
|
|
|
// fastrand (C) FUKUCHI, Kentaro (EffectTV)
|
|
unsigned int fastrand(int val)
|
|
{
|
|
return (val = val * 1103516245 + 12345);
|
|
}
|
|
|
|
|
|
/* function to blend luminance pixel */
|
|
pix_func_Y get_pix_func_Y(const int pix_type)
|
|
{
|
|
if (pix_type == 0)
|
|
return &bl_pix_swap_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDDISTORT)
|
|
return &bl_pix_add_distorted_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_SUBDISTORT)
|
|
return &bl_pix_sub_distorted_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_MULTIPLY)
|
|
return &bl_pix_multiply_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_DIVIDE)
|
|
return &bl_pix_divide_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDITIVE)
|
|
return &bl_pix_additive_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_SUBSTRACTIVE)
|
|
return &bl_pix_substract_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_SOFTBURN)
|
|
return &bl_pix_softburn_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_INVERSEBURN)
|
|
return &bl_pix_inverseburn_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_COLORDODGE)
|
|
return &bl_pix_colordodge_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_MULSUB)
|
|
return &bl_pix_mulsub_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_LIGHTEN)
|
|
return &bl_pix_lighten_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_DIFFERENCE)
|
|
return &bl_pix_difference_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_DIFFNEGATE)
|
|
return &bl_pix_diffnegate_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_EXCLUSIVE)
|
|
return &bl_pix_exclusive_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_BASECOLOR)
|
|
return &bl_pix_basecolor_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_FREEZE)
|
|
return &bl_pix_freeze_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_UNFREEZE)
|
|
return &bl_pix_unfreeze_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_HARDLIGHT)
|
|
return &bl_pix_hardlight_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_RELADD)
|
|
return &bl_pix_relativeadd_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_RELSUB)
|
|
return &bl_pix_relativesub_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_MAXSEL)
|
|
return &bl_pix_maxsel_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_MINSEL)
|
|
return &bl_pix_minsel_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_RELADDLUM)
|
|
return &bl_pix_relativeadd_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_RELSUBLUM)
|
|
return &bl_pix_relativesub_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_MINSUBSEL)
|
|
return &bl_pix_minsubsel_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_MAXSUBSEL)
|
|
return &bl_pix_maxsubsel_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDSUBSEL)
|
|
return &bl_pix_addsubsel_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDAVG)
|
|
return &bl_pix_dblbneg_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDTEST2)
|
|
return &bl_pix_dblbneg_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDTEST3)
|
|
return &bl_pix_relneg_Y;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDTEST4)
|
|
return &bl_pix_test3_Y;
|
|
/*
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTMIN) return &bl_pix_minsel_Y;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTMAX) return &bl_pix_maxsel_Y;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTDIFF) return &bl_pix_seldiff_Y;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTDIFFNEG) return &bl_pix_seldiffneg_Y;
|
|
if(pix_type == VJ_EFFECT_BLEND_ADDLUM) return &bl_pix_relativeadd_Y;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTFREEZE) return &bl_pix_selfreeze_Y;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTUNFREEZE) return &bl_pix_selunfreeze_Y;
|
|
*/
|
|
return &bl_pix_noswap_Y;
|
|
}
|
|
|
|
/* function to blend chrominance pixel */
|
|
pix_func_C get_pix_func_C(const int pix_type)
|
|
{
|
|
if (pix_type == 0)
|
|
return &bl_pix_swap_C;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDDISTORT)
|
|
return &bl_pix_add_distorted_C;
|
|
if (pix_type == VJ_EFFECT_BLEND_SUBDISTORT)
|
|
return &bl_pix_sub_distorted_C;
|
|
if (pix_type == VJ_EFFECT_BLEND_RELADD)
|
|
return &bl_pix_relativeadd_C;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDTEST2)
|
|
return &bl_pix_dblbneg_C;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDTEST3)
|
|
return &bl_pix_relneg_C;
|
|
if (pix_type == VJ_EFFECT_BLEND_ADDTEST4)
|
|
return &bl_pix_test3_C;
|
|
/*
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTMAX) return &bl_pix_swap_C;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTDIFF) return &bl_pix_swap_C;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTDIFFNEG) return &bl_pix_swap_C;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTFREEZE) return &bl_pix_swap_C;
|
|
if(pix_type == VJ_EFFECT_BLEND_SELECTUNFREEZE) return &bl_pix_swap_C;
|
|
*/
|
|
return &bl_pix_noswap_C;
|
|
}
|
|
|
|
|
|
/* point arithemetic , these are blending functions. */
|
|
|
|
/* multiply pixel a with pixel b */
|
|
uint8_t bl_pix_multiply_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( (y1 * y2) >> 8);
|
|
}
|
|
/* divide pixel a with pixel b */
|
|
uint8_t bl_pix_divide_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
int c = y1 * y2;
|
|
int b = 0xff - y2;
|
|
if( b <= pixel_Y_lo_ || c <= pixel_Y_lo_ )
|
|
return pixel_Y_lo_;
|
|
return ( c / b );
|
|
}
|
|
|
|
uint8_t bl_pix_additive_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return (y1 + ((2 * y2) - 0xff) );
|
|
}
|
|
|
|
|
|
uint8_t bl_pix_substract_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( y1 + (y2 - 0xff ) );
|
|
}
|
|
|
|
uint8_t bl_pix_softburn_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (a + b < 0xff) {
|
|
if (a > pixel_Y_hi_) {
|
|
new_Y = pixel_Y_hi_;
|
|
} else {
|
|
new_Y = (b >> 7) / (256 - a);
|
|
if (new_Y > pixel_Y_hi_)
|
|
new_Y = pixel_Y_hi_;
|
|
}
|
|
} else {
|
|
new_Y = 0xff - (((0xff - a) >> 7) / b);
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_inverseburn_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (a <= pixel_Y_lo_) {
|
|
new_Y = pixel_Y_lo_;
|
|
} else {
|
|
new_Y = 0xff - (((0xff - b) >> 8) / a);
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
|
|
uint8_t bl_pix_colordodge_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
if(y1 > pixel_Y_hi_ )
|
|
y1 = pixel_Y_hi_;
|
|
return ((y2 >> 8) / (256 - y1));
|
|
}
|
|
|
|
uint8_t bl_pix_mulsub_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b;
|
|
a = y1;
|
|
b = (0xff - y2);
|
|
if( a < 16 )
|
|
a = 16;
|
|
if (b < 16)
|
|
b = 16;
|
|
return ( a / b );
|
|
}
|
|
|
|
uint8_t bl_pix_lighten_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
if (y1 > y2)
|
|
return y1;
|
|
return y2;
|
|
}
|
|
|
|
uint8_t bl_pix_difference_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
new_Y = abs(a - b);
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_diffnegate_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b;
|
|
a = 0xff - y1;
|
|
b = y2;
|
|
return ( 0xff - abs(a - b) );
|
|
}
|
|
|
|
uint8_t bl_pix_exclusive_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( y1 + y2 - ((y1 * y2) >> 8) );
|
|
}
|
|
|
|
|
|
uint8_t bl_pix_basecolor_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, c, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (a < 16)
|
|
a = 16;
|
|
if (b < 16)
|
|
b = 16;
|
|
c = a * b >> 7;
|
|
new_Y = c + a * ((0xff - (((0xff - a) * (0xff - b)) >> 7) - c) >> 7);
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_freeze_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (b < 16) {
|
|
new_Y = 16;
|
|
} else {
|
|
new_Y = 0xff - ((0xff - a) * (0xff - a)) / b;
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_unfreeze_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (a < 16) {
|
|
new_Y = 16;
|
|
} else {
|
|
if(b > 235) b = 235;
|
|
new_Y = 0xff - ((0xff - b) * (0xff - b)) / a;
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_hardlight_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (b < 128) {
|
|
new_Y = (a * b) >> 7;
|
|
} else {
|
|
new_Y = 0xff - ((0xff - b) * (0xff - a) >> 7);
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_relativeadd_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, c, d, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
c = a >> 1;
|
|
d = b >> 1;
|
|
new_Y = c + d;
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_relativeadd_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t new_C;
|
|
new_C = (y1 - y2 + 0xff) >> 1;
|
|
return new_C;
|
|
}
|
|
|
|
uint8_t bl_pix_relativesub_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
new_Y = (a - b + 0xff) >> 1;
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_maxsubsel_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (b > a) {
|
|
new_Y = (b - a + 0xff) >> 1;
|
|
} else {
|
|
new_Y = (a - b + 0xff) >> 1;
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_minsubsel_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (b < a) {
|
|
new_Y = (b - a + 0xff) >> 1;
|
|
} else {
|
|
new_Y = (a - b + 0xff) >> 1;
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_addsubsel_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( (y1 + y2) >> 1 );
|
|
}
|
|
|
|
uint8_t bl_pix_maxsel_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( (y2>y1 ? y2 : y1 ) );
|
|
}
|
|
|
|
uint8_t bl_pix_minsel_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( (y2 < y1 ? y2: y1 ));
|
|
}
|
|
|
|
|
|
uint8_t bl_pix_dblbneg_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( (y1 + (y2 << 1 ) - 0xff ) );
|
|
}
|
|
|
|
uint8_t bl_pix_dblbneg_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( (y1 + (y2 << 1 ) - 0xff ));
|
|
}
|
|
|
|
uint8_t bl_pix_muldiv_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
if( y2 > 235 ) y2 = 235;
|
|
if( y1 < 16 ) y1 = 16;
|
|
return ( (y1*y1) / (0xff - y2 ) );
|
|
}
|
|
|
|
uint8_t bl_pix_add_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (b < 16)
|
|
b = 16;
|
|
if (a < 16)
|
|
a = 16;
|
|
if ((0xff - b) <= 0) {
|
|
new_Y = (a * a) >> 8;
|
|
} else {
|
|
if( b > 235)
|
|
b= 235;
|
|
new_Y = (a * a) / (0xff - b);
|
|
}
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_relneg_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = 0xff - y2;
|
|
if (a < 16)
|
|
a = 16;
|
|
if (b < 16)
|
|
b = y1;
|
|
if (b < 16)
|
|
b = 16;
|
|
new_Y = (a * a) / b;
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_relneg_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_C;
|
|
a = y1;
|
|
b = 0xff - y2;
|
|
if (b < 16)
|
|
b = y2;
|
|
if (b < 16)
|
|
b = 16;
|
|
if (a < 16)
|
|
a = 16;
|
|
new_C = (a >> 1) + (b >> 1);
|
|
if (new_C < 16)
|
|
new_C = 16;
|
|
return new_C;
|
|
}
|
|
|
|
uint8_t bl_pix_selfreeze_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
|
|
a = y1;
|
|
b = y2;
|
|
if (a > b) {
|
|
if (a < 16) {
|
|
new_Y = 16;
|
|
} else {
|
|
new_Y = 0xff - ((0xff - b) * (0xff - b)) / a;
|
|
}
|
|
return new_Y;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t bl_pix_selunfreeze_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
|
|
a = y1;
|
|
b = y2;
|
|
if (a > b) {
|
|
if (b < 16) {
|
|
new_Y = 16;
|
|
} else {
|
|
if( a > 235 ) a = 235;
|
|
new_Y = 0xff - ((0xff - a) * (0xff - a)) / b;
|
|
if (new_Y < 16)
|
|
new_Y = 16;
|
|
}
|
|
return new_Y;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t bl_pix_seldiff_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b;
|
|
a = y1;
|
|
b = y2;
|
|
if (a > b) {
|
|
return (uint8_t) abs(y1 - y2);
|
|
}
|
|
return y1;
|
|
}
|
|
|
|
|
|
uint8_t bl_pix_seldiffneg_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
|
|
a = y1;
|
|
b = y2;
|
|
if (a > b) {
|
|
new_Y = 0xff - abs(0xff - a - b);
|
|
return new_Y;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t bl_pix_swap_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return y2;
|
|
}
|
|
|
|
uint8_t bl_pix_swap_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
return y2;
|
|
}
|
|
|
|
uint8_t bl_pix_noswap_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
return y1;
|
|
}
|
|
|
|
uint8_t bl_pix_noswap_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return y1;
|
|
}
|
|
|
|
uint8_t bl_pix_add_distorted_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( y1 + y2 );
|
|
}
|
|
|
|
uint8_t bl_pix_add_distorted_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
return ( y1 + y2 );
|
|
}
|
|
|
|
uint8_t bl_pix_sub_distorted_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t new_Y;
|
|
new_Y = y1 - y2;
|
|
new_Y -= y2;
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_sub_distorted_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t new_C;
|
|
new_C = y1 - y2;
|
|
new_C -= y2;
|
|
return new_C;
|
|
}
|
|
|
|
|
|
uint8_t bl_pix_test3_Y(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_Y;
|
|
a = y1;
|
|
b = y2;
|
|
if (b < 16)
|
|
b = 16;
|
|
if (a < 16)
|
|
a = 16;
|
|
new_Y = (a >> 1) + (b >> 1);
|
|
return new_Y;
|
|
}
|
|
|
|
uint8_t bl_pix_test3_C(uint8_t y1, uint8_t y2)
|
|
{
|
|
uint8_t a, b, new_C;
|
|
a = y1;
|
|
b = 0xff - y2;
|
|
if (b < 16)
|
|
b = y2;
|
|
if (a < 16)
|
|
a = 16;
|
|
new_C = (a >> 1) + (b >> 1);
|
|
return new_C;
|
|
}
|
|
|
|
void _4byte_copy( uint8_t *src, uint8_t *dst, int width,int height, int x_start, int y_start)
|
|
{
|
|
unsigned int x = 0, y = 0;
|
|
int *in,*out;
|
|
|
|
width = width >> 2;
|
|
|
|
for(y = y_start; y < height; y++ )
|
|
{
|
|
out = (int*) &dst[y*width];
|
|
in = (int*) &src[y*width];
|
|
for(x=x_start;x < width; x++)
|
|
{
|
|
out[x] =(((in[x] >> 24) & 0xff)) + (((in[x] >> 16) & 0xff) << 8) + (((in[x] >> 8) & 0xff) << 16) + (((in[x]) & 0xff) << 24);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int bl_pix_get_color_y(int color_num)
|
|
{
|
|
switch (color_num) {
|
|
case VJ_EFFECT_COLOR_RED:
|
|
return VJ_EFFECT_LUM_RED;
|
|
case VJ_EFFECT_COLOR_BLUE:
|
|
return VJ_EFFECT_LUM_BLUE;
|
|
case VJ_EFFECT_COLOR_GREEN:
|
|
return VJ_EFFECT_LUM_GREEN;
|
|
case VJ_EFFECT_COLOR_CYAN:
|
|
return VJ_EFFECT_LUM_CYAN;
|
|
case VJ_EFFECT_COLOR_MAGNETA:
|
|
return VJ_EFFECT_LUM_MAGNETA;
|
|
case VJ_EFFECT_COLOR_YELLOW:
|
|
return VJ_EFFECT_LUM_YELLOW;
|
|
case VJ_EFFECT_COLOR_BLACK:
|
|
return VJ_EFFECT_LUM_BLACK;
|
|
case VJ_EFFECT_COLOR_WHITE:
|
|
return VJ_EFFECT_LUM_WHITE;
|
|
}
|
|
return VJ_EFFECT_LUM_BLACK;
|
|
}
|
|
int bl_pix_get_color_cb(int color_num)
|
|
{
|
|
switch (color_num) {
|
|
case VJ_EFFECT_COLOR_RED:
|
|
return VJ_EFFECT_CB_RED;
|
|
case VJ_EFFECT_COLOR_BLUE:
|
|
return VJ_EFFECT_CB_BLUE;
|
|
case VJ_EFFECT_COLOR_GREEN:
|
|
return VJ_EFFECT_CB_GREEN;
|
|
case VJ_EFFECT_COLOR_CYAN:
|
|
return VJ_EFFECT_CB_CYAN;
|
|
case VJ_EFFECT_COLOR_MAGNETA:
|
|
return VJ_EFFECT_CB_MAGNETA;
|
|
case VJ_EFFECT_COLOR_YELLOW:
|
|
return VJ_EFFECT_CB_YELLOW;
|
|
case VJ_EFFECT_COLOR_BLACK:
|
|
return VJ_EFFECT_CB_BLACK;
|
|
case VJ_EFFECT_COLOR_WHITE:
|
|
return VJ_EFFECT_CB_WHITE;
|
|
}
|
|
return VJ_EFFECT_CB_BLACK;
|
|
}
|
|
|
|
int bl_pix_get_color_cr(int color_num)
|
|
{
|
|
switch (color_num) {
|
|
case VJ_EFFECT_COLOR_RED:
|
|
return VJ_EFFECT_CR_RED;
|
|
case VJ_EFFECT_COLOR_BLUE:
|
|
return VJ_EFFECT_CR_BLUE;
|
|
case VJ_EFFECT_COLOR_GREEN:
|
|
return VJ_EFFECT_CR_GREEN;
|
|
case VJ_EFFECT_COLOR_CYAN:
|
|
return VJ_EFFECT_CR_CYAN;
|
|
case VJ_EFFECT_COLOR_MAGNETA:
|
|
return VJ_EFFECT_CR_MAGNETA;
|
|
case VJ_EFFECT_COLOR_YELLOW:
|
|
return VJ_EFFECT_CR_YELLOW;
|
|
case VJ_EFFECT_COLOR_BLACK:
|
|
return VJ_EFFECT_CR_BLACK;
|
|
case VJ_EFFECT_COLOR_WHITE:
|
|
return VJ_EFFECT_CR_WHITE;
|
|
}
|
|
return VJ_EFFECT_CR_BLACK;
|
|
}
|
|
|
|
|
|
uint8_t _pf_dneg(uint8_t a, uint8_t b)
|
|
{
|
|
uint8_t t =
|
|
255 - ( abs ( (255 - abs((255-a)-a)) - (255-abs((255-b)-b))) );
|
|
return ( abs( abs(t-b) - b ));
|
|
}
|
|
|
|
uint8_t _pf_lghtn(uint8_t a, uint8_t b)
|
|
{
|
|
if( a > b ) return a;
|
|
return b;
|
|
}
|
|
|
|
uint8_t _pf_dneg2(uint8_t a,uint8_t b)
|
|
{
|
|
return ( 255 - abs ( (255-a)- b ) );
|
|
}
|
|
|
|
uint8_t _pf_min(uint8_t a, uint8_t b)
|
|
{
|
|
uint8_t p = ( (b < a) ? b : a);
|
|
return ( 255 - abs( (255-p) - b ) );
|
|
}
|
|
|
|
uint8_t _pf_max(uint8_t a,uint8_t b)
|
|
{
|
|
uint8_t p = ( (b > a) ? b : a);
|
|
if( p<=16) p = 16;
|
|
return ( 255 - ((255 - b) * (255 - b)) / p);
|
|
|
|
}
|
|
|
|
uint8_t _pf_pq(uint8_t a,uint8_t b)
|
|
{
|
|
if( a <= 16) a = 16;
|
|
if( b <= 16) b = 16;
|
|
int p = 255 - ((255-a) * (255-a)) / a;
|
|
int q = 255 - ((255-b) * (255-b)) / b;
|
|
|
|
return ( 255 - ((255-p) * (255 - a)) / q);
|
|
}
|
|
|
|
uint8_t _pf_none(uint8_t a, uint8_t b)
|
|
{
|
|
return a;
|
|
}
|
|
|
|
_pf _get_pf(int type)
|
|
{
|
|
|
|
switch(type)
|
|
{
|
|
|
|
case 0: return &_pf_dneg;
|
|
case 3: return &_pf_lghtn;
|
|
case 1: return &_pf_min;
|
|
case 2: return &_pf_max;
|
|
case 5: return &_pf_pq;
|
|
case 6: return &_pf_dneg2;
|
|
|
|
}
|
|
return &_pf_none;
|
|
}
|
|
|
|
int calculate_luma_value(uint8_t *Y, int w , int h) {
|
|
unsigned int len = (w * h);
|
|
unsigned int sum = 0;
|
|
unsigned int i = len;
|
|
while( i ) {
|
|
sum += *(Y++);
|
|
i--;
|
|
}
|
|
return (sum/len);
|
|
}
|
|
|
|
int calculate_cbcr_value(uint8_t *Cb,uint8_t *Cr, int w, int h) {
|
|
unsigned int len = (w * h) >> 1;
|
|
unsigned int sum = 0;
|
|
unsigned int i = len;
|
|
while( i ) {
|
|
sum += ( Cb[i] + Cr[i] ) >> 1;
|
|
i--;
|
|
}
|
|
return (sum/len);
|
|
|
|
}
|
|
|
|
#ifdef HAVE_ASM_MMX
|
|
|
|
#define MMX_load8byte_mm7(data)__asm__("\n\t movq %0,%%mm7\n" : "=m" (data):)
|
|
|
|
#endif
|
|
|
|
void memset_ycbcr( uint8_t *in,
|
|
uint8_t *out,
|
|
uint8_t val,
|
|
unsigned int width,
|
|
unsigned int height)
|
|
{
|
|
veejay_memset( in, val, (width*height) );
|
|
}
|
|
|
|
double m_get_radius( int x, int y )
|
|
{
|
|
return (sqrt( (x*x) + (y*y) ));
|
|
}
|
|
double m_get_angle( int x, int y )
|
|
{
|
|
return (atan2( (float)y,x));
|
|
}
|
|
|
|
double m_get_polar_x( double r, double a)
|
|
{
|
|
return ( r * cos(a) );
|
|
}
|
|
double m_get_polar_y( double r, double a)
|
|
{
|
|
return ( r * sin(a) );
|
|
}
|
|
|
|
//copied from xine
|
|
inline void blur(uint8_t *dst, uint8_t *src, int w, int radius, int dstStep, int srcStep){
|
|
int x;
|
|
const int length= radius*2 + 1;
|
|
const int inv= ((1<<16) + length/2)/length;
|
|
|
|
int sum= 0;
|
|
|
|
for(x=0; x<radius; x++){
|
|
sum+= src[x*srcStep]<<1;
|
|
}
|
|
sum+= src[radius*srcStep];
|
|
|
|
for(x=0; x<=radius; x++){
|
|
sum+= src[(radius+x)*srcStep] - src[(radius-x)*srcStep];
|
|
dst[x*dstStep]= (sum*inv + (1<<15))>>16;
|
|
}
|
|
|
|
for(; x<w-radius; x++){
|
|
sum+= src[(radius+x)*srcStep] - src[(x-radius-1)*srcStep];
|
|
dst[x*dstStep]= (sum*inv + (1<<15))>>16;
|
|
}
|
|
|
|
for(; x<w; x++){
|
|
sum+= src[(2*w-radius-x-1)*srcStep] - src[(x-radius-1)*srcStep];
|
|
dst[x*dstStep]= (sum*inv + (1<<15))>>16;
|
|
}
|
|
}
|
|
|
|
//copied from xine
|
|
inline void blur2(uint8_t *dst, uint8_t *src, int w, int radius, int power, int dstStep, int srcStep){
|
|
uint8_t temp[2][4096];
|
|
uint8_t *a= temp[0], *b=temp[1];
|
|
|
|
if(radius){
|
|
blur(a, src, w, radius, 1, srcStep);
|
|
for(; power>2; power--){
|
|
uint8_t *c;
|
|
blur(b, a, w, radius, 1, 1);
|
|
c=a; a=b; b=c;
|
|
}
|
|
if(power>1)
|
|
blur(dst, a, w, radius, dstStep, 1);
|
|
else{
|
|
int i;
|
|
for(i=0; i<w; i++)
|
|
dst[i*dstStep]= a[i];
|
|
}
|
|
}else{
|
|
int i;
|
|
for(i=0; i<w; i++)
|
|
dst[i*dstStep]= src[i*srcStep];
|
|
}
|
|
}
|
|
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t hY[256];
|
|
uint32_t hR[256];
|
|
uint32_t hG[256];
|
|
uint32_t hB[256];
|
|
} histogram_t;
|
|
|
|
void *veejay_histogram_new()
|
|
{
|
|
histogram_t *h = (histogram_t*) vj_calloc(sizeof(histogram_t));
|
|
if(!h) return NULL;
|
|
return h;
|
|
}
|
|
|
|
void veejay_histogram_del(void *his)
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
if( h ) free(h);
|
|
}
|
|
|
|
int i_cmp( const void *a, const void *b )
|
|
{
|
|
return ( *(uint32_t*) a - *(uint32_t*) b );
|
|
}
|
|
|
|
static uint32_t veejay_histogram_median( uint32_t *h )
|
|
{
|
|
uint32_t list[256];
|
|
veejay_memcpy( h, list, sizeof(list));
|
|
qsort( list, 256, sizeof(uint32_t), i_cmp);
|
|
return ( list[128] );
|
|
}
|
|
|
|
static void build_histogram_rgb( uint8_t *rgb, histogram_t *h, VJFrame *f)
|
|
{
|
|
unsigned int i,j;
|
|
uint32_t *Hr,*Hb,*Hg;
|
|
|
|
Hr = h->hR;
|
|
Hg = h->hG;
|
|
Hb = h->hB;
|
|
|
|
int W = f->width;
|
|
int H = f->height;
|
|
int r = W * 3;
|
|
|
|
veejay_memset( Hr, 0,sizeof(uint32_t) * 256 );
|
|
veejay_memset( Hg, 0,sizeof(uint32_t) * 256 );
|
|
veejay_memset( Hb, 0,sizeof(uint32_t) * 256 );
|
|
|
|
for( i = 0; i < H; i ++ )
|
|
{
|
|
for( j = 0; j < r; j += 3 )
|
|
{
|
|
Hr[ (rgb[i*r+j] ) ] ++;
|
|
Hg[ (rgb[i*r+j+1]) ] ++;
|
|
Hb[ (rgb[i*r+j+2]) ] ++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void build_histogram( histogram_t *h, VJFrame *f )
|
|
{
|
|
unsigned int i, len;
|
|
uint32_t *H;
|
|
uint8_t *p;
|
|
|
|
// intensity histogram
|
|
H = h->hY;
|
|
p = f->data[0];
|
|
len = f->len;
|
|
veejay_memset( H, 0, sizeof(uint32_t) * 256 );
|
|
for( i = 0; i < len; i ++ )
|
|
H[ p[i] ] ++;
|
|
|
|
}
|
|
|
|
static void veejay_lut_calc( uint32_t *h, uint32_t *lut, int intensity, int strength, int len )
|
|
{
|
|
unsigned int i;
|
|
unsigned int op0 = 255 - strength;
|
|
unsigned int op1 = strength;
|
|
lut[0] = h[0];
|
|
for( i = 1; i < 256; i ++ )
|
|
lut[i] = lut[i-1] + h[i];
|
|
for( i = 0; i < 256; i ++ )
|
|
lut[i] = (lut[i] * intensity ) / len;
|
|
for( i = 0; i < 256; i ++ )
|
|
lut[i] = (op1 * lut[i] + op0 * i ) >> 8;
|
|
}
|
|
|
|
static void veejay_blit_histogram( uint8_t *D, uint32_t *h, int len )
|
|
{
|
|
unsigned int i;
|
|
for( i = 0; i < 256; i ++ )
|
|
D[i] = (h[i] > 0 ? (len / h[i]) : 0 );
|
|
}
|
|
|
|
|
|
static inline void veejay_histogram_qdraw( uint32_t *histi, histogram_t *h, VJFrame *f, uint8_t *plane, int left, int down)
|
|
{
|
|
uint8_t lut[256];
|
|
unsigned int i,j,len;
|
|
|
|
len = f->len;
|
|
veejay_blit_histogram( lut, histi, len );
|
|
|
|
int his_height = f->height/5;
|
|
int his_width = f->width/5;
|
|
|
|
float sx = his_width/256.0f;
|
|
float sy = his_height/256.0f;
|
|
|
|
//@ slow!
|
|
for ( i = 0; i < 256; i ++ )
|
|
{
|
|
for( j = 0; j < 256 ; j ++ )
|
|
{
|
|
int dx = j * sx;
|
|
int dy = i * sy;
|
|
|
|
int pos = (f->height - dy - 1 - down) * f->width + dx + left;
|
|
if( plane[pos] != 0xff)
|
|
plane[pos] = (lut[j] >= i ? 0xff: 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void veejay_histogram_draw( void *his, VJFrame *org, VJFrame *f, int intensity, int strength )
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
|
|
veejay_histogram_analyze( his, org, 0 );
|
|
veejay_histogram_qdraw( h->hY, h, f, f->data[0],0,0 );
|
|
|
|
|
|
veejay_histogram_equalize( his, org, intensity, strength );
|
|
veejay_histogram_analyze( his, org, 0 );
|
|
veejay_histogram_qdraw( h->hY, h, f, f->data[0],f->width/4 + 10,0 );
|
|
}
|
|
|
|
void veejay_histogram_draw_rgb( void *his, VJFrame *f, uint8_t *rgb, int in, int st, int mode )
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
|
|
veejay_histogram_analyze_rgb(his,rgb,f );
|
|
switch(mode)
|
|
{
|
|
case 0:
|
|
veejay_histogram_qdraw( h->hR, h, f, f->data[0], 0,f->height/4 );
|
|
break;
|
|
case 1:
|
|
veejay_histogram_qdraw( h->hG, h, f, f->data[0], 0,f->height/4 );
|
|
break;
|
|
case 2:
|
|
veejay_histogram_qdraw( h->hB, h, f, f->data[0], 0,f->height/4 );
|
|
break;
|
|
case 3:
|
|
veejay_histogram_qdraw( h->hR, h , f, f->data[0], 0, f->height/4 );
|
|
veejay_histogram_qdraw( h->hG, h , f, f->data[0], (f->width/4+10), f->height/4 );
|
|
veejay_histogram_qdraw( h->hB, h, f, f->data[0], (f->width/4+10)*2, f->height/4 );
|
|
break;
|
|
}
|
|
|
|
veejay_histogram_equalize_rgb( his, f, rgb, in,st, mode );
|
|
veejay_histogram_analyze_rgb(his,rgb,f );
|
|
|
|
switch(mode)
|
|
{
|
|
case 0:
|
|
veejay_histogram_qdraw( h->hR, h,f,f->data[0], 0,0 );
|
|
break;
|
|
case 1:
|
|
veejay_histogram_qdraw( h->hG, h,f,f->data[0], 0,0);
|
|
break;
|
|
case 2:
|
|
veejay_histogram_qdraw( h->hB, h,f, f->data[0],0,0);
|
|
break;
|
|
case 3:
|
|
veejay_histogram_qdraw( h->hR, h,f,f->data[0], 0, 0 );
|
|
veejay_histogram_qdraw( h->hG, h,f,f->data[0], (f->width/4 + 10),0 );
|
|
veejay_histogram_qdraw( h->hB, h,f,f->data[0], (f->width/4 + 10)*2,0 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void veejay_histogram_equalize_rgb( void *his, VJFrame *f, uint8_t *rgb, int intensity, int strength, int mode )
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
uint32_t LUTr[256];
|
|
uint32_t LUTg[256];
|
|
uint32_t LUTb[256];
|
|
unsigned int i,j;
|
|
unsigned int len = f->len;
|
|
|
|
uint32_t r = f->width * 3;
|
|
uint32_t H = f->height;
|
|
|
|
switch(mode)
|
|
{
|
|
case 0:
|
|
veejay_lut_calc( h->hR, LUTr, intensity , strength , len );
|
|
for( i = 0; i < H; i ++ )
|
|
{
|
|
for( j = 0; j < r ; j +=3 )
|
|
rgb[i*r+j] = LUTr[ rgb[i*r+j] ];
|
|
}
|
|
break;
|
|
case 1:
|
|
veejay_lut_calc( h->hG, LUTg, intensity , strength , len );
|
|
for( i = 0; i < H; i ++ )
|
|
{
|
|
for( j = 0; j < r; j += 3 )
|
|
rgb[ i*r+j+1 ] = LUTg[rgb[i*r+j+1]];
|
|
}
|
|
break;
|
|
case 2:
|
|
veejay_lut_calc( h->hB, LUTb, intensity , strength , len );
|
|
for( i = 0; i < H; i ++ )
|
|
{
|
|
for( j = 0; j < r; j += 3 )
|
|
rgb[i*r+j+2] = LUTb[ rgb[i*r+j+2]];
|
|
}
|
|
break;
|
|
case 3:
|
|
veejay_lut_calc( h->hR, LUTr, intensity , strength , len );
|
|
veejay_lut_calc( h->hG, LUTg, intensity , strength , len );
|
|
veejay_lut_calc( h->hB, LUTb, intensity , strength , len );
|
|
|
|
for( i = 0; i < H; i ++ )
|
|
{
|
|
for( j = 0; j < r ; j +=3 )
|
|
{
|
|
rgb[i*r+j] = LUTr[ rgb[i*r+j] ];
|
|
rgb[i*r+j+1] = LUTg[rgb[i*r+j+1]];
|
|
rgb[i*r+j+2] = LUTb[ rgb[i*r+j+2]];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void veejay_histogram_equalize( void *his, VJFrame *f , int intensity, int strength)
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
uint32_t LUT[256];
|
|
unsigned int i;
|
|
uint8_t *y;
|
|
unsigned int len;
|
|
|
|
len = f->len;
|
|
veejay_lut_calc( h->hY, LUT, intensity, strength, len );
|
|
y = f->data[0];
|
|
for( i = 0; i < len ; i ++ )
|
|
y[i] = LUT[ y[i] ];
|
|
}
|
|
|
|
void veejay_histogram_analyze_rgb( void *his, uint8_t *rgb, VJFrame *f )
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
build_histogram_rgb( rgb,h,f );
|
|
}
|
|
|
|
void veejay_histogram_analyze( void *his, VJFrame *f, int type )
|
|
{
|
|
histogram_t *h = (histogram_t*) his;
|
|
|
|
build_histogram( h, f );
|
|
}
|
|
|
|
#ifndef MIN
|
|
#define MIN(a,b) ( (a)>(b) ? (b) : (a) )
|
|
#endif
|
|
#define min4(a,b,c,d) MIN(MIN(MIN(a,b),c),d)
|
|
#define min5(a,b,c,d,e) MIN(MIN(MIN(MIN(a,b),c),d),e)
|
|
|
|
#ifndef MAX
|
|
#define MAX(a,b) ( (a)>(b) ? (a) : (b) )
|
|
#endif
|
|
|
|
#define max4(a,b,c,d) MAX(MAX(MAX(a,b),c),d)
|
|
|
|
void veejay_distance_transform8( uint8_t *plane, int w, int h, uint32_t *output)
|
|
{
|
|
register unsigned int x,y;
|
|
const uint8_t *I = plane;
|
|
uint32_t *Id = output;
|
|
const uint32_t wid = w - 1;
|
|
const uint32_t hei = h - 2;
|
|
|
|
for( y = 1; y < hei; y ++ )
|
|
{
|
|
for( x = 1; x < wid; x ++ )
|
|
{
|
|
if( I[ y * w + x ] )
|
|
Id[ y * w + x ] = min4(
|
|
(Id[ (y-1) * w + (x-1) ]) + 1,
|
|
(Id[ (y-1) * w + x ]) + 1,
|
|
(Id[ (y-1) * w + (x+1) ]) + 1,
|
|
(Id[ y * w + (x-1) ]) + 1 );
|
|
}
|
|
}
|
|
|
|
for( y = hei; y > 1; y -- )
|
|
{
|
|
for( x = wid; x > 1; x -- )
|
|
{
|
|
if( I[ y * w + x ] )
|
|
Id[ y * w + x ] = min5(
|
|
(Id[ (y+1) * w + (x-1) ]) + 1,
|
|
Id[ y * w + x ],
|
|
(Id[ (y+1) * w + x ]) + 1,
|
|
(Id[ y * w + (x + 1) ]) + 1,
|
|
(Id[ (y+1) * w + (x+1) ]) + 1
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void veejay_distance_transform( uint32_t *plane, int w, int h, uint32_t *output)
|
|
{
|
|
register unsigned int x,y;
|
|
const uint32_t *I = plane;
|
|
uint32_t *Id = output;
|
|
const uint32_t wid = w - 1;
|
|
const uint32_t hei = h - 2;
|
|
|
|
for( y = 1; y < hei; y ++ )
|
|
{
|
|
for( x = 1; x < wid; x ++ )
|
|
{
|
|
if( I[ y * w + x ] )
|
|
Id[ y * w + x ] = min4(
|
|
(Id[ (y-1) * w + (x-1) ]) + 1,
|
|
(Id[ (y-1) * w + x ]) + 1,
|
|
(Id[ (y-1) * w + (x+1) ]) + 1,
|
|
(Id[ y * w + (x-1) ]) + 1 );
|
|
}
|
|
}
|
|
|
|
for( y = hei; y > 1; y -- )
|
|
{
|
|
for( x = wid; x > 1; x -- )
|
|
{
|
|
if( I[ y * w + x ] )
|
|
Id[ y * w + x ] = min5(
|
|
(Id[ (y+1) * w + (x-1) ]) + 1,
|
|
Id[ y * w + x ],
|
|
(Id[ (y+1) * w + x ]) + 1,
|
|
(Id[ y * w + (x + 1) ]) + 1,
|
|
(Id[ (y+1) * w + (x+1) ]) + 1
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t veejay_component_labeling(int w, int h, uint32_t *I , uint32_t *M)
|
|
{
|
|
uint32_t label = 0;
|
|
uint32_t x,y,i;
|
|
uint32_t p1,p2;
|
|
uint32_t Mi=0,Ma=0;
|
|
uint32_t Eq[5000];
|
|
|
|
uint32_t n_labels = 0;
|
|
|
|
for( y = 1; y < (h-1); y ++ )
|
|
{
|
|
for ( x = 1; x < (w-1); x ++ )
|
|
{
|
|
if( I[ y * w + x] )
|
|
{
|
|
p1 = I[ (y-1) * w + x ];
|
|
p2 = I[ y * w + (x-1) ];
|
|
|
|
if( p1 == 0 && p2 == 0 )
|
|
{
|
|
label++;
|
|
if( label > 5000 )
|
|
return 0;
|
|
|
|
I[ y * w + x ] = Eq[ label ] = label;
|
|
} else if ( p1 == 0 ) {
|
|
I[ y * w + x ] = p2;
|
|
} else if ( p2 == 0 ) {
|
|
I[ y * w + x ] = p1;
|
|
} else if ( p1 == p2 ) {
|
|
I[ y * w + x ] = p1;
|
|
} else {
|
|
|
|
// Mi = min4(p1,p2,p3,p4);
|
|
// Ma = max4(p1,p2,p3,p4);
|
|
//Mi = MIN( p1,p2 );
|
|
//Ma = MAX( p1,p2 );
|
|
|
|
I[ y * w + x ] = Mi;
|
|
|
|
while( Eq[ Ma ] != Ma )
|
|
Ma = Eq[ Ma ];
|
|
while( Eq[ Mi ] != Mi )
|
|
Mi = Eq[ Mi ];
|
|
|
|
if( Ma >= Mi )
|
|
Eq[ Ma ] = Mi;
|
|
else
|
|
Eq[ Mi ] = Ma;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
n_labels = 0;
|
|
for( i = 1; i <= label; i ++ )
|
|
{
|
|
if( Eq[ i ] == i ) {
|
|
n_labels ++;
|
|
Eq[i] = n_labels;
|
|
}
|
|
else {
|
|
Eq[i] = Eq[ Eq[i] ];
|
|
}
|
|
}
|
|
|
|
if( n_labels > 5000 )
|
|
return 0;
|
|
|
|
for( i = 1; i < n_labels ; i ++ )
|
|
M[ i ] = 0;
|
|
|
|
for( y = 0; y < h ; y ++ )
|
|
{
|
|
for( x = 0; x < w ; x ++ )
|
|
{
|
|
if( I[y * w + x ] )
|
|
{
|
|
I[y * w + x ] = Eq[ I[y * w + x] ];
|
|
M[ I[y * w +x ] ]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return n_labels;
|
|
}
|
|
|
|
static inline int center_of_blob(
|
|
uint8_t *img,
|
|
int width,
|
|
int height,
|
|
uint8_t label,
|
|
uint32_t *dx, uint32_t *dy, uint32_t *xsize, uint32_t *ysize)
|
|
{
|
|
unsigned int i,j;
|
|
uint32_t product_row = 0;
|
|
uint32_t pixels_row = 0;
|
|
uint32_t product_col = 0;
|
|
uint32_t pixels_col = 0;
|
|
uint32_t pixels_row_c = 0;
|
|
uint32_t product_col_c = 0;
|
|
|
|
for( i = 0; i < height; i ++ )
|
|
{
|
|
pixels_row = 0;
|
|
for( j = 0; j < width; j ++ )
|
|
{
|
|
if ( img[i * width + j] == label )
|
|
pixels_row++;
|
|
}
|
|
if( pixels_row > *(xsize) )
|
|
*xsize = pixels_row;
|
|
product_row += (i * pixels_row);
|
|
pixels_row_c += pixels_row;
|
|
}
|
|
|
|
for( j = 0; j < width; j ++ )
|
|
{
|
|
pixels_col = 0;
|
|
for( i = 0; i < height; i ++ )
|
|
{
|
|
if( img[i * width + j ] == label )
|
|
pixels_col ++;
|
|
}
|
|
if( pixels_col > *(ysize) )
|
|
*ysize = pixels_col;
|
|
product_col += (j * pixels_col);
|
|
product_col_c += pixels_col;
|
|
}
|
|
|
|
|
|
if( pixels_row_c == 0 || product_col_c == 0 )
|
|
return 0;
|
|
|
|
*dy = ( product_row / pixels_row_c );
|
|
*dx = ( product_col / product_col_c );
|
|
|
|
return 1;
|
|
}
|
|
|
|
int compare_l8( const void *a, const void *b )
|
|
{
|
|
return ( *(int*)a - *(int*)b );
|
|
}
|
|
|
|
uint8_t veejay_component_labeling_8(int w, int h, uint8_t *I , uint32_t *M,
|
|
uint32_t *XX,
|
|
uint32_t *YY,
|
|
uint32_t *xsize,
|
|
uint32_t *ysize,
|
|
int min_blob_weight)
|
|
{
|
|
uint8_t label = 0;
|
|
uint32_t x,y,i;
|
|
uint8_t p1,p2;
|
|
uint32_t Mi=0,Ma=0;
|
|
uint8_t Eq[256];
|
|
|
|
uint8_t n_labels = 0;
|
|
|
|
veejay_memset( Eq, 0, sizeof(Eq) );
|
|
|
|
for( y = 1; y < (h-1); y ++ )
|
|
{
|
|
for ( x = 1; x < (w-1); x ++ )
|
|
{
|
|
if( I[ y * w + x] )
|
|
{
|
|
p1 = I[ (y-1) * w + x ];
|
|
p2 = I[ y * w + (x-1) ];
|
|
|
|
if( p1 == 0 && p2 == 0 )
|
|
{
|
|
label++;
|
|
if( label > 254 )
|
|
{
|
|
veejay_msg(0, "available labels exceeded");
|
|
return 0;
|
|
}
|
|
I[ y * w + x ] = Eq[ label ] = label;
|
|
} else if ( p1 == 0) {
|
|
I[ y * w + x ] = p2;
|
|
} else if ( p2 == 0 ) {
|
|
I[ y * w + x ] = p1;
|
|
} else if ( p1 == p2 ) {
|
|
I[ y * w + x ] = p1;
|
|
} else {
|
|
|
|
Mi = MIN( p1,p2 );
|
|
Ma = MAX( p1,p2 );
|
|
|
|
I[ y * w + x ] = Mi;
|
|
|
|
while( Eq[ Ma ] != Ma )
|
|
Ma = Eq[ Ma ];
|
|
while( Eq[ Mi ] != Mi )
|
|
Mi = Eq[ Mi ];
|
|
|
|
if( Ma >= Mi )
|
|
Eq[ Ma ] = Mi;
|
|
else
|
|
Eq[ Mi ] = Ma;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
n_labels = 0;
|
|
for( i = 1; i <= label; i ++ )
|
|
{
|
|
if( Eq[ i ] == i ) {
|
|
n_labels ++;
|
|
Eq[i] = n_labels;
|
|
}
|
|
else {
|
|
Eq[i] = Eq[ Eq[i] ];
|
|
}
|
|
}
|
|
|
|
if( n_labels > 254 )
|
|
{
|
|
veejay_msg(0, "Too many blobs");
|
|
return 0;
|
|
}
|
|
for( i = 0; i <= n_labels ; i ++ )
|
|
M[ i ] = 0;
|
|
|
|
for( y = 0; y < h ; y ++ )
|
|
{
|
|
for( x = 0; x < w ; x ++ )
|
|
{
|
|
if( I[y * w + x ] )
|
|
{
|
|
I[y * w + x ] = Eq[ I[y * w + x] ];
|
|
M[ I[y * w +x ] ]++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( n_labels <= 0 )
|
|
return 0;
|
|
|
|
for( i = 1; i <= n_labels; i ++ )
|
|
{
|
|
if( (M[i] * 8) >= min_blob_weight )
|
|
{
|
|
if(! center_of_blob( I,w,h, i, &(XX[i]), &(YY[i]), &(xsize[i]), &(ysize[i]) ) )
|
|
{
|
|
M[i] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M[i] = 0;
|
|
}
|
|
}
|
|
|
|
return n_labels;
|
|
}
|
|
|