X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fplugins%2Fcrikey%2Fcrikey.C;h=3ec93f7bfe952c06025ec6e05bebdd94fff807d2;hb=3ad39dda113124e7e1bb11a808541e6311417863;hp=ccbb216a34ca180373edfe4a14050e0e2ca1743b;hpb=63ced327c156ea7fe4448a18b0b1b0f2571dce7e;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/plugins/crikey/crikey.C b/cinelerra-5.1/plugins/crikey/crikey.C index ccbb216a..3ec93f7b 100644 --- a/cinelerra-5.1/plugins/crikey/crikey.C +++ b/cinelerra-5.1/plugins/crikey/crikey.C @@ -25,8 +25,9 @@ #include "arraylist.h" #include "bccmodels.h" -#include "cicolors.h" +#include "bccolors.h" #include "clip.h" +#include "edlsession.h" #include "filexml.h" #include "crikey.h" #include "crikeywindow.h" @@ -48,59 +49,82 @@ void crikey_pgm(const char *fn,VFrame *vfrm) } #endif +CriKeyPoint::CriKeyPoint(int tag, int e, float x, float y, float t) +{ + this->tag = tag; this->e = e; + this->x = x; this->y = y; + this->t = t; +} +CriKeyPoint::~CriKeyPoint() +{ +} + CriKeyConfig::CriKeyConfig() { - color = 0x000000; threshold = 0.5f; draw_mode = DRAW_ALPHA; - key_mode = KEY_SEARCH; - point_x = point_y = 0; drag = 0; + selected = 0; +} +CriKeyConfig::~CriKeyConfig() +{ } int CriKeyConfig::equivalent(CriKeyConfig &that) { - return this->color != that.color || - !EQUIV(this->threshold, that.threshold) || - this->draw_mode != that.draw_mode || - this->key_mode != that.key_mode || - !EQUIV(this->point_x, that.point_x) || - !EQUIV(this->point_y, that.point_y) || - this->drag != that.drag ? 0 : 1; + if( !EQUIV(this->threshold, that.threshold) ) return 0; + if( this->draw_mode != that.draw_mode ) return 0; + if( this->drag != that.drag ) return 0; + if( this->points.size() != that.points.size() ) return 0; + for( int i=0, n=points.size(); ipoints[i], *bp = that.points[i]; + if( ap->tag != bp->tag ) return 0; + if( ap->e != bp->e ) return 0; + if( !EQUIV(ap->x, bp->x) ) return 0; + if( !EQUIV(ap->y, bp->y) ) return 0; + if( !EQUIV(ap->t, bp->t) ) return 0; + } + return 1; } void CriKeyConfig::copy_from(CriKeyConfig &that) { - this->color = that.color; this->threshold = that.threshold; this->draw_mode = that.draw_mode; - this->key_mode = that.key_mode; - this->point_x = that.point_x; - this->point_y = that.point_y; this->drag = that.drag; + this->selected = that.selected; + + points.remove_all_objects(); + for( int i=0,n=that.points.size(); itag, pt->e, pt->x, pt->y, pt->t); + } } void CriKeyConfig::interpolate(CriKeyConfig &prev, CriKeyConfig &next, long prev_frame, long next_frame, long current_frame) { - copy_from(prev); + this->threshold = prev.threshold; + this->draw_mode = prev.draw_mode; + this->drag = prev.drag; + this->selected = prev.selected; + double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame); double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame); - this->threshold = prev.threshold * prev_scale + next.threshold * next_scale; - switch( prev.key_mode ) { - case KEY_POINT: { - this->point_x = prev.point_x * prev_scale + next.point_x * next_scale; - this->point_y = prev.point_y * prev_scale + next.point_y * next_scale; - break; } - case KEY_SEARCH: - case KEY_SEARCH_ALL: { - float prev_target[3]; set_target(0, prev.color, prev_target); - float next_target[3]; set_target(0, next.color, next_target); - float target[3]; // interpolates rgb components - for( int i=0; i<3; ++i ) - target[i] = prev_target[i] * prev_scale + next_target[i] * next_scale; - set_color(0, target, this->color); - break; } + + points.remove_all_objects(); + int prev_sz = prev.points.size(), next_sz = next.points.size(); + for( int i=0; ix, y = pt->y, t = pt->t; + int k = next_sz; // associated by tag id in next + while( --k >= 0 && pt->tag != (nt=next.points[k])->tag ); + if( k >= 0 ) { + x = x * prev_scale + nt->x * next_scale; + y = y * prev_scale + nt->y * next_scale; + t = t * prev_scale + nt->t * next_scale; + } + add_point(pt->tag, pt->e, x, y, t); } } @@ -108,7 +132,25 @@ void CriKeyConfig::limits() { bclamp(threshold, 0.0f, 1.0f); bclamp(draw_mode, 0, DRAW_MODES-1); - bclamp(key_mode, 0, KEY_MODES-1); +} + +int CriKeyConfig::add_point(int tag, int e, float x, float y, float t) +{ + int k = points.size(); + if( tag < 0 ) { + tag = 0; + for( int i=k; --i>=0; ) { + int n = points[i]->tag; + if( n >= tag ) tag = n + 1; + } + } + points.append(new CriKeyPoint(tag, e, x, y, t)); + return k; +} + +void CriKeyConfig::del_point(int i) +{ + points.remove_object_number(i); } @@ -127,50 +169,58 @@ class FillRegion stack.remove(); } - int w, h, threshold; - uint8_t *data, *mask; - bool edge_pixel(uint8_t *dp) { return *dp; } + int w, h; + float *edg; + uint8_t *msk; + bool edge_pixel(int i) { return edg[i] > 0; } public: void fill(int x, int y); - void set_threshold(float v) { threshold = v; } + void run(); - FillRegion(VFrame *d, VFrame *m); + FillRegion(VFrame *edg, VFrame *msk); }; -FillRegion::FillRegion(VFrame *d, VFrame *m) +FillRegion::FillRegion(VFrame *edg, VFrame *msk) { - threshold = 128; - w = d->get_w(); - h = d->get_h(); - data = d->get_data(); - mask = m->get_data(); + this->w = msk->get_w(); + this->h = msk->get_h(); + this->msk = (uint8_t*) msk->get_data(); + this->edg = (float*) edg->get_data(); } void FillRegion::fill(int x, int y) { push(y, x, x); +} - do { - int ilt, irt, lt, rt; +void FillRegion::run() +{ + while( stack.size() > 0 ) { + int y, ilt, irt; pop(y, ilt, irt); int ofs = y*w + ilt; - uint8_t *idp = data + ofs, *dp; - uint8_t *imp = mask + ofs, *mp; - for( int x=ilt; x<=irt; ++x,++imp,++idp ) { - if( !*imp || edge_pixel(idp) ) continue; - *imp = 0; - lt = rt = x; - dp = idp; mp = imp; - for( int i=lt; --i>=0; lt=i,*mp=0 ) - if( !*--mp || edge_pixel(--dp) ) break; - dp = idp; mp = imp; - for( int i=rt; ++i< w; rt=i,*mp=0 ) - if( !*++mp || edge_pixel(++dp) ) break; + for( int x=ilt; x<=irt; ++x,++ofs ) { + if( !msk[ofs] ) continue; + msk[ofs] = 0; + if( edge_pixel(ofs) ) continue; + int lt = x, rt = x; + int lofs = ofs; + for( int i=lt; --i>=0; ) { + if( !msk[--lofs] ) break; + msk[lofs] = 0; lt = i; + if( edge_pixel(lofs) ) break; + } + int rofs = ofs; + for( int i=rt; ++i< w; rt=i,msk[rofs]=0 ) { + if( !msk[++rofs] ) break; + msk[rofs] = 0; rt = i; + if( edge_pixel(rofs) ) break; + } if( y+1 < h ) push(y+1, lt, rt); if( y-1 >= 0 ) push(y-1, lt, rt); } - } while( stack.size() > 0 ); + } } @@ -179,123 +229,46 @@ CriKey::CriKey(PluginServer *server) { engine = 0; msk = 0; - dst = 0; - diff_pixel = 0; + edg = 0; } CriKey::~CriKey() { delete engine; delete msk; - delete dst; -} - -void CriKeyConfig::set_target(int is_yuv, int color, float *target) -{ - float r = ((color>>16) & 0xff) / 255.0f; - float g = ((color>> 8) & 0xff) / 255.0f; - float b = ((color>> 0) & 0xff) / 255.0f; - if( is_yuv ) { - float y, u, v; - YUV::rgb_to_yuv_f(r,g,b, y,u,v); - target[0] = y; - target[1] = u + 0.5f; - target[2] = v + 0.5f; - } - else { - target[0] = r; - target[1] = g; - target[2] = b; - } -} -void CriKeyConfig::set_color(int is_yuv, float *target, int &color) -{ - float r = target[0]; - float g = target[1]; - float b = target[2]; - if( is_yuv ) { - float y = r, u = g-0.5f, v = b-0.5f; - YUV::yuv_to_rgb_f(y,u,v, r,g,b); - } - int ir = r >= 1 ? 0xff : r < 0 ? 0 : (int)(r * 256); - int ig = g >= 1 ? 0xff : g < 0 ? 0 : (int)(g * 256); - int ib = b >= 1 ? 0xff : b < 0 ? 0 : (int)(b * 256); - color = (ir << 16) | (ig << 8) | (ib << 0); + delete edg; } -void CriKey::get_color(int x, int y) +int CriKey::set_target(float *color, int x, int y) { - if( x < 0 || x >= w ) return; - if( y < 0 || y >= h ) return; + if( x < 0 || x >= w ) return 1; + if( y < 0 || y >= h ) return 1; uint8_t **src_rows = src->get_rows(); - uint8_t *sp = src_rows[y] + x*bpp; if( is_float ) { - float *fp = (float *)sp; - for( int i=0; iget_rows(); - for( int y=0; y*diff_pixel)(sp); - if( v >= mv ) continue; - mv = v; ix = x; iy = y; - } - } -} -bool CriKey::find_key(int &ix, int &iy, float thr) -{ - uint8_t **src_rows = src->get_rows(); - uint8_t **msk_rows = msk->get_rows(); - int x = ix, y = iy; - for( ; y*diff_pixel)(sp); - if( v < thr ) { - ix = x; iy = y; - return true; - } - } - x = 0; + for( int i=0; ioutput_w / 2.f; + float y = !session ? 0.f : session->output_h / 2.f; + return config.add_point(-1, 0, x, y, 0.5f); +} + void CriKey::save_data(KeyFrame *keyframe) { FileXML output; @@ -304,18 +277,29 @@ void CriKey::save_data(KeyFrame *keyframe) output.set_shared_output(keyframe->get_data(), MESSAGESIZE); output.tag.set_title("CRIKEY"); - output.tag.set_property("COLOR", config.color); output.tag.set_property("THRESHOLD", config.threshold); output.tag.set_property("DRAW_MODE", config.draw_mode); - output.tag.set_property("KEY_MODE", config.key_mode); - output.tag.set_property("POINT_X", config.point_x); - output.tag.set_property("POINT_Y", config.point_y); output.tag.set_property("DRAG", config.drag); + output.tag.set_property("SELECTED", config.selected); output.append_tag(); output.append_newline(); output.tag.set_title("/CRIKEY"); output.append_tag(); output.append_newline(); + for( int i=0, n = config.points.size(); itag); + output.tag.set_title(point+1); + output.tag.set_property("E", pt->e); + output.tag.set_property("X", pt->x); + output.tag.set_property("Y", pt->y); + output.tag.set_property("T", pt->t); + output.append_tag(); + output.tag.set_title(point+0); + output.append_tag(); + output.append_newline(); + } output.terminate_string(); } @@ -323,24 +307,28 @@ void CriKey::read_data(KeyFrame *keyframe) { FileXML input; input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data())); + config.points.remove_all_objects(); int result = 0; while( !(result=input.read_tag()) ) { - if(input.tag.title_is("CRIKEY")) { - config.color = input.tag.get_property("COLOR", config.color); + if( input.tag.title_is("CRIKEY") ) { config.threshold = input.tag.get_property("THRESHOLD", config.threshold); config.draw_mode = input.tag.get_property("DRAW_MODE", config.draw_mode); - config.key_mode = input.tag.get_property("KEY_MODE", config.key_mode); - config.point_x = input.tag.get_property("POINT_X", config.point_x); - config.point_y = input.tag.get_property("POINT_Y", config.point_y); config.drag = input.tag.get_property("DRAG", config.drag); + config.selected = input.tag.get_property("SELECTED", 0); config.limits(); } - else if(input.tag.title_is("/CRIKEY")) { - result = 1; + else if( !strncmp(input.tag.get_title(),"POINT_",6) ) { + int tag = atoi(input.tag.get_title() + 6); + int e = input.tag.get_property("E", 0); + float x = input.tag.get_property("X", 0.f); + float y = input.tag.get_property("Y", 0.f); + float t = input.tag.get_property("T", .5f); + config.add_point(tag, e, x, y, t); } } + if( !config.points.size() ) new_point(); } void CriKey::update_gui() @@ -414,6 +402,79 @@ void CriKey::draw_alpha(VFrame *msk) } } +void CriKey::draw_edge(VFrame *edg) +{ + uint8_t **src_rows = src->get_rows(); + float **edg_rows = (float**) edg->get_rows(), gain = 10; + switch( color_model ) { + case BC_RGB_FLOAT: + for( int y=0; yget_rows(); @@ -488,6 +549,42 @@ void CriKey::draw_mask(VFrame *msk) } } + +void CriKey::draw_point(VFrame *src, CriKeyPoint *pt) +{ + int d = bmax(w,h) / 200 + 2; + int r = d/2+1, x = pt->x, y = pt->y; + src->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r); + src->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0); + src->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r); + src->draw_smooth(x+0,y+r, x-r, y+r, x-r,y+0); + if( pt->e ) { + src->set_pixel_color(RED); + src->draw_x(pt->x, pt->y, d); + } + else { + src->set_pixel_color(BLUE); + src->draw_t(pt->x, pt->y, d); + } +} + + +static void get_vframe(VFrame *&vfrm, int w, int h, int color_model) +{ + if( vfrm && ( vfrm->get_w() != w || vfrm->get_h() != h ) ) { + delete vfrm; vfrm = 0; + } + if( !vfrm ) vfrm = new VFrame(w, h, color_model, 0); +} + +static void fill_edge(VFrame *vfrm, int w, int h) +{ + int w1 = w-1, h1 = h-1; + float *dp = (float*) vfrm->get_data(); + if( w1 > 0 ) for( int y=0; y 0 ) for( int x=0; xget_w(), h = src->get_h(); color_model = src->get_color_model(); bpp = BC_CModels::calculate_pixelsize(color_model); - comp = BC_CModels::components(color_model); - if( comp > 3 ) comp = 3; - is_yuv = BC_CModels::is_yuv(color_model); is_float = BC_CModels::is_float(color_model); - diff_pixel = is_float ? &CriKey::diff_float : &CriKey::diff_uint8; + is_yuv = BC_CModels::is_yuv(color_model); + comp = BC_CModels::components(color_model); + if( comp > 3 ) comp = 3; read_frame(src, 0, start_position, frame_rate, 0); - - switch( config.key_mode ) { - case KEY_SEARCH: - case KEY_SEARCH_ALL: - set_target(is_yuv, config.color, target); - break; - case KEY_POINT: - get_color(config.point_x, config.point_y); - break; - } - - if( dst && ( dst->get_w() != w || src->get_h() != h ) ) { - delete dst; dst = 0; - } - if( !dst ) - dst = new VFrame(w, h, BC_A8); - memset(dst->get_data(), 0x00, dst->get_data_size()); + get_vframe(edg, w, h, BC_A_FLOAT); if( !engine ) engine = new CriKeyEngine(this, PluginClient::get_project_smp() + 1, PluginClient::get_project_smp() + 1); - engine->process_packages(); -// copy fill btm/rt edges - int w1 = w-1, h1 = h-1; - uint8_t *dp = dst->get_data(); - if( w1 > 0 ) for( int y=0; y 0 ) for( int x=0; xget_w() != w || msk->get_h() != h ) ) { - delete msk; msk = 0; - } - if( !msk ) - msk = new VFrame(w, h, BC_A8); + get_vframe(msk, w, h, BC_A8); memset(msk->get_data(), 0xff, msk->get_data_size()); - FillRegion fill_region(dst, msk); - fill_region.set_threshold(config.threshold); - - int x = 0, y = 0; - switch( config.key_mode ) { - case KEY_SEARCH: - min_key(x, y); - fill_region.fill(x, y); - break; - case KEY_SEARCH_ALL: - while( find_key(x, y, config.threshold) ) { - fill_region.fill(x, y); - ++x; - } - break; - case KEY_POINT: - x = config.point_x, y = config.point_y; - if( x >= 0 && x < w && y >= 0 && y < h ) - fill_region.fill(x, y); - break; + for( int i=0, n=config.points.size(); ie ) continue; + if( set_target(engine->color, pt->x, pt->y) ) continue; + engine->threshold = pt->t; + edg->clear_frame(); + engine->process_packages(); + fill_edge(edg, w, h); + FillRegion fill_region(edg, msk); + fill_region.fill(pt->x, pt->y); + fill_region.run(); } -//crikey_pgm("/tmp/msk.pgm",msk); - if( config.draw_mode == DRAW_MASK ) { - draw_mask(msk); - return 0; +//crikey_pgm("/tmp/msk.pgm",msk); + switch( config.draw_mode ) { + case DRAW_ALPHA: draw_alpha(msk); break; + case DRAW_EDGE: draw_edge(edg); break; + case DRAW_MASK: draw_mask(msk); break; } - draw_alpha(msk); + if( config.drag ) { + for( int i=0, n=config.points.size(); iset_pixel_color(config.selected == i ? GREEN : WHITE); + draw_point(src, pt); + } + } return 0; } @@ -598,30 +660,28 @@ LoadClient* CriKeyEngine::new_client() return new CriKeyUnit(this); } -#define EDGE_MACRO(type, max, components, is_yuv) \ +#define EDGE_MACRO(type, components, is_yuv) \ { \ uint8_t **src_rows = src->get_rows(); \ int comps = MIN(components, 3); \ - float scale = 1.0f/max; \ for( int y=y1; y= threshold ) continue; \ + *edgp += (mx - mn); \ } \ } \ } break @@ -629,23 +689,25 @@ LoadClient* CriKeyEngine::new_client() void CriKeyUnit::process_package(LoadPackage *package) { - VFrame *src = server->plugin->src; + int color_model = server->plugin->color_model; int bpp = server->plugin->bpp; - VFrame *dst = server->plugin->dst; - uint8_t **dst_rows = dst->get_rows(); - float *target = server->plugin->target; - float threshold = server->plugin->config.threshold; + VFrame *src = server->plugin->src; + VFrame *edg = server->plugin->edg; + float **edg_rows = (float**)edg->get_rows(); + float *target_color = server->color; + float threshold = 2.f * server->threshold*server->threshold; + float scale = 1./BC_CModels::calculate_max(color_model); CriKeyPackage *pkg = (CriKeyPackage*)package; int x1 = 0, x2 = server->plugin->w-1; int y1 = pkg->y1, y2 = pkg->y2; - switch( src->get_color_model() ) { - case BC_RGB_FLOAT: EDGE_MACRO(float, 1, 3, 0); - case BC_RGBA_FLOAT: EDGE_MACRO(float, 1, 4, 0); - case BC_RGB888: EDGE_MACRO(unsigned char, 0xff, 3, 0); - case BC_YUV888: EDGE_MACRO(unsigned char, 0xff, 3, 1); - case BC_RGBA8888: EDGE_MACRO(unsigned char, 0xff, 4, 0); - case BC_YUVA8888: EDGE_MACRO(unsigned char, 0xff, 4, 1); + switch( color_model ) { + case BC_RGB_FLOAT: EDGE_MACRO(float, 3, 0); + case BC_RGBA_FLOAT: EDGE_MACRO(float, 4, 0); + case BC_RGB888: EDGE_MACRO(unsigned char, 3, 0); + case BC_YUV888: EDGE_MACRO(unsigned char, 3, 1); + case BC_RGBA8888: EDGE_MACRO(unsigned char, 4, 0); + case BC_YUVA8888: EDGE_MACRO(unsigned char, 4, 1); } }