static void imb_float_from_rect_linear(struct ImBuf *ibuf, float *fbuf) { float *tof = fbuf; int i; unsigned char *to = (unsigned char *) ibuf->rect; for (i = ibuf->x * ibuf->y; i > 0; i--) { tof[0] = srgb_to_linearrgb(((float)to[0])*(1.0f/255.0f)); tof[1] = srgb_to_linearrgb(((float)to[1])*(1.0f/255.0f)); tof[2] = srgb_to_linearrgb(((float)to[2])*(1.0f/255.0f)); tof[3] = ((float)to[3])*(1.0f/255.0f); to += 4; tof += 4; } }
MINLINE void srgb_to_linearrgb_predivide_v4(float linear[4], const float srgb[4]) { float alpha, inv_alpha; if (srgb[3] == 1.0f || srgb[3] == 0.0f) { alpha = 1.0f; inv_alpha = 1.0f; } else { alpha = srgb[3]; inv_alpha = 1.0f / alpha; } linear[0] = srgb_to_linearrgb(srgb[0] * inv_alpha) * alpha; linear[1] = srgb_to_linearrgb(srgb[1] * inv_alpha) * alpha; linear[2] = srgb_to_linearrgb(srgb[2] * inv_alpha) * alpha; linear[3] = srgb[3]; }
/* note: lift_lgg is just 2-lift, gamma_inv is 1.0/gamma */ DO_INLINE float colorbalance_lgg(float in, float lift_lgg, float gamma_inv, float gain) { /* 1:1 match with the sequencer with linear/srgb conversions, the conversion isnt pretty * but best keep it this way, sice testing for durian shows a similar calculation * without lin/srgb conversions gives bad results (over-saturated shadows) with colors * slightly below 1.0. some correction can be done but it ends up looking bad for shadows or lighter tones - campbell */ float x= (((linearrgb_to_srgb(in) - 1.0f) * lift_lgg) + 1.0f) * gain; /* prevent NaN */ if (x < 0.f) x = 0.f; return powf(srgb_to_linearrgb(x), gamma_inv); }
void IMB_convert_profile(struct ImBuf *ibuf, int profile) { int ok= FALSE; int i; unsigned char *rct= (unsigned char *)ibuf->rect; float *rctf= ibuf->rect_float; if(ibuf->profile == profile) return; if(ELEM(ibuf->profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* from */ if(profile == IB_PROFILE_LINEAR_RGB) { /* to */ if(ibuf->rect_float) { for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) { rctf[0]= srgb_to_linearrgb(rctf[0]); rctf[1]= srgb_to_linearrgb(rctf[1]); rctf[2]= srgb_to_linearrgb(rctf[2]); } } if(ibuf->rect) { for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) { rct[0]= (unsigned char)((srgb_to_linearrgb((float)rct[0]/255.0f) * 255.0f) + 0.5f); rct[1]= (unsigned char)((srgb_to_linearrgb((float)rct[1]/255.0f) * 255.0f) + 0.5f); rct[2]= (unsigned char)((srgb_to_linearrgb((float)rct[2]/255.0f) * 255.0f) + 0.5f); } } ok= TRUE; } } else if (ibuf->profile == IB_PROFILE_LINEAR_RGB) { /* from */ if(ELEM(profile, IB_PROFILE_NONE, IB_PROFILE_SRGB)) { /* to */ if(ibuf->rect_float) { for (i = ibuf->x * ibuf->y; i > 0; i--, rctf+=4) { rctf[0]= linearrgb_to_srgb(rctf[0]); rctf[1]= linearrgb_to_srgb(rctf[1]); rctf[2]= linearrgb_to_srgb(rctf[2]); } } if(ibuf->rect) { for (i = ibuf->x * ibuf->y; i > 0; i--, rct+=4) { rct[0]= (unsigned char)((linearrgb_to_srgb((float)rct[0]/255.0f) * 255.0f) + 0.5f); rct[1]= (unsigned char)((linearrgb_to_srgb((float)rct[1]/255.0f) * 255.0f) + 0.5f); rct[2]= (unsigned char)((linearrgb_to_srgb((float)rct[2]/255.0f) * 255.0f) + 0.5f); } } ok= TRUE; } } if(ok==FALSE){ printf("IMB_convert_profile: failed profile conversion %d -> %d\n", ibuf->profile, profile); return; } ibuf->profile= profile; }
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3]) { linear[0] = srgb_to_linearrgb(srgb[0]); linear[1] = srgb_to_linearrgb(srgb[1]); linear[2] = srgb_to_linearrgb(srgb[2]); }
static void compute_gradient_screen(RenderData *rd, NodeKeyingScreenData *keyingscreen_data, MovieClip *clip, CompBuf *screenbuf) { MovieClipUser user = {0}; MovieTracking *tracking = &clip->tracking; MovieTrackingTrack *track; VoronoiTriangulationPoint *triangulated_points; VoronoiSite *sites; ImBuf *ibuf; ListBase *tracksbase; ListBase edges = {NULL, NULL}; int sites_total, triangulated_points_total, triangles_total; int (*triangles)[3]; int i, x, y; float *rect = screenbuf->rect; if (keyingscreen_data->tracking_object[0]) { MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, keyingscreen_data->tracking_object); if (!object) return; tracksbase = BKE_tracking_object_get_tracks(tracking, object); } else tracksbase = BKE_tracking_get_active_tracks(tracking); sites_total = BLI_countlist(tracksbase); if (!sites_total) return; BKE_movieclip_user_set_frame(&user, rd->cfra); ibuf = BKE_movieclip_get_ibuf(clip, &user); sites = MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites"); track = tracksbase->first; i = 0; while (track) { VoronoiSite *site = &sites[i]; MovieTrackingMarker *marker = BKE_tracking_marker_get(track, rd->cfra); ImBuf *pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE); int j; zero_v3(site->color); if (pattern_ibuf) { for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) { if (pattern_ibuf->rect_float) { add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]); } else { unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect; site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f); site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f); site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f); } } mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y)); IMB_freeImBuf(pattern_ibuf); } site->co[0] = marker->pos[0] * screenbuf->x; site->co[1] = marker->pos[1] * screenbuf->y; track = track->next; i++; } IMB_freeImBuf(ibuf); BLI_voronoi_compute(sites, sites_total, screenbuf->x, screenbuf->y, &edges); BLI_voronoi_triangulate(sites, sites_total, &edges, screenbuf->x, screenbuf->y, &triangulated_points, &triangulated_points_total, &triangles, &triangles_total); for (y = 0; y < screenbuf->y; y++) { for (x = 0; x < screenbuf->x; x++) { int index = 4 * (y * screenbuf->x + x); rect[index + 0] = rect[index + 1] = rect[index + 2] = 0.0f; rect[index + 3] = 1.0f; for (i = 0; i < triangles_total; i++) { int *triangle = triangles[i]; VoronoiTriangulationPoint *a = &triangulated_points[triangle[0]], *b = &triangulated_points[triangle[1]], *c = &triangulated_points[triangle[2]]; float co[2] = {x, y}, w[3]; if (barycentric_coords_v2(a->co, b->co, c->co, co, w)) { if (barycentric_inside_triangle_v2(w)) { rect[index + 0] += a->color[0] * w[0] + b->color[0] * w[1] + c->color[0] * w[2]; rect[index + 1] += a->color[1] * w[0] + b->color[1] * w[1] + c->color[1] * w[2]; rect[index + 2] += a->color[2] * w[0] + b->color[2] * w[1] + c->color[2] * w[2]; } } } } } MEM_freeN(triangulated_points); MEM_freeN(triangles); MEM_freeN(sites); BLI_freelistN(&edges); }
KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTriangulation() { MovieClipUser user = {0}; TriangulationData *triangulation; MovieTracking *tracking = &this->m_movieClip->tracking; MovieTrackingTrack *track; VoronoiSite *sites, *site; ImBuf *ibuf; ListBase *tracksbase; ListBase edges = {NULL, NULL}; int sites_total; int i; int width = this->getWidth(); int height = this->getHeight(); int clip_frame = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber); if (this->m_trackingObject[0]) { MovieTrackingObject *object = BKE_tracking_object_get_named(tracking, this->m_trackingObject); if (!object) return NULL; tracksbase = BKE_tracking_object_get_tracks(tracking, object); } else tracksbase = BKE_tracking_get_active_tracks(tracking); /* count sites */ for (track = (MovieTrackingTrack *) tracksbase->first, sites_total = 0; track; track = track->next) { MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame); float pos[2]; if (marker->flag & MARKER_DISABLED) continue; add_v2_v2v2(pos, marker->pos, track->offset); if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) { continue; } sites_total++; } if (!sites_total) return NULL; BKE_movieclip_user_set_frame(&user, clip_frame); ibuf = BKE_movieclip_get_ibuf(this->m_movieClip, &user); if (!ibuf) return NULL; triangulation = (TriangulationData *) MEM_callocN(sizeof(TriangulationData), "keying screen triangulation data"); sites = (VoronoiSite *) MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites"); track = (MovieTrackingTrack *) tracksbase->first; for (track = (MovieTrackingTrack *) tracksbase->first, site = sites; track; track = track->next) { MovieTrackingMarker *marker = BKE_tracking_marker_get(track, clip_frame); ImBuf *pattern_ibuf; int j; float pos[2]; if (marker->flag & MARKER_DISABLED) continue; add_v2_v2v2(pos, marker->pos, track->offset); if (!IN_RANGE_INCL(pos[0], 0.0f, 1.0f) || !IN_RANGE_INCL(pos[1], 0.0f, 1.0f)) { continue; } pattern_ibuf = BKE_tracking_get_pattern_imbuf(ibuf, track, marker, TRUE, FALSE); zero_v3(site->color); if (pattern_ibuf) { for (j = 0; j < pattern_ibuf->x * pattern_ibuf->y; j++) { if (pattern_ibuf->rect_float) { add_v3_v3(site->color, &pattern_ibuf->rect_float[4 * j]); } else { unsigned char *rrgb = (unsigned char *)pattern_ibuf->rect; site->color[0] += srgb_to_linearrgb((float)rrgb[4 * j + 0] / 255.0f); site->color[1] += srgb_to_linearrgb((float)rrgb[4 * j + 1] / 255.0f); site->color[2] += srgb_to_linearrgb((float)rrgb[4 * j + 2] / 255.0f); } } mul_v3_fl(site->color, 1.0f / (pattern_ibuf->x * pattern_ibuf->y)); IMB_freeImBuf(pattern_ibuf); } site->co[0] = pos[0] * width; site->co[1] = pos[1] * height; site++; } IMB_freeImBuf(ibuf); BLI_voronoi_compute(sites, sites_total, width, height, &edges); BLI_voronoi_triangulate(sites, sites_total, &edges, width, height, &triangulation->triangulated_points, &triangulation->triangulated_points_total, &triangulation->triangles, &triangulation->triangles_total); MEM_freeN(sites); BLI_freelistN(&edges); if (triangulation->triangles_total) { rctf *rect; rect = triangulation->triangles_AABB = (rctf *) MEM_callocN(sizeof(rctf) * triangulation->triangles_total, "voronoi triangulation AABB"); for (i = 0; i < triangulation->triangles_total; i++, rect++) { int *triangle = triangulation->triangles[i]; VoronoiTriangulationPoint *a = &triangulation->triangulated_points[triangle[0]], *b = &triangulation->triangulated_points[triangle[1]], *c = &triangulation->triangulated_points[triangle[2]]; float min[2], max[2]; INIT_MINMAX2(min, max); minmax_v2v2_v2(min, max, a->co); minmax_v2v2_v2(min, max, b->co); minmax_v2v2_v2(min, max, c->co); rect->xmin = min[0]; rect->ymin = min[1]; rect->xmax = max[0]; rect->ymax = max[1]; } } return triangulation; }