const ColorRanges* meta(Images&, const ColorRanges *srcRanges) { // cb->print(); // in the I buckets, some discrete buckets may have become continuous to keep the colorbucket info small // this means some Q buckets are empty, which means that some values from the I buckets can be eliminated really_used = true; prevPlanes pixelL,pixelU; pixelL.push_back(cb->min0); pixelU.push_back(cb->min0+CB0b-1); pixelL.push_back(cb->min1); pixelU.push_back(cb->min1+CB1-1); for (auto bv : cb->bucket2) { pixelL[1] = cb->min1; pixelU[1] = cb->min1+CB1-1; for (auto b : bv) { if (b.empty()) { for (ColorVal c=pixelL[1]; c<=pixelU[1]; c++) { cb->findBucket(1,pixelL).removeColor(c); cb->findBucket(1,pixelU).removeColor(c); } } pixelL[1] += CB1; pixelU[1] += CB1; } pixelL[0] += CB0b; pixelU[0] += CB0b; } cb->bucket0.prepare_snapvalues(); cb->bucket3.prepare_snapvalues(); for (auto& b : cb->bucket1) b.prepare_snapvalues(); for (auto& bv : cb->bucket2) for (auto& b : bv) b.prepare_snapvalues(); return new ColorRangesCB(srcRanges, cb); }
void save_bucket(const ColorBucket &b, SimpleSymbolCoder<FLIFBitChanceMeta, RacOut<IO>, 18> &coder, const ColorRanges *srcRanges, const int plane, const prevPlanes &pixelL, const prevPlanes &pixelU) const { if (plane<3) for (int p=0; p<plane; p++) { if (!cb->exists(p,pixelL,pixelU)) { if (!b.empty()) {printf("\nBucket does not exist but is not empty!\n"); assert(false);} return; } } ColorVal smin,smax; minmax(srcRanges,plane,pixelL,pixelU,smin,smax); if (b.min > b.max) { coder.write_int(0, 1, 0); // empty bucket return; } else coder.write_int(0, 1, 1); // non-empty bucket if (smin==smax) { return;} coder.write_int(smin, smax, b.min); coder.write_int(b.min, smax, b.max); if (b.min == b.max) return; // singleton bucket if (b.min + 1 == b.max) return; // bucket contains two consecutive values coder.write_int(0, 1, b.discrete); if (b.discrete) { assert((int)b.values.size() < b.max-b.min+1); // no discrete buckets that are completely full coder.write_int(2, std::min((int)max_per_colorbucket[plane],b.max-b.min), b.values.size()); ColorVal v=b.min; int nb = b.values.size(); for (int p=1; p < nb - 1; p++) { coder.write_int(v+1, b.max+1-nb+p, b.values[p]); v = b.values[p]; } } }
const ColorBucket load_bucket(SimpleSymbolCoder<FLIFBitChanceMeta, RacIn<IO>, 18> &coder, const ColorRanges *srcRanges, const int plane, const prevPlanes &pixelL, const prevPlanes &pixelU) const { ColorBucket b; if (plane<3) for (int p=0; p<plane; p++) { if (!cb->exists(p,pixelL,pixelU)) return b; } // SimpleBitCoder<FLIFBitChanceMeta, RacIn> bcoder(rac); ColorVal smin,smax; minmax(srcRanges,plane,pixelL,pixelU,smin,smax); int exists = coder.read_int(0, 1); if (exists == 0) { return b; // empty bucket } if (smin == smax) {b.min = b.max = smin; b.discrete=false; return b;} b.min = coder.read_int(smin, smax); b.max = coder.read_int(b.min, smax); if (b.min == b.max) { b.discrete=false; return b; } if (b.min + 1 == b.max) { b.discrete=false; return b; } b.discrete = coder.read_int(0,1); if (b.discrete) { int nb = coder.read_int(2, std::min((int)max_per_colorbucket[plane],b.max-b.min)); b.values.push_back(b.min); ColorVal v=b.min; for (int p=1; p < nb-1; p++) { b.values.push_back(coder.read_int(v+1, b.max+1-nb+p)); v = b.values[p]; } if (b.min < b.max) b.values.push_back(b.max); } return b; }
bool process(const ColorRanges *srcRanges, const Images &images) { std::vector<ColorVal> pixel(images[0].numPlanes()); // fill buckets for (const Image& image : images) for (uint32_t r=0; r<image.rows(); r++) { for (uint32_t c=0; c<image.cols(); c++) { int p; for (p=0; p<image.numPlanes(); p++) { ColorVal v = image(p,r,c); pixel[p] = v; } if (image.alpha_zero_special && p>3 && pixel[3]==0) { cb->findBucket(3, pixel).addColor(0,max_per_colorbucket[3]); continue;} cb->addColor(pixel); } } cb->bucket0.simplify_lossless(); cb->bucket3.simplify_lossless(); for (auto& b : cb->bucket1) b.simplify_lossless(); for (auto& bv : cb->bucket2) for (auto& b : bv) b.simplify_lossless(); // TODO: IMPROVE THESE HEURISTICS! // TAKE IMAGE SIZE INTO ACCOUNT! // CONSIDER RELATIVE AREA OF BUCKETS / BOUNDS! // printf("Filled color buckets with %i discrete colors + %i continous buckets\n",totaldiscretecolors,totalcontinuousbuckets); int64_t total_pixels = (int64_t) images.size() * images[0].rows() * images[0].cols(); v_printf(7,", [D=%i,C=%i,P=%i]",totaldiscretecolors,totalcontinuousbuckets,(int) (total_pixels/100)); if (totaldiscretecolors < total_pixels/200 && totalcontinuousbuckets < total_pixels/50) return true; if (totaldiscretecolors < total_pixels/100 && totalcontinuousbuckets < total_pixels/200) return true; if (totaldiscretecolors < total_pixels/40 && totalcontinuousbuckets < total_pixels/500) return true; // simplify buckets for (int factor = 95; factor >= 35; factor -= 10) { for (auto& b : cb->bucket1) b.simplify(factor); for (auto& bv : cb->bucket2) for (auto& b : bv) b.simplify(factor-20); v_printf(8,"->[D=%i,C=%i]",totaldiscretecolors,totalcontinuousbuckets); if (totaldiscretecolors < total_pixels/200 && totalcontinuousbuckets < total_pixels/100) return true; } return false; }
void save_bucket(const ColorBucket &b, SimpleSymbolCoder<FLIFBitChanceMeta, RacOut<IO>, 24> &coder, const ColorRanges *srcRanges, const int plane, const prevPlanes &pixelL, const prevPlanes &pixelU) const { if (plane<3) for (int p=0; p<plane; p++) { if (!cb->exists(p,pixelL,pixelU)) { if (!b.empty()) {printf("\nBucket does not exist but is not empty!\n"); assert(false);} return; } } // SimpleBitCoder<FLIFBitChanceMeta, RacOut> bcoder(rac); // if (b.min > b.max) printf("SHOULD NOT HAPPEN!\n"); ColorVal smin,smax; minmax(srcRanges,plane,pixelL,pixelU,smin,smax); if (smin==smax) { return;} // b.printshort(); // b.print(); if (b.min > b.max) { coder.write_int(0, 1, 0); // empty bucket return; } else coder.write_int(0, 1, 1); // non-empty bucket coder.write_int(smin, smax, b.min); coder.write_int(b.min, smax, b.max); if (b.min == b.max) return; // singleton bucket if (b.min + 1 == b.max) return; // bucket contains two consecutive values coder.write_int(0, 1, b.discrete); if (b.discrete) { coder.write_int(2, max_per_colorbucket[plane], b.values.size()); ColorVal v=b.min; /* if (b.values.size() > 10) { v++; bcoder.set( 0x1000 * (b.values.size()-2) / (b.max-b.min-1) ); for (unsigned int p=1; p < b.values.size() - 1; p++) { while (v<b.values[p]) { bcoder.write(0); v++; } bcoder.write(1); v++; } } else */ for (unsigned int p=1; p < b.values.size() - 1; p++) { coder.write_int(v+1, b.max-1, b.values[p]); // coder.write_int(0, b.max-v-2, b.values[p]-v-1); v = b.values[p]; } } }
ColorBucket load_bucket(SimpleSymbolCoder<FLIFBitChanceMeta, RacIn<IO>, 24> &coder, const ColorRanges *srcRanges, const int plane, const prevPlanes &pixelL, const prevPlanes &pixelU) { ColorBucket b; if (plane<3) for (int p=0; p<plane; p++) { if (!cb->exists(p,pixelL,pixelU)) return b; } // SimpleBitCoder<FLIFBitChanceMeta, RacIn> bcoder(rac); ColorVal smin,smax; minmax(srcRanges,plane,pixelL,pixelU,smin,smax); if (smin == smax) {b.min = b.max = smin; b.discrete=false; return b;} int exists = coder.read_int(0, 1); if (exists == 0) { return b; // empty bucket } b.min = coder.read_int(smin, smax); b.max = coder.read_int(b.min, smax); if (b.min == b.max) { b.discrete=false; return b; } if (b.min + 1 == b.max) { b.discrete=false; return b; } b.discrete = coder.read_int(0,1); if (b.discrete) { int nb = coder.read_int(2, max_per_colorbucket[plane]); b.values.push_back(b.min); ColorVal v=b.min; /* if (nb > 10) { v++; bcoder.set( 0x1000 * (nb-2) / (b.max-b.min-1) ); for (int p=1; p < nb - 1; p++) { while (bcoder.read() == 0) { v++; } b.values.push_back(v); v++; } } else */ for (int p=1; p < nb-1; p++) { b.values.push_back(coder.read_int(v+1, b.max-1)); // b.values.push_back(v+1+coder.read_int(0, b.max-v-2)); // printf("val %i\n",b.values[p]); v = b.values[p]; } if (b.min < b.max) b.values.push_back(b.max); } // b.print(); return b; }
void print() { buckets->print(); }
ColorBucket bucket(const int p, const prevPlanes &pp) const { return buckets->findBucket(p,pp); }