mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-17 05:10:00 +01:00
265 lines
6.9 KiB
C
265 lines
6.9 KiB
C
/*
|
|
* Linux VeeJay
|
|
*
|
|
* Copyright(C)2004 Niels Elburg <nwelburg@gmail.com>
|
|
*
|
|
* 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 "common.h"
|
|
#include <veejaycore/vjmem.h>
|
|
#include "pencilsketch2.h"
|
|
|
|
/**
|
|
* Initially based on 'sketchify', added gamma compr, strength,contrast and level parmeters.
|
|
* https://github.com/rra94/sketchify
|
|
*/
|
|
|
|
/**
|
|
* This FX works in the following order:
|
|
* 1. Invert luminance channel
|
|
* 2. Blur the inverted luminance channel
|
|
* 3. Dodge blend the blurred image
|
|
* 4. Apply Posterize (if levels > 0)
|
|
* 5. Apply Histogram equaliser (if strength > 0)
|
|
* 6. Apply Contrast (if contrast > 0 )
|
|
* 7. Apply Gamma Correction
|
|
*
|
|
*/
|
|
|
|
vj_effect *pencilsketch2_init(int w, int h)
|
|
{
|
|
vj_effect *ve = (vj_effect *) vj_calloc(sizeof(vj_effect));
|
|
ve->num_params = 6;
|
|
|
|
ve->defaults = (int *) vj_calloc(sizeof(int) * ve->num_params); /* default values */
|
|
ve->limits[0] = (int *) vj_calloc(sizeof(int) * ve->num_params); /* min */
|
|
ve->limits[1] = (int *) vj_calloc(sizeof(int) * ve->num_params); /* max */
|
|
ve->limits[0][0] = 3;
|
|
ve->limits[1][0] = 128;
|
|
ve->limits[0][1] = 0;
|
|
ve->limits[1][1] = 9000;
|
|
ve->limits[0][2] = 0;
|
|
ve->limits[1][2] = 255;
|
|
ve->limits[0][3] = 0;
|
|
ve->limits[1][3] = 255;
|
|
ve->limits[0][4] = 0;
|
|
ve->limits[1][4] = 255;
|
|
ve->limits[0][5] = 0;
|
|
ve->limits[1][5] = 1;
|
|
ve->defaults[0] = 24;
|
|
ve->defaults[1] = 9000;
|
|
ve->defaults[2] = 0;
|
|
ve->defaults[3] = 0;
|
|
ve->defaults[4] = 0;
|
|
ve->defaults[5] = 1;
|
|
ve->description = "Sketchify";
|
|
ve->sub_format = -1;
|
|
ve->extra_frame = 0;
|
|
ve->parallel = 0;
|
|
ve->has_user = 0;
|
|
ve->param_description = vje_build_param_list( ve->num_params, "Blur Radius", "Gamma Compression", "Strength", "Contrast", "Levels", "Grayscale" );
|
|
return ve;
|
|
}
|
|
#define GAMMA_MAX 256
|
|
static void gammacompr_setup();
|
|
|
|
typedef struct {
|
|
uint8_t *pencilbuf;
|
|
uint8_t *pencilhblur;
|
|
uint8_t *pencilvblur;
|
|
void *histogram_;
|
|
double *gamma_table;
|
|
double gamma_value;
|
|
} pencilsketch_t;
|
|
|
|
void *pencilsketch2_malloc(int w, int h) {
|
|
|
|
pencilsketch_t *p =(pencilsketch_t*) vj_calloc(sizeof(pencilsketch_t));
|
|
if(!p) {
|
|
return NULL;
|
|
}
|
|
|
|
p->pencilbuf = (uint8_t*) vj_malloc( sizeof(uint8_t) * RUP8(w*h*3) );
|
|
if(!p->pencilbuf) {
|
|
free(p);
|
|
return NULL;
|
|
}
|
|
|
|
p->pencilhblur = p->pencilbuf + RUP8(w*h);
|
|
p->pencilvblur = p->pencilhblur + RUP8(w*h);
|
|
|
|
p->histogram_ = veejay_histogram_new();
|
|
if(!p->histogram_) {
|
|
free(p->pencilbuf);
|
|
free(p);
|
|
return NULL;
|
|
}
|
|
|
|
p->gamma_table = (double*) vj_calloc(sizeof(double) * GAMMA_MAX );
|
|
if(!p->gamma_table) {
|
|
free(p->pencilbuf);
|
|
veejay_histogram_del(p->histogram_);
|
|
free(p);
|
|
return NULL;
|
|
}
|
|
|
|
p->gamma_value = 9000;
|
|
|
|
gammacompr_setup(p);
|
|
|
|
return (void*) p;
|
|
}
|
|
|
|
void pencilsketch2_free(void *ptr) {
|
|
|
|
pencilsketch_t *p = (pencilsketch_t*) ptr;
|
|
|
|
free(p->pencilbuf);
|
|
veejay_histogram_del(p->histogram_);
|
|
free(p->gamma_table);
|
|
free(p);
|
|
}
|
|
|
|
static void gammacompr_setup(pencilsketch_t *p)
|
|
{
|
|
int i;
|
|
double val;
|
|
double gm = (double) GAMMA_MAX;
|
|
for (i = 0; i < GAMMA_MAX; i++) {
|
|
val = i / gm;
|
|
val = pow(val, p->gamma_value + ((double) i * 0.01));
|
|
val = gm * val;
|
|
p->gamma_table[i] = (val < 0.0 ? 0.0 : val > 255.0 ? 255.0 : val);
|
|
}
|
|
}
|
|
|
|
|
|
static void rhblur_apply( uint8_t *dst , uint8_t *src, int w, int h, int r)
|
|
{
|
|
int y;
|
|
for(y = 0; y < h ; y ++ )
|
|
{
|
|
veejay_blur( dst + y * w, src + y *w , w, r,1, 1);
|
|
}
|
|
}
|
|
|
|
static void rvblur_apply( uint8_t *dst, uint8_t *src, int w, int h, int r)
|
|
{
|
|
int x;
|
|
for(x=0; x < w; x++)
|
|
{
|
|
veejay_blur( dst + x, src + x , h, r, w, w );
|
|
}
|
|
}
|
|
|
|
static void pencilsketch2_negate(uint8_t *src, uint8_t *dst, const int len)
|
|
{
|
|
int i;
|
|
for( i = 0; i < len; i ++ ) {
|
|
dst[i] = 0xff - src[i];
|
|
}
|
|
}
|
|
|
|
static void pencilsketch2_posterize(uint8_t *dst, const int len, const int levels)
|
|
{
|
|
const int factor = (256 / levels);
|
|
int i;
|
|
for( i = 0; i < len; i ++ ) {
|
|
dst[i] = dst[i] - (dst[i] % factor);
|
|
}
|
|
}
|
|
|
|
static void pencilsketch2_dodge(uint8_t *result, uint8_t *front, uint8_t *back, const int len)
|
|
{
|
|
int i;
|
|
for( i = 0; i < len; i ++ ) {
|
|
|
|
if( back[i] == 0xff ) {
|
|
result[i] = 0xff;
|
|
}
|
|
else {
|
|
int v = ( front[i] * 0xff ) / ( 0xff - back[i] );
|
|
result[i] = CLAMP_Y( v );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pencilsketch2_contrast(uint8_t *dst, const int len, const int contrast)
|
|
{
|
|
int i;
|
|
for( i = 0; i < len; i ++ ) {
|
|
int m = dst[i];
|
|
m -= 128;
|
|
m *= contrast;
|
|
m = (m + 50) / 100;
|
|
m += 128;
|
|
dst[i] = CLAMP_Y(m);
|
|
}
|
|
}
|
|
|
|
static void pencilsketch2_gammacompr(double *gamma_table, uint8_t *dst, const int len)
|
|
{
|
|
int i;
|
|
for( i = 0; i < len; i ++ ) {
|
|
dst[i] = (uint8_t) gamma_table[ dst[i] ];
|
|
}
|
|
}
|
|
|
|
void pencilsketch2_apply( void *ptr, VJFrame *frame, int *args ) {
|
|
|
|
int val = args[0];
|
|
int gamma_compr = args[1];
|
|
int strength = args[2];
|
|
int contrast = args[3];
|
|
int levels = args[4];
|
|
int mode = args[5];
|
|
|
|
pencilsketch_t *p = (pencilsketch_t*) ptr;
|
|
|
|
double v = ( (double) gamma_compr - 4500.0) / 1000.0;
|
|
if (v != p->gamma_value) {
|
|
p->gamma_value = v;
|
|
gammacompr_setup(p);
|
|
}
|
|
|
|
pencilsketch2_negate(frame->data[0],p->pencilbuf, frame->len);
|
|
|
|
rhblur_apply( p->pencilhblur, p->pencilbuf, frame->width, frame->height, val );
|
|
rvblur_apply( p->pencilvblur, p->pencilhblur, frame->width, frame->height, val );
|
|
|
|
pencilsketch2_dodge( frame->data[0], p->pencilhblur, frame->data[0], frame->len );
|
|
|
|
if(mode) {
|
|
veejay_memset( frame->data[1], 128, frame->uv_len );
|
|
veejay_memset( frame->data[2], 128, frame->uv_len );
|
|
}
|
|
|
|
if(levels > 0 ) {
|
|
pencilsketch2_posterize(frame->data[0], frame->len, levels);
|
|
}
|
|
|
|
if(strength > 0) {
|
|
veejay_histogram_analyze( p->histogram_, frame, 0 );
|
|
veejay_histogram_equalize( p->histogram_, frame, 0xff, strength );
|
|
}
|
|
|
|
if( contrast > 0) {
|
|
pencilsketch2_contrast(frame->data[0], frame->len, contrast );
|
|
}
|
|
|
|
pencilsketch2_gammacompr(p->gamma_table, frame->data[0], frame->len );
|
|
}
|