void invData(Images& images) const override { ColorVal R,G,B,Y,C1,C2; const ColorVal max[3] = {ranges->max(0), ranges->max(1), ranges->max(2)}; for (Image& image : images) { image.undo_make_constant_plane(0); image.undo_make_constant_plane(1); image.undo_make_constant_plane(2); for (uint32_t r=0; r<image.rows(); r++) { for (uint32_t c=0; c<image.cols(); c++) { Y=image(0,r,c); C1=image(1,r,c); C2=image(2,r,c); G = Y - (-2*C2)/3; clip(G, 0, max[1]); B = G - C2 - C1/2; clip(B, 0, max[2]); R = B + C1; clip(R, 0, max[0]); // clipping only needed in case of lossy/partial decoding image.set(0,r,c, R); image.set(1,r,c, G); image.set(2,r,c, B); } } } }
void initPropRanges(Ranges &propRanges, const ColorRanges &ranges, int p) { propRanges.clear(); int min = ranges.min(p); int max = ranges.max(p); int mind = min - max, maxd = max - min; if (p < 3) { // alpha channel first for (int pp = 0; pp < p; pp++) { propRanges.push_back(std::make_pair(ranges.min(pp), ranges.max(pp))); // pixels on previous planes } if (ranges.numPlanes()>3) propRanges.push_back(std::make_pair(ranges.min(3), ranges.max(3))); // pixel on alpha plane } //if (p<1 || p>2) propRanges.push_back(std::make_pair(0,2)); // median predictor: which of the three values is the median? if (p==1 || p==2) propRanges.push_back(std::make_pair(ranges.min(0)-ranges.max(0),ranges.max(0)-ranges.min(0))); // luma prediction miss propRanges.push_back(std::make_pair(mind,maxd)); // neighbor A - neighbor B (top-bottom or left-right) propRanges.push_back(std::make_pair(mind,maxd)); // top/left prediction miss (previous pixel) propRanges.push_back(std::make_pair(mind,maxd)); // left/top prediction miss (other direction) propRanges.push_back(std::make_pair(mind,maxd)); // bottom/right prediction miss propRanges.push_back(std::make_pair(min,max)); // guess // propRanges.push_back(std::make_pair(mind,maxd)); // left - topleft // propRanges.push_back(std::make_pair(mind,maxd)); // topleft - top // if (p == 0 || p > 2) // propRanges.push_back(std::make_pair(mind,maxd)); // top - topright if (p != 2) { propRanges.push_back(std::make_pair(mind,maxd)); // toptop - top propRanges.push_back(std::make_pair(mind,maxd)); // leftleft - left } }
void data(Images& images) const override { ColorVal pixel[5]; for (Image& image : images) for (uint32_t r=0; r<image.rows(); r++) { for (uint32_t c=0; c<image.cols(); c++) { for (int p=0; p<ranges->numPlanes(); p++) pixel[p] = image(p,r,c); image.set(0,r,c, pixel[permutation[0]]); if (!subtract) { for (int p=1; p<ranges->numPlanes(); p++) image.set(p,r,c, pixel[permutation[p]]); } else { for (int p=1; p<3 && p<ranges->numPlanes(); p++) image.set(p,r,c, pixel[permutation[p]] - pixel[permutation[0]]); for (int p=3; p<ranges->numPlanes(); p++) image.set(p,r,c, pixel[permutation[p]]); } } } }
bool exists(const int p, const prevPlanes &pp) const { if (p>0 && (pp[0] < min0 || pp[0] > ranges->max(0))) return false; if (p>1 && (pp[1] < min1 || pp[1] > ranges->max(1))) return false; ColorVal rmin, rmax; ColorVal v=pp[p]; ranges->snap(p,pp,rmin,rmax,v); if (v != pp[p]) return false; // bucket empty because of original range constraints const ColorBucket b = findBucket(p,pp); //if (b.min > b.max) return false; if (b.snapColor_slow(pp[p]) != pp[p]) return false; return true; }
ColorVal max(int p) const { switch(p) { case 0: return 4*par-1; case 1: return 8*par-2; case 2: return 8*par-2; default: return ranges->max(p); }; }
ColorVal max(int p) const { switch(p) { case 0: return 0; case 1: return nb_colors-1; case 2: return 0; default: return ranges->max(p); }; }
void invData(Images& images) const override { ColorVal pixel[5]; for (Image& image : images) { for (int p=0; p<ranges->numPlanes(); p++) image.undo_make_constant_plane(p); for (uint32_t r=0; r<image.rows(); r++) { for (uint32_t c=0; c<image.cols(); c++) { for (int p=0; p<ranges->numPlanes(); p++) pixel[p] = image(p,r,c); for (int p=0; p<ranges->numPlanes(); p++) image.set(permutation[p],r,c, pixel[p]); image.set(permutation[0],r,c, pixel[0]); if (!subtract) { for (int p=1; p<ranges->numPlanes(); p++) image.set(permutation[p],r,c, pixel[p]); } else { for (int p=1; p<3 && p<ranges->numPlanes(); p++) image.set(permutation[p],r,c, CLAMP(pixel[p] + pixel[0], ranges->min(permutation[p]), ranges->max(permutation[p]))); for (int p=3; p<ranges->numPlanes(); p++) image.set(permutation[p],r,c, pixel[p]); } } } } }
ColorVal min(int p) const { switch(p) { case 0: return 0; case 1: return -maximum; case 2: return -maximum; default: return ranges->min(p); }; }
ColorVal max(int p) const { switch(p) { case 0: return maximum; case 1: return maximum; case 2: return maximum; default: return ranges->max(p); }; }
void print() { printf("Y buckets:\n"); bucket0.print(); printf("\nI buckets:\n"); for (auto b : bucket1) b.print(); printf("\nQ buckets:\n "); for (auto bs : bucket2) { for (auto b : bs) b.print(); printf("\n ");} if (ranges->numPlanes() > 3) { printf("Alpha buckets:\n"); bucket3.print(); } }
void minmax(const int p, const prevPlanes &pp, ColorVal &min, ColorVal &max) const { assert(p<numPlanes()); if (p==0 || p==3) { min=bounds[p].first; max=bounds[p].second; return; } // optimization for special case ranges->minmax(p, pp, min, max); if (min < bounds[p].first) min=bounds[p].first; if (max > bounds[p].second) max=bounds[p].second; if (min>max) { // should happen only if alpha=0 interpolation produces YI combination for which Q range from ColorRangesYIQ is outside bounds min=bounds[p].first; max=bounds[p].second; } assert(min <= max); }
void minmax(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv) const { if (p==1) { minv=0; maxv=nb_colors-1; return; } else if (p<3) { minv=0; maxv=0; return; } else ranges->minmax(p,pp,minv,maxv); }
void snap(const int p, const prevPlanes &pp, ColorVal &min, ColorVal &max, ColorVal &v) const { if (p==0 || p==3) { min=bounds[p].first; max=bounds[p].second; } // optimization for special case else ranges->snap(p,pp,min,max,v); if (min < bounds[p].first) min=bounds[p].first; if (max > bounds[p].second) max=bounds[p].second; if (min>max) { // should happen only if alpha=0 interpolation produces YI combination for which Q range from ColorRangesYIQ is outside bounds min=bounds[p].first; max=bounds[p].second; } if(v>max) v=max; if(v<min) v=min; }
void initPropRanges_scanlines(Ranges &propRanges, const ColorRanges &ranges, int p) { propRanges.clear(); int min = ranges.min(p); int max = ranges.max(p); int mind = min - max, maxd = max - min; if (p < 3) { for (int pp = 0; pp < p; pp++) { propRanges.push_back(std::make_pair(ranges.min(pp), ranges.max(pp))); // pixels on previous planes } if (ranges.numPlanes()>3) propRanges.push_back(std::make_pair(ranges.min(3), ranges.max(3))); // pixel on alpha plane } propRanges.push_back(std::make_pair(min,max)); // guess (median of 3) propRanges.push_back(std::make_pair(0,2)); // which predictor was it propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); }
void initPropRanges(Ranges &propRanges, const ColorRanges &ranges, int p) { propRanges.clear(); int min = ranges.min(p); int max = ranges.max(p); int mind = min - max, maxd = max - min; if (p < 3) { // alpha channel first for (int pp = 0; pp < p; pp++) { propRanges.push_back(std::make_pair(ranges.min(pp), ranges.max(pp))); // pixels on previous planes } if (ranges.numPlanes()>3) propRanges.push_back(std::make_pair(ranges.min(3), ranges.max(3))); // pixel on alpha plane } propRanges.push_back(std::make_pair(mind,maxd)); // neighbor A - neighbor B (top-bottom or left-right) propRanges.push_back(std::make_pair(min,max)); // guess (median of 3) propRanges.push_back(std::make_pair(0,2)); // which predictor was it propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); if (p < 2 || p >= 3) { propRanges.push_back(std::make_pair(mind,maxd)); propRanges.push_back(std::make_pair(mind,maxd)); } }
ColorVal min(int p) const { if (p<3) return ranges->min(p); else if (p==3) return alpha_min; else return 0; }
ColorVal min(int p) const { return ranges->min(p); }
bool isStatic() const override { return ranges->isStatic(); }
int numPlanes() const override { return ranges->numPlanes(); }
ColorVal max(int p) const override { return ranges->max(p); }
void minmax(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv) const override { ranges->minmax(p,pp,minv,maxv); }
ColorVal max(int p) const { if (p<3) return ranges->max(p); else if (p==3) return alpha_max; else return numPrevFrames; }
ColorVal min(int p) const override { return ranges->min(p); }
int numPlanes() const { return ranges->numPlanes(); }
ColorVal min(int p) const { if (p<3) return 0; else return ranges->min(p); }
ColorVal max(int p) const { return ranges->max(p); }
void minmax(const int p, const prevPlanes &pp, ColorVal &mi, ColorVal &ma) const { if (p >= 3) { mi=min(p); ma=max(p); } else ranges->minmax(p, pp, mi, ma); }
ColorVal min(int p) const { assert(p<numPlanes()); return std::max(ranges->min(p), bounds[p].first); }
ColorVal max(int p) const { assert(p<numPlanes()); return std::min(ranges->max(p), bounds[p].second); }
void minmax(const int p, const prevPlanes &pp, ColorVal &minv, ColorVal &maxv) const { if (p==1) { minv=get_min_i(par, pp[0]); maxv=get_max_i(par, pp[0]); return; } else if (p==2) { minv=get_min_q(par, pp[0], pp[1]); maxv=get_max_q(par, pp[0], pp[1]); return; } else if (p==0) { minv=0; maxv=get_max_y(par); return;} else ranges->minmax(p,pp,minv,maxv); }