2 * rotoscoping.c -- (not yet)keyframable vector based rotoscoping
3 * Copyright (C) 2011 Till Theato <root@ttill.de>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <framework/mlt_filter.h>
21 #include <framework/mlt_frame.h>
22 #include <framework/mlt_tokeniser.h>
29 #define MAX( x, y ) x > y ? x : y
30 #define MIN( x, y ) x < y ? x : y
32 /** x, y pair with double precision */
40 * Extracts the polygon points stored in \param string
41 * \param string string containing the points in the format: x1;y1#x2;y2#...
42 * \param points pointer to array of points. Will be allocated and filled with the points in \param string
43 * \return number of points
45 int parsePolygonString( char *string, PointF **points )
48 mlt_tokeniser tokens = mlt_tokeniser_init( );
52 mlt_tokeniser_parse_new( tokens, string, "#" );
54 // Iterate through each token
55 int count = mlt_tokeniser_count( tokens );
56 *points = malloc( (count + 1) * sizeof( struct PointF ) );
58 for ( i = 0; i < count; ++i )
60 char *value = mlt_tokeniser_get_string( tokens, i );
61 (*points)[i].x = atof( value );
62 (*points)[i].y = atof( strchr( value, ';' ) + 1 );
65 // Remove the tokeniser
66 mlt_tokeniser_close( tokens );
71 /** helper for using qsort with an array of integers. */
72 int ncompare( const void *a, const void *b )
74 return *(const int*)a - *(const int*)b;
78 * Determines which points are located in the polygon and sets their value in \param map to 1
79 * \param vertices points defining the polygon
80 * \param count number of vertices
82 * \param height y range
83 * \param map array of integers of the dimension width * height.
84 * The map entries belonging to the points in the polygon will be set to 1, the other entries remain untouched.
86 * based on public-domain code by Darel Rex Finley, 2007
87 * \see: http://alienryderflex.com/polygon_fill/
89 void fillMap( PointF *vertices, int count, int width, int height, int *map )
91 int nodes, nodeX[1024], pixelX, pixelY, i, j, swap;
93 // Loop through the rows of the image
94 for ( pixelY = 0; pixelY < height; pixelY++ )
97 * Build a list of nodes.
98 * nodes are located at the borders of the polygon
99 * and therefore indicate a move from in to out or vice versa
102 for ( i = 0, j = count - 1; i < count; j = i++ )
103 if ( (vertices[i].y > (double)pixelY) != (vertices[j].y > (double)pixelY) )
104 nodeX[nodes++] = (int)(vertices[i].x + (pixelY - vertices[i].y) / (vertices[j].y - vertices[i].y) * (vertices[j].x - vertices[i].x) );
106 qsort( nodeX, nodes, sizeof( int ), ncompare );
108 // Fill the pixels between node pairs.
109 for ( i = 0; i < nodes; i += 2 )
111 if ( nodeX[i] >= width )
113 if ( nodeX[i+1] > 0 )
115 nodeX[i] = MAX( 0, nodeX[i] );
116 nodeX[i+1] = MIN( nodeX[i+1], width );
117 for ( j = nodeX[i]; j < nodeX[i+1]; j++ )
118 map[width * pixelY + j] = 1;
126 static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
129 *format = mlt_image_rgb24a;
130 int error = mlt_frame_get_image( this, image, format, width, height, 1 );
132 // Only process if we have no error and a valid colour space
135 struct PointF *points;
137 points = mlt_properties_get_data( MLT_FRAME_PROPERTIES( this ), "points", &length );
138 count = length / sizeof( struct PointF );
141 for ( i = 0; i < count; ++i ) {
142 points[i].x *= *width;
143 points[i].y *= *height;
148 int *map = calloc( *width * *height, sizeof( int ) );
149 fillMap( points, count, *width, *height, map );
152 uint8_t *q = *image + *width * *height * 4;
156 int pixel = (p - *image) / 4;
158 // pixel is not in polygon
160 p[0] = p[1] = p[2] = 0;
172 /** Filter processing.
174 static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
176 char *polygon = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "polygon" );
178 if ( polygon == NULL || strcmp( polygon, "" ) == 0 ) {
179 // :( we are redundant
183 struct PointF *points;
184 int count = parsePolygonString( polygon, &points );
185 int length = count * sizeof( struct PointF );
187 mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "points", points, length, free, NULL );
188 mlt_frame_push_get_image( frame, filter_get_image );
193 /** Constructor for the filter.
195 mlt_filter filter_rotoscoping_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
197 mlt_filter this = mlt_filter_new( );
200 this->process = filter_process;
202 mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "polygon", arg );