Пример #1
0
Файл: flif.cpp Проект: uxn/FLIF
int handle_decode(char **argv, Images &images, int quality, int scale) {
    char *ext = strrchr(argv[1],'.');
    if (!check_compatible_extension(ext)) {
        e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n");
        return 1;
    }
    const auto tim0 = high_resolution_clock::now();
    if (!decode_flif(argv, images, quality, scale)) {e_printf("Error: could not decode FLIF file\n"); return 3; }
    const auto tim1 = high_resolution_clock::now();
    printf("decoded in %lld msec\n", duration_cast<milliseconds>(tim1 - tim0).count());
    if (scale>1)
        v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale);
    if (images.size() == 1) {
        if (!images[0].save(argv[1],scale)) return 2;
    } else {
        int counter=0;
        std::vector<char> vfilename(strlen(argv[1])+6);
        char *filename = &vfilename[0];
        strcpy(filename,argv[1]);
        char *a_ext = strrchr(filename,'.');
        for (Image& image : images) {
            sprintf(a_ext,"-%03d%s",counter++,ext);
            if (!image.save(filename,scale)) return 2;
            v_printf(2,"    (%i/%i)         \r",counter,(int)images.size()); v_printf(4,"\n");
        }
    }
    v_printf(2,"\n");
    return 0;
}
Пример #2
0
 bool process(const ColorRanges *srcRanges, const Images &images) {
     int np=srcRanges->numPlanes();
     nb = images.size();
     seen_before.clear();
     seen_before.resize(nb,-1);
     bool dupes_found=false;
     for (unsigned int fr=1; fr<images.size(); fr++) {
         const Image& image = images[fr];
         for (unsigned int ofr=0; ofr<fr; ofr++) {
           const Image& oimage = images[ofr];
           bool identical=true;
           for (uint32_t r=0; r<image.rows(); r++) {
             for (uint32_t c=0; c<image.cols(); c++) {
                 for (int p=0; p<np; p++) {
                    if(image(p,r,c) != oimage(p,r,c)) { identical=false; break;}
                 }
                 if (!identical) {break;}
             }
             if (!identical) {break;}
           }
           if (identical) {seen_before[fr] = ofr; dupes_found=true; break;}
         }
     }
     return dupes_found;
 }
Пример #3
0
int handle_decode(char **argv, Images &images, int quality, int scale) {
    char *ext = strrchr(argv[1],'.');
    if (!check_compatible_extension(ext)) {
        e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n");
        return 1;
    }
    if (!decode_flif(argv, images, quality, scale)) return 3;
    if (scale>1)
        v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale);
    if (images.size() == 1) {
        if (!images[0].save(argv[1],scale)) return 2;
    } else {
        int counter=0;
        std::vector<char> vfilename(strlen(argv[1])+6);
        char *filename = &vfilename[0];
        strcpy(filename,argv[1]);
        char *a_ext = strrchr(filename,'.');
        for (Image& image : images) {
            sprintf(a_ext,"-%03d%s",counter++,ext);
            if (!image.save(filename,scale)) return 2;
            v_printf(2,"    (%i/%i)         \r",counter,(int)images.size()); v_printf(4,"\n");
        }
    }
    v_printf(2,"\n");
    return -1;
}
Пример #4
0
bool encode_load_input_images(int argc, char **argv, Images &images) {
    int nb_input_images = argc-1;
    while(argc>1) {
        Image image;
        v_printf(2,"\r");
        if (!image.load(argv[0])) {
            e_printf("Could not read input file: %s\n", argv[0]);
            return false;
        };
        images.push_back(std::move(image));
        Image& last_image = images.back();
        if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols()) {
            e_printf("Dimensions of all input images should be the same!\n");
            e_printf("  First image is %ux%u\n",images[0].cols(),images[0].rows());
            e_printf("  This image is %ux%u: %s\n",last_image.cols(),last_image.rows(),argv[0]);
            return false;
        }
        if (last_image.numPlanes() < images[0].numPlanes()) {
            if (images[0].numPlanes() == 3) last_image.ensure_chroma();
            else if (images[0].numPlanes() == 4) last_image.ensure_alpha();
            else { e_printf("Problem while loading input images, please report this.\n"); return false; }
        } else if (last_image.numPlanes() > images[0].numPlanes()) {
            if (last_image.numPlanes() == 3) { for (Image& i : images) i.ensure_chroma(); }
            else if (last_image.numPlanes() == 4) { for (Image& i : images) i.ensure_alpha(); }
            else { e_printf("Problem while loading input images, please report this.\n"); return false; }
        }
        argc--; argv++;
        if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
    }
    v_printf(2,"\n");
    return true;
}
Пример #5
0
template<typename Coder> void flif_decode_scanlines_inner(std::vector<Coder> &coders, Images &images, const ColorRanges *ranges)
{

    ColorVal min,max;
    int nump = images[0].numPlanes();
    for (int k=0,i=0; k < 5; k++) {
        int p=PLANE_ORDERING[k];
        if (p>=nump) continue;
        i++;
        Properties properties((nump>3?NB_PROPERTIES_scanlinesA[p]:NB_PROPERTIES_scanlines[p]));
        v_printf(2,"\r%i%% done [%i/%i] DEC[%ux%u]    ",(int)(100*pixels_done/pixels_todo),i,nump,images[0].cols(),images[0].rows());
        v_printf(4,"\n");
        pixels_done += images[0].cols()*images[0].rows();
        if (ranges->min(p) >= ranges->max(p)) continue;
        for (uint32_t r = 0; r < images[0].rows(); r++) {
            for (int fr=0; fr< (int)images.size(); fr++) {
              Image& image = images[fr];
              uint32_t begin=image.col_begin[r], end=image.col_end[r];
              if (image.seen_before >= 0) { for(uint32_t c=0; c<image.cols(); c++) image.set(p,r,c,images[image.seen_before](p,r,c)); continue; }
              if (fr>0) {
                for (uint32_t c = 0; c < begin; c++)
                   if (nump>3 && p<3 && image(3,r,c) == 0) image.set(p,r,c,predict_and_calcProps_scanlines(properties,ranges,image,p,r,c,min,max));
                   else if (p !=4 ) image.set(p,r,c,images[fr-1](p,r,c));
                   /*
                   else if (nump>4 && p<4 && image(4,r,c) > 0) image.set(p,r,c,images[fr-image(4,r,c)](p,r,c));
                   else {
                     int oldframe=fr-1;  image.set(p,r,c,images[oldframe](p,r,c));
                     while(p == 4 && image(p,r,c) > 0) {oldframe -= image(p,r,c); assert(oldframe>=0); image.set(p,r,c,images[oldframe](p,r,c));}
                   }
                   */
              } else {
                if (nump>3 && p<3) { begin=0; end=image.cols(); }
              }
              for (uint32_t c = begin; c < end; c++) {
                ColorVal guess = predict_and_calcProps_scanlines(properties,ranges,image,p,r,c,min,max);
                if (p==4 && max > fr) max = fr;
                if (nump>3 && p<3 && image(3,r,c) == 0) {image.set(p,r,c,guess); continue;}
                if (nump>4 && p<4 && image(4,r,c) > 0) {image.set(p,r,c,images[fr-image(4,r,c)](p,r,c)); continue;}
                ColorVal curr = coders[p].read_int(properties, min - guess, max - guess) + guess;
                image.set(p,r,c, curr);
              }
              if (fr>0) {
                for (uint32_t c = end; c < image.cols(); c++)
                   if (nump>3 && p<3 && image(3,r,c) == 0) image.set(p,r,c,predict_and_calcProps_scanlines(properties,ranges,image,p,r,c,min,max));
                   else if (p !=4 ) image.set(p,r,c,images[fr-1](p,r,c));
/*                   else if (nump>4 && p<4 && image(4,r,c) > 0) image.set(p,r,c,images[fr-image(4,r,c)](p,r,c));
                   else {
                     int oldframe=fr-1;  image.set(p,r,c,images[oldframe](p,r,c));
                     while(p == 4 && image(p,r,c) > 0) {oldframe -= image(p,r,c); assert(oldframe>=0); image.set(p,r,c,images[oldframe](p,r,c));}
                   }*/
              }
            }
        }
    }
}
Пример #6
0
bool encode_flif(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback, int learn_repeats, int frame_delay, int divisor=CONTEXT_TREE_COUNT_DIV, int min_size=CONTEXT_TREE_MIN_SUBTREE_SIZE, int split_threshold=CONTEXT_TREE_SPLIT_THRESHOLD, int yiq=1, int plc=1) {
    bool flat=true;
    for (Image &image : images) if (image.uses_alpha()) flat=false;
    if (flat && images[0].numPlanes() == 4) {
        v_printf(2,"Alpha channel not actually used, dropping it.\n");
        for (Image &image : images) image.drop_alpha();
    }
    bool grayscale=true;
    for (Image &image : images) if (image.uses_color()) grayscale=false;
    if (grayscale && images[0].numPlanes() == 3) {
        v_printf(2,"Chroma not actually used, dropping it.\n");
        for (Image &image : images) image.drop_color();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    if (nb_pixels > 2) {         // no point in doing anything for 1- or 2-pixel images
      if (plc)
        desc.push_back("PLC");  // compactify channels
      if (yiq)
        desc.push_back("YIQ");  // convert RGB(A) to YIQ(A)
        desc.push_back("BND");  // get the bounds of the color spaces
    }
    if (palette_size < 0) {
        palette_size = 1024;
        if (nb_pixels * images.size() / 2 < 1024) palette_size = nb_pixels * images.size() / 2;
    }
    if (palette_size > 0)
        desc.push_back("PLA");  // try palette (including alpha)
    if (palette_size > 0)
        desc.push_back("PLT");  // try palette (without alpha)

    if (acb == -1) {
        // not specified if ACB should be used
        if (nb_pixels * images.size() > 10000) desc.push_back("ACB");  // try auto color buckets on large images
    } else if (acb) desc.push_back("ACB");  // try auto color buckets if forced
    if (method.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels * images.size() < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else method.encoding=flifEncoding::interlaced; // default method: interlacing
    }
    if (images.size() > 1) {
        desc.push_back("DUP");  // find duplicate frames
        desc.push_back("FRS");  // get the shapes of the frames
        if (lookback != 0) desc.push_back("FRA");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
    }
    if (learn_repeats < 0) {
        // no number of repeats specified, pick a number heuristically
        learn_repeats = TREE_LEARN_REPEATS;
        if (nb_pixels * images.size() < 5000) learn_repeats--;        // avoid large trees for small images
        if (learn_repeats < 0) learn_repeats=0;
    }
    FILE *file = fopen(argv[0],"wb");
    if (!file)
        return false;
    FileIO fio(file, argv[0]);
    return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, frame_delay, palette_size, lookback, divisor, min_size, split_threshold);
}
Пример #7
0
 bool process(const ColorRanges *srcRanges, const Images &images) {
     if (images.size()<2) return false;
     int np=srcRanges->numPlanes();
     nb = 0;
     cols = images[0].cols();
     for (unsigned int fr=1; fr<images.size(); fr++) {
         const Image& image = images[fr];
         if (image.seen_before >= 0) continue;
         nb += image.rows();
         for (uint32_t r=0; r<image.rows(); r++) {
             bool beginfound=false;
             for (uint32_t c=0; c<image.cols(); c++) {
                 if (image.alpha_zero_special && np>3 && image(3,r,c) == 0 && images[fr-1](3,r,c)==0) continue;
                 for (int p=0; p<np; p++) {
                    if(image(p,r,c) != images[fr-1](p,r,c)) { beginfound=true; break;}
                 }
                 if (beginfound) {b.push_back(c); break;}
             }
             if (!beginfound) {b.push_back(image.cols()); e.push_back(image.cols()); continue;}
             bool endfound=false;
             for (uint32_t c=image.cols()-1; c >= b.back(); c--) {
                 if (image.alpha_zero_special && np>3 && image(3,r,c) == 0 && images[fr-1](3,r,c)==0) continue;
                 for (int p=0; p<np; p++) {
                    if(image(p,r,c) != images[fr-1](p,r,c)) { endfound=true; break;}
                 }
                 if (endfound) {e.push_back(c+1); break;}
             }
             if (!endfound) {e.push_back(0); continue;} //shouldn't happen, right?
         }
     }
     /* does not seem to do much good at all
     if (nb&1) {b.push_back(b[nb-1]); e.push_back(e[nb-1]);}
     for (unsigned int i=0; i<nb; i+=2) { b[i]=b[i+1]=std::min(b[i],b[i+1]); }
     for (unsigned int i=0; i<nb; i+=2) { e[i]=e[i+1]=std::max(e[i],e[i+1]); }
     */
     return true;
 }
Пример #8
0
int handle_decode(int argc, char **argv, Images &images, int quality, int scale, int resize_width, int resize_height) {
    if (scale < 0) {
        // just identify the file(s), don't actually decode
        while (argc>0) {
            decode_flif(argv, images, quality, scale, resize_width, resize_height);
            argv++; argc--;
        }
        return 0;
    }
    char *ext = strrchr(argv[1],'.');
    if (!check_compatible_extension(ext) && strcmp(argv[1],"null:")) {
        e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n");
        return 1;
    }
    if (!decode_flif(argv, images, quality, scale, resize_width, resize_height)) {
        e_printf("Error: could not decode FLIF file\n"); return 3;
    }
    if (!strcmp(argv[1],"null:")) return 0;
//    if (scale>1)
//        v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale);
    if (images.size() == 1) {
        if (!images[0].save(argv[1])) return 2;
    } else {
        int counter=0;
        std::vector<char> vfilename(strlen(argv[1])+6);
        char *filename = &vfilename[0];
        strcpy(filename,argv[1]);
        char *a_ext = strrchr(filename,'.');
        for (Image& image : images) {
            sprintf(a_ext,"-%03d%s",counter++,ext);
            if (!image.save(filename)) return 2;
            v_printf(2,"    (%i/%i)         \r",counter,(int)images.size()); v_printf(4,"\n");
        }
    }
    v_printf(2,"\n");
    return 0;
}
Пример #9
0
void Enhancer::analyze(void)
{
	for (int i=0; i<p_files->size(); i++) {
		Images *images = p_files->at(i)->load_images();
		for (int idx=0; idx<images->size(); idx++) {
			Image *img = images->at(idx);
			//img->gen_preview();
			//img->gen_thumbnail();
			img->analyse(&m_filterQueue);
			//img->free_pix();
			p_images->push_back(img);
		}
		delete images;
		std::cout << i << std::endl;
	}
}
Пример #10
0
    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;
    }
Пример #11
0
// a heuristic to figure out if this is going to help (it won't help if we introduce more entropy than what is eliminated)
    bool process(const ColorRanges *srcRanges, const Images &images) {
        if (images.size() < 2) return false;
        int nump=images[0].numPlanes();
        nb_frames = images.size();
        int64_t pixel_cost = 1;
        for (int p=0; p<nump; p++) pixel_cost *= (1 + srcRanges->max(p) - srcRanges->min(p));
        // pixel_cost is roughly the cost per pixel (number of different values a pixel can take)
        if (pixel_cost < 16) {v_printf(7,", no_FRA[pixels_too_cheap:%i]", pixel_cost); return false;} // pixels are too cheap, no point in trying to save stuff
        std::vector<uint64_t> found_pixels(images.size(), 0);
        uint64_t new_pixels=0;
        max_lookback=1;
        if (user_max_lookback == -1) user_max_lookback = images.size()-1;
        for (int fr=1; fr < (int)images.size(); fr++) {
            const Image& image = images[fr];
            for (uint32_t r=0; r<image.rows(); r++) {
                for (uint32_t c=image.col_begin[r]; c<image.col_end[r]; c++) {
                    new_pixels++;
                    for (int prev=1; prev <= fr; prev++) {
                        if (prev>user_max_lookback) break;
                        bool identical=true;
                        if (image.alpha_zero_special && nump>3 && image(3,r,c) == 0 && images[fr-prev](3,r,c) == 0) identical=true;
                        else
                        for (int p=0; p<nump; p++) {
                          if(image(p,r,c) != images[fr-prev](p,r,c)) { identical=false; break;}
                        }
                        if (identical) { found_pixels[prev]++; new_pixels--; if (prev>max_lookback) max_lookback=prev; break;}
                    }
                }
            }
        }
        if (images.size() > 2) v_printf(7,", trying_FRA(at -1: %llu, at -2: %llu, new: %llu)",(long long unsigned) found_pixels[1],(long long unsigned) found_pixels[2], (long long unsigned) new_pixels);
        if (max_lookback>256) max_lookback=256;
        for(int i=1; i <= max_lookback; i++) {
            v_printf(8,"at lookback %i: %llu pixels\n",-i, found_pixels[i]);
            if (found_pixels[i] <= new_pixels/200 || i>pixel_cost) {max_lookback=i-1; break;}
            found_pixels[0] += found_pixels[i];
        }
        for(int i=max_lookback+1; i<(int)images.size(); i++) {
            if (found_pixels[i] > new_pixels/200 && i<pixel_cost) {max_lookback=i; found_pixels[0] += found_pixels[i];}
            else new_pixels += found_pixels[i];
        }

        return (found_pixels[0] * pixel_cost > new_pixels * (2 + max_lookback));
    };
Пример #12
0
    void data(Images &images) const {
        for (int fr=1; fr < (int)images.size(); fr++) {
            uint32_t ipixels=0;
            Image& image = images[fr];
            for (uint32_t r=0; r<image.rows(); r++) {
                for (uint32_t c=image.col_begin[r]; c<image.col_end[r]; c++) {
                    for (int prev=1; prev <= fr; prev++) {
                        if (prev>max_lookback) break;
                        bool identical=true;
                        if (image.alpha_zero_special && image(3,r,c) == 0 && images[fr-prev](3,r,c) == 0) identical=true;
                        else
                        for (int p=0; p<4; p++) {
                          if(image(p,r,c) != images[fr-prev](p,r,c)) { identical=false; break;}
                        }
                        if (identical) {image.set(4,r,c, prev); ipixels++; break;}
                    }
                }
            }
//            printf("frame %i: found %u pixels from previous frames\n", fr, ipixels);
        }
    }
Пример #13
0
bool encode_load_input_images(int argc, char **argv, Images &images) {
    int nb_input_images = argc-1;
    while(argc>1) {
        Image image;
        v_printf(2,"\r");
        if (!image.load(argv[0])) {
            e_printf("Could not read input file: %s\n", argv[0]);
            return false;
        };
        images.push_back(std::move(image));
        const Image& last_image = images.back();
        if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols() || last_image.numPlanes() != images[0].numPlanes()) {
            e_printf("Dimensions of all input images should be the same!\n");
            e_printf("  First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes());
            e_printf("  This image is %ux%u, %i channels: %s\n",last_image.cols(),last_image.rows(),last_image.numPlanes(),argv[0]);
            return false;
        }
        argc--; argv++;
        if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
    }
    v_printf(2,"\n");
    return true;
}
Пример #14
0
bool handle_encode_arguments(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback, int learn_repeats, int frame_delay) {
    int nb_input_images = argc-1;
    while(argc>1) {
        Image image;
        v_printf(2,"\r");
        if (!image.load(argv[0])) {
            e_printf("Could not read input file: %s\n", argv[0]);
            return 2;
        };
        images.push_back(std::move(image));
        const Image& last_image = images.back();
		if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols() || last_image.numPlanes() != images[0].numPlanes()) {
            e_printf("Dimensions of all input images should be the same!\n");
            e_printf("  First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes());
            e_printf("  This image is %ux%u, %i channels: %s\n",last_image.cols(),last_image.rows(),last_image.numPlanes(),argv[0]);
            return 2;
        }
        argc--; argv++;
        if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
    }
    v_printf(2,"\n");
    bool flat=true;
    for (Image &image : images) if (image.uses_alpha()) flat=false;
    if (flat && images[0].numPlanes() == 4) {
        v_printf(2,"Alpha channel not actually used, dropping it.\n");
        for (Image &image : images) image.drop_alpha();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    desc.push_back("YIQ");  // convert RGB(A) to YIQ(A)
    desc.push_back("BND");  // get the bounds of the color spaces
    if (palette_size > 0)
        desc.push_back("PLA");  // try palette (including alpha)
    if (palette_size > 0)
        desc.push_back("PLT");  // try palette (without alpha)
    if (acb == -1) {
        // not specified if ACB should be used
        if (nb_pixels > 10000) desc.push_back("ACB");  // try auto color buckets on large images
    } else if (acb) desc.push_back("ACB");  // try auto color buckets if forced
    if (method.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else method.encoding=flifEncoding::interlaced; // default method: interlacing
    }
    if (images.size() > 1) {
        desc.push_back("DUP");  // find duplicate frames
        desc.push_back("FRS");  // get the shapes of the frames
        if (lookback != 0) desc.push_back("FRA");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
    }
    if (learn_repeats < 0) {
        // no number of repeats specified, pick a number heuristically
        learn_repeats = TREE_LEARN_REPEATS;
        if (nb_pixels < 5000) learn_repeats--;        // avoid large trees for small images
        if (learn_repeats < 0) learn_repeats=0;
    }
    FILE *file = fopen(argv[0],"wb");
    if (!file)
        return false;
    FileIO fio(file, argv[0]);
    return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, frame_delay, palette_size, lookback);
}
Пример #15
0
bool flif_decode(IO& io, Images &images, int quality, int scale, uint32_t (*callback)(int,int), Images &partial_images) {
    if (scale != 1 && scale != 2 && scale != 4 && scale != 8 && scale != 16 && scale != 32 && scale != 64 && scale != 128) {
                e_printf("Invalid scale down factor: %i\n", scale);
                return false;
    }

    char buff[5];
    if (!io.gets(buff,5)) { e_printf("Could not read header from file: %s\n",io.getName()); return false; }
    if (!strcmp(buff,"!<ar")) {
       // FLIF file in an archive, try to find find the main image
       if (!io.gets(buff,5)) return false;
       if (strcmp(buff,"ch>\n")) return false;
       char ar_header[61];
       while (true) {
          if (!io.gets(ar_header,61)) { e_printf("Archive does not contain a FLIF image\n"); return false; }
          if (!strncmp(ar_header,"__image.flif/",13)) {
            if (!io.gets(buff,5)) { e_printf("Corrupt archive?\n"); return false; }
            break;
          }
          else {
            long skip = strtol(&ar_header[48],NULL,10);
            if (skip < 0) return false;
            if (skip & 1) skip++;
            io.fseek(skip,SEEK_CUR);
          }
       }
    }
    if (strcmp(buff,"FLIF")) { e_printf("Not a FLIF file: %s (header: \"%s\")\n",io.getName(),buff); return false; }
    int c = io.getc();
    if (c < ' ' || c > ' '+32+15+32) { e_printf("Invalid or unknown FLIF format byte\n"); return false;}
    c -= ' ';
    int numFrames=1;
    if (c > 47) {
        c -= 32;
        numFrames = io.getc();
        if (numFrames < 2 || numFrames >= 255) return false;
    }
    const int encoding=c/16;
    if (encoding < 1 || encoding > 2) { e_printf("Invalid or unknown FLIF encoding method\n"); return false;}
    if (scale != 1 && encoding==1) { v_printf(1,"Cannot decode non-interlaced FLIF file at lower scale! Ignoring scale...\n");}
    if (quality < 100 && encoding==1) { v_printf(1,"Cannot decode non-interlaced FLIF file at lower quality! Ignoring quality...\n");}
    int numPlanes=c%16;
    if (numPlanes < 1 || numPlanes > 4) {e_printf("Invalid FLIF header (unsupported color channels)\n"); return false;}
    c = io.getc();
    if (c < '0' || c > '2')  {e_printf("Invalid FLIF header (unsupported color depth)\n"); return false;}

    int width=io.getc() << 8;
    width += io.getc();
    int height=io.getc() << 8;
    height += io.getc();
    if (width < 1 || height < 1) {e_printf("Invalid FLIF header\n"); return false;}

    // TODO: implement downscaled decoding without allocating a fullscale image buffer!

    RacIn<IO> rac(io);
    SimpleSymbolCoder<FLIFBitChanceMeta, RacIn<IO>, 24> metaCoder(rac);

//    image.init(width, height, 0, 0, 0);
    v_printf(3,"Decoding %ux%u image, channels:",width,height);
    int maxmax=0;
    for (int p = 0; p < numPlanes; p++) {
//        int min = 0;
        int max = 255;
        if (c=='2') max=65535;
        else if (c=='0') max=(1 << metaCoder.read_int(1, 16)) - 1;
        if (max>maxmax) maxmax=max;
//        image.add_plane(min, max);
//        v_printf(2," [%i] %i bpp (%i..%i)",p,ilog2(image.max(p)+1),image.min(p), image.max(p));
        if (c=='0') v_printf(3," [%i] %i bpp",p,ilog2(max+1));
    }
    if (c=='1') v_printf(3," %i, depth: 8 bit",numPlanes);
    if (c=='2') v_printf(3," %i, depth: 16 bit",numPlanes);
    if (numFrames>1) v_printf(3,", frames: %i",numFrames);
    v_printf(3,"\n");

    if (numFrames>1) {
        // ignored for now (assuming loop forever)
        metaCoder.read_int(0, 100); // repeats (0=infinite)
    }

    for (int i=0; i<numFrames; i++) {
      images.push_back(Image());
      if (!images[i].init(width,height,0,maxmax,numPlanes)) return false;
      if (numFrames>1) images[i].frame_delay = metaCoder.read_int(0, 60000); // time in ms between frames
      if (callback) partial_images.push_back(Image());
      //if (numFrames>1) partial_images[i].frame_delay = images[i].frame_delay;
    }
    std::vector<const ColorRanges*> rangesList;
    std::vector<Transform<IO>*> transforms;
    rangesList.push_back(getRanges(images[0]));
    v_printf(4,"Transforms: ");
    int tcount=0;
    transform_l=0;
    while (rac.read()) {
        if (transform_l > MAX_TRANSFORM) return false;
        std::string desc = read_name(rac);
        Transform<IO> *trans = create_transform<IO>(desc);
        if (!trans) {
            e_printf("Unknown transformation '%s'\n", desc.c_str());
            return false;
        }
        if (!trans->init(rangesList.back())) {
            e_printf("Transformation '%s' failed\n", desc.c_str());
            return false;
        }
        if (tcount++ > 0) v_printf(4,", ");
        v_printf(4,"%s", desc.c_str());
        if (desc == "FRA" && images.size()<2) return false;
        if (desc == "FRS") {
                if (images.size()<2) return false;
                int unique_frames=images.size()-1; // not considering first frame
                for (Image& i : images) if (i.seen_before >= 0) unique_frames--;
                if (unique_frames < 1) {return false;}
                trans->configure(unique_frames*images[0].rows()); trans->configure(images[0].cols()); }
        if (desc == "DUP") { if (images.size()<2) return false; else trans->configure(images.size()); }
        if (!trans->load(rangesList.back(), rac)) return false;
        rangesList.push_back(trans->meta(images, rangesList.back()));
        transforms.push_back(trans);
    }
    if (tcount==0) v_printf(4,"none\n"); else v_printf(4,"\n");
    const ColorRanges* ranges = rangesList.back();
    grey.clear();
    for (int p = 0; p < ranges->numPlanes(); p++) grey.push_back((ranges->min(p)+ranges->max(p))/2);

    pixels_todo = (int64_t)width*height*ranges->numPlanes()/scale/scale;
    pixels_done = 0;

    for (int p = 0; p < ranges->numPlanes(); p++) {
      v_printf(7,"Plane %i: %i..%i\n",p,ranges->min(p),ranges->max(p));
    }

    for (int p = 0; p < ranges->numPlanes(); p++) {
        if (ranges->min(p) >= ranges->max(p)) {
             v_printf(4,"Constant plane %i at color value %i\n",p,ranges->min(p));
             //for (ColorVal_intern& x : image(p).data) x=ranges->min(p);
            for (int fr = 0; fr < numFrames; fr++)
            for (uint32_t r=0; r<images[fr].rows(); r++) {
              for (uint32_t c=0; c<images[fr].cols(); c++) {
                images[fr].set(p,r,c,ranges->min(p));
              }
            }
        }
    }
    int mbits = 0;
    for (int p = 0; p < ranges->numPlanes(); p++) {
        if (ranges->max(p) > ranges->min(p)) {
          int nBits = ilog2((ranges->max(p) - ranges->min(p))*2-1)+1;
          if (nBits > mbits) mbits = nBits;
        }
    }
    int bits = 10;
#ifdef SUPPORT_HDR
    if (mbits >10) bits=18;
#endif
    if (mbits > bits) { e_printf("This FLIF cannot decode >8 bit per channel files. Please compile with SUPPORT_HDR.\n"); return false;}


    std::vector<Tree> forest(ranges->numPlanes(), Tree());
    int roughZL = 0;
    if (encoding == 2) {
      roughZL = images[0].zooms() - NB_NOLEARN_ZOOMS-1;
      if (roughZL < 0) roughZL = 0;
//      v_printf(2,"Decoding rough data\n");
      if (bits==10) flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 10> >(rac, images, ranges, forest, images[0].zooms(), roughZL+1, 100, scale, transforms, callback, partial_images);
#ifdef SUPPORT_HDR
      else flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 18> >(rac, images, ranges, forest, images[0].zooms(), roughZL+1, 100, scale, transforms, callback, partial_images);
#endif
    }
    if (encoding == 2 && quality <= 0) {
      v_printf(3,"Not decoding MANIAC tree\n");
    } else {
      v_printf(3,"Decoded header + rough data. Decoding MANIAC tree.\n");
      if (!flif_decode_tree<FLIFBitChanceTree, RacIn<IO>>(rac, ranges, forest, encoding)) return false;
    }


    switch(encoding) {
        case 1: v_printf(3,"Decoding data (scanlines)\n");
                if (bits==10) flif_decode_scanlines_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 10> >(rac, images, ranges, forest, transforms, callback, partial_images);
#ifdef SUPPORT_HDR
                else flif_decode_scanlines_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 18> >(rac, images, ranges, forest, transforms, callback, partial_images);
#endif
                break;
        case 2: v_printf(3,"Decoding data (interlaced)\n");
                if (bits==10) flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 10> >(rac, images, ranges, forest, roughZL, 0, quality, scale, transforms, callback, partial_images);
#ifdef SUPPORT_HDR
                else flif_decode_FLIF2_pass<IO, RacIn<IO>, FinalPropertySymbolCoder<FLIFBitChancePass2, RacIn<IO>, 18> >(rac, images, ranges, forest, roughZL, 0, quality, scale, transforms, callback, partial_images);
#endif
                break;
    }
 

    if (quality==100 && scale==1) {
      uint32_t checksum = images[0].checksum();
      v_printf(8,"Computed checksum: %X\n", checksum);
      uint32_t checksum2 = metaCoder.read_int(0, 0xFFFF);
      checksum2 *= 0x10000;
      checksum2 += metaCoder.read_int(0, 0xFFFF);
      v_printf(8,"Read checksum: %X\n", checksum2);
      if (checksum != checksum2) v_printf(1,"\nCORRUPTION DETECTED! (partial file?)\n\n");
      else v_printf(2,"Image decoded, checksum verified.\n");
    } else {
      v_printf(2,"Not checking checksum, lossy partial decoding was chosen.\n");
    }

   if (numFrames==1)
      v_printf(2,"\rDecoding done, %li bytes for %ux%u pixels (%.4fbpp)   \n",rac.ftell(), images[0].cols()/scale, images[0].rows()/scale, 8.0*rac.ftell()/images[0].rows()/images[0].cols()/scale/scale);
    else
      v_printf(2,"\rDecoding done, %li bytes for %i frames of %ux%u pixels (%.4fbpp)   \n",rac.ftell(), numFrames, images[0].cols()/scale, images[0].rows()/scale, 8.0*rac.ftell()/numFrames/images[0].rows()/images[0].cols()/scale/scale);


    for (int i=(int)transforms.size()-1; i>=0; i--) {
        transforms[i]->invData(images);
        delete transforms[i];
    }
    transforms.clear();


    for (unsigned int i=0; i<rangesList.size(); i++) {
        delete rangesList[i];
    }
    rangesList.clear();

    return true;
}
Пример #16
0
template<typename IO, typename Rac, typename Coder> void flif_decode_scanlines_inner(Rac &rac, std::vector<Coder> &coders, Images &images, const ColorRanges *ranges, std::vector<Transform<IO>*> &transforms, uint32_t (*callback)(int,int), Images &partial_images) {
    ColorVal min,max;
    int nump = images[0].numPlanes();
    int progressive_qual_target = 0;
    if (callback) {
         // initialize planes to grey
         for (int p=0; p<nump; p++) {
           for (int fr=0; fr< (int)images.size(); fr++) {
            for (uint32_t r=0; r<images[fr].rows(); r++) {
              for (uint32_t c=0; c<images[fr].cols(); c++) {
                images[fr].set(p,r,c,(ranges->min(p)+ranges->max(p))/2);
              }
            }
           }
         }
    }
    for (int k=0,i=0; k < 5; k++) {
        int p=PLANE_ORDERING[k];
        if (p>=nump) continue;
        i++;
        Properties properties((nump>3?NB_PROPERTIES_scanlinesA[p]:NB_PROPERTIES_scanlines[p]));
        v_printf(2,"\r%i%% done [%i/%i] DEC[%ux%u]    ",(int)(100*pixels_done/pixels_todo),i,nump,images[0].cols(),images[0].rows());
        v_printf(4,"\n");
        pixels_done += images[0].cols()*images[0].rows();
        if (ranges->min(p) < ranges->max(p))
        for (uint32_t r = 0; r < images[0].rows(); r++) {
            for (int fr=0; fr< (int)images.size(); fr++) {
              Image& image = images[fr];
              uint32_t begin=image.col_begin[r], end=image.col_end[r];
              if (image.seen_before >= 0) { for(uint32_t c=0; c<image.cols(); c++) image.set(p,r,c,images[image.seen_before](p,r,c)); continue; }
              if (fr>0) {
                for (uint32_t c = 0; c < begin; c++)
                   if (nump>3 && p<3 && image(3,r,c) == 0) image.set(p,r,c,predict(image,p,r,c));
                   else if (p !=4 ) image.set(p,r,c,images[fr-1](p,r,c));
                   /*
                   else if (nump>4 && p<4 && image(4,r,c) > 0) image.set(p,r,c,images[fr-image(4,r,c)](p,r,c));
                   else {
                     int oldframe=fr-1;  image.set(p,r,c,images[oldframe](p,r,c));
                     while(p == 4 && image(p,r,c) > 0) {oldframe -= image(p,r,c); assert(oldframe>=0); image.set(p,r,c,images[oldframe](p,r,c));}
                   }
                   */
              } else {
                if (nump>3 && p<3) { begin=0; end=image.cols(); }
              }
              for (uint32_t c = begin; c < end; c++) {
                if (nump>3 && p<3 && image(3,r,c) == 0) {image.set(p,r,c,predict(image,p,r,c)); continue;}
                if (nump>4 && p<4 && image(4,r,c) > 0) {assert(fr >= image(4,r,c)); image.set(p,r,c,images[fr-image(4,r,c)](p,r,c)); continue;}
                ColorVal guess = predict_and_calcProps_scanlines(properties,ranges,image,p,r,c,min,max);
                if (p==4 && max > fr) max = fr;
                ColorVal curr = coders[p].read_int(properties, min - guess, max - guess) + guess;
                image.set(p,r,c, curr);
              }
              if (fr>0) {
                for (uint32_t c = end; c < image.cols(); c++)
                   if (nump>3 && p<3 && image(3,r,c) == 0) image.set(p,r,c,predict(image,p,r,c));
                   else if (p !=4 ) image.set(p,r,c,images[fr-1](p,r,c));
/*                   else if (nump>4 && p<4 && image(4,r,c) > 0) image.set(p,r,c,images[fr-image(4,r,c)](p,r,c));
                   else {
                     int oldframe=fr-1;  image.set(p,r,c,images[oldframe](p,r,c));
                     while(p == 4 && image(p,r,c) > 0) {oldframe -= image(p,r,c); assert(oldframe>=0); image.set(p,r,c,images[oldframe](p,r,c));}
                   }*/
              }
            }
        }
      int qual = 10000*pixels_done/pixels_todo;
      if (callback && qual >= progressive_qual_target) {
        for (unsigned int n=0; n < images.size(); n++) partial_images[n] = images[n].clone(); // make a copy to work with
        for (int i=transforms.size()-1; i>=0; i--) if (transforms[i]->undo_redo_during_decode()) transforms[i]->invData(partial_images);
        progressive_qual_target = callback(qual,rac.ftell());
        if (qual >= progressive_qual_target) break;
      }
    }
}
Пример #17
0
template<typename IO, typename Rac, typename Coder> void flif_decode_FLIF2_inner(Rac &rac, std::vector<Coder> &coders, Images &images, const ColorRanges *ranges, const int beginZL, const int endZL, int quality, int scale, std::vector<Transform<IO>*> &transforms, uint32_t (*callback)(int,int), Images &partial_images) {
    ColorVal min,max;
    int nump = images[0].numPlanes();
    int progressive_qual_target = 0;
//    if (quality >= 0) {
//      quality = plane_zoomlevels(image, beginZL, endZL) * quality / 100;
//    }
    // flif_decode
    for (int i = 0; i < plane_zoomlevels(images[0], beginZL, endZL); i++) {
      std::pair<int, int> pzl = plane_zoomlevel(images[0], beginZL, endZL, i);
      int p = pzl.first;
      int z = pzl.second;
      if ((100*pixels_done > quality*pixels_todo) ||  1<<(z/2) < scale) {
              flif_decode_FLIF2_inner_interpol(images, ranges, i, beginZL, endZL, (z%2 == 0 ?1:0), scale);
              return;
      }
      if (endZL == 0) v_printf(2,"\r%i%% done [%i/%i] DEC[%i,%ux%u]  ",(int)(100*pixels_done/pixels_todo),i,plane_zoomlevels(images[0], beginZL, endZL)-1,p,images[0].cols(z),images[0].rows(z));
      pixels_done += (images[0].cols(z)/(z%2==0?1:2))*(images[0].rows(z)/(z%2==0?2:1));
      if (ranges->min(p) < ranges->max(p)) {
      ColorVal curr;
      Properties properties((nump>3?NB_PROPERTIESA[p]:NB_PROPERTIES[p]));
      if (z % 2 == 0) {
          for (uint32_t r = 1; r < images[0].rows(z); r += 2) {
#ifdef CHECK_FOR_BROKENFILES
            if (rac.isEOF()) {
              v_printf(1,"Row %i: Unexpected file end. Interpolation from now on.\n",r);
              flif_decode_FLIF2_inner_interpol(images, ranges, i, beginZL, endZL, (r>1?r-2:r), scale);
              return;
            }
#endif
            for (int fr=0; fr<(int)images.size(); fr++) {
              Image& image = images[fr];
              if (image.seen_before >= 0) { for (uint32_t c=0; c<image.cols(z); c++) image.set(p,z,r,c,images[image.seen_before](p,z,r,c)); continue; }
              uint32_t begin=image.col_begin[r*image.zoom_rowpixelsize(z)]/image.zoom_colpixelsize(z), end=1+(image.col_end[r*image.zoom_rowpixelsize(z)]-1)/image.zoom_colpixelsize(z);
              if (fr>0) {
                for (uint32_t c = 0; c < begin; c++)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
                for (uint32_t c = end; c < image.cols(z); c++)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
              } else {
                if (nump>3 && p<3) {begin=0; end=image.cols(z);}
              }
              for (uint32_t c = begin; c < end; c++) {
                     if (nump>3 && p<3 && image(3,z,r,c) == 0) { image.set(p,z,r,c,predict(image,z,p,r,c)); continue;}
                     if (nump>4 && p<4 && image(4,z,r,c) > 0) { image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c)); continue;}
                     ColorVal guess = predict_and_calcProps(properties,ranges,image,z,p,r,c,min,max);
                     if (p==4 && max > fr) max = fr;
                     curr = coders[p].read_int(properties, min - guess, max - guess) + guess;
                     image.set(p,z,r,c, curr);
              }
            }
        }
      } else {
          for (uint32_t r = 0; r < images[0].rows(z); r++) {
#ifdef CHECK_FOR_BROKENFILES
            if (rac.isEOF()) {
              v_printf(1,"Row %i: Unexpected file end. Interpolation from now on.\n", r);
              flif_decode_FLIF2_inner_interpol(images, ranges, i, beginZL, endZL, (r>0?r-1:r), scale);
              return;
            }
#endif
            for (int fr=0; fr<(int)images.size(); fr++) {
              Image& image = images[fr];
              if (image.seen_before >= 0) { for (uint32_t c=1; c<image.cols(z); c+=2) image.set(p,z,r,c,images[image.seen_before](p,z,r,c)); continue; }
              uint32_t begin=(image.col_begin[r*image.zoom_rowpixelsize(z)]/image.zoom_colpixelsize(z)),
              end=(1+(image.col_end[r*image.zoom_rowpixelsize(z)]-1)/image.zoom_colpixelsize(z))|1;
              if (begin>1 && ((begin&1) ==0)) begin--;
              if (begin==0) begin=1;
              if (fr>0) {
                for (uint32_t c = 1; c < begin; c+=2)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
                for (uint32_t c = end; c < image.cols(z); c+=2)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
              } else {
                if (nump>3 && p<3) {begin=1; end=image.cols(z);}
              }
              for (uint32_t c = begin; c < end; c+=2) {
                     if (nump>3 && p<3 && image(3,z,r,c) == 0) { image.set(p,z,r,c,predict(image,z,p,r,c)); continue;}
                     if (nump>4 && p<4 && image(4,z,r,c) > 0) { image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c)); continue;}
                     ColorVal guess = predict_and_calcProps(properties,ranges,image,z,p,r,c,min,max);
                     if (p==4 && max > fr) max = fr;
                     curr = coders[p].read_int(properties, min - guess, max - guess) + guess;
                     image.set(p,z,r,c, curr);
              }
            }
        }
      }
      if (endZL==0) {
          v_printf(3,"    read %li bytes   ", rac.ftell());
          v_printf(5,"\n");
      }
      }
      int qual = 10000*pixels_done/pixels_todo;
      if (callback && (endZL==0 || i+1 == plane_zoomlevels(images[0], beginZL, endZL)) && qual >= progressive_qual_target) {
        for (unsigned int n=0; n < images.size(); n++) partial_images[n] = images[n].clone(); // make a copy to work with
        int64_t pixels_really_done = pixels_done;
        flif_decode_FLIF2_inner_interpol(partial_images, ranges, i+1, beginZL, endZL, -1, scale);
        if (endZL>0) flif_decode_FLIF2_inner_interpol(partial_images, ranges, 0, endZL-1, 0, -1, scale);
        pixels_done = pixels_really_done;
        for (int i=transforms.size()-1; i>=0; i--) if (transforms[i]->undo_redo_during_decode()) transforms[i]->invData(partial_images);
        progressive_qual_target = callback(qual,rac.ftell());
        if (qual >= progressive_qual_target) break;
      }
    }
}
Пример #18
0
int handle_decode(int argc, char **argv, Images &images, flif_options &options) {
    if (options.scale < 0) {
        // just identify the file(s), don't actually decode
        while (argc>0) {
            decode_flif(argv, images, options);
            argv++; argc--;
        }
        return 0;
    }
    if (argc == 1 && options.show_breakpoints) {
        decode_flif(argv, images, options);
        return 0;
    }
    char *ext = strrchr(argv[1],'.');
    if (check_metadata_extension(ext)) {
        // only requesting metadata, no need to actually decode the file
        options.scale = -2;
        decode_flif(argv, images, options);
        if (!images[0].save(argv[1])) return 2;
        v_printf(2,"\n");
        return 0;
    }
    if (!check_compatible_extension(ext) && strcmp(argv[1],"null:") && strcmp(argv[1],"-")) {
        e_printf("Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n");
        return 1;
    }
    if (!(ext && ( !strcasecmp(ext,".png"))))
        options.keep_palette = false;   // don't try to make a palette PNM

    try {
      if (!decode_flif(argv, images, options)) {
        e_printf("Error: could not decode FLIF file\n"); return 3;
      }
    } catch (std::bad_alloc& ba) {
        e_printf("Error: memory allocation problem (unexpected)\n"); return 3;
    }
    if (!strcmp(argv[1],"null:")) return 0;
//    if (scale>1)
//        v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale);
    if (images.size() == 1) {
        if (!images[0].save(argv[1])) return 2;
    } else {
        bool to_stdout=false;
        if (!strcmp(argv[1],"-")) {
            to_stdout=true;
            v_printf(1,"Warning: writing animation to standard output as a concatenation of PAM files.\n");
        }
        int counter=0;
        int maxlength = strlen(argv[1])+100;
        std::vector<char> vfilename(maxlength);
        char *filename = &vfilename[0];
        bool use_custom_format = false;
        if (strchr(argv[1],'%')) use_custom_format = true;
        strcpy(filename,argv[1]);
        char *a_ext = strrchr(filename,'.');
        if (!a_ext && !to_stdout) {
            e_printf("Problem saving animation to %s\n",filename);
            return 2;
        }
        for (Image& image : images) {
            if (!to_stdout) {
              if (use_custom_format) snprintf(filename,maxlength,argv[1],counter);
              else if (images.size() < 1000) sprintf(a_ext,"-%03d%s",counter,ext);
              else if (images.size() < 10000) sprintf(a_ext,"-%04d%s",counter,ext);
              else if (images.size() < 100000) sprintf(a_ext,"-%05d%s",counter,ext);
              else sprintf(a_ext,"-%08d%s",counter,ext);
              if (file_exists(filename) && !options.overwrite) {
                e_printf("Error: output file already exists: %s\nUse --overwrite to force overwrite.\n",filename);
                return 4;
              }
              if (!image.save(filename)) return 2;
            } else {
              if (!image.save(argv[1])) return 2;
            }
            counter++;
            v_printf(2,"    (%i/%i)         \r",counter,(int)images.size()); v_printf(4,"\n");
        }
    }
    // get rid of palette (should also do this in the non-standard/error paths, but being lazy here since the tool will exit anyway)
    images[0].clear();
    v_printf(2,"\n");
    return 0;
}
Пример #19
0
bool encode_flif(int argc, char **argv, Images &images, flif_options &options) {
    bool flat=true;
    unsigned int framenb=0;
    for (Image& i : images) { i.frame_delay = options.frame_delay[framenb]; if (framenb+1 < options.frame_delay.size()) framenb++; }
    for (Image &image : images) if (image.uses_alpha()) flat=false;
    if (flat && images[0].numPlanes() == 4) {
        v_printf(2,"Alpha channel not actually used, dropping it.\n");
        for (Image &image : images) image.drop_alpha();
    }
    bool grayscale=true;
    for (Image &image : images) if (image.uses_color()) grayscale=false;
    if (grayscale && images[0].numPlanes() == 3) {
        v_printf(2,"Chroma not actually used, dropping it.\n");
        for (Image &image : images) image.drop_color();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    if (nb_pixels > 2) {         // no point in doing anything for 1- or 2-pixel images
      if (options.plc && (images[0].getDepth() > 8 || !options.loss)) {
        desc.push_back("Channel_Compact");  // compactify channels (not if lossy, because then loss gets magnified!)
      }
      if (options.ycocg) {
        desc.push_back("YCoCg");  // convert RGB(A) to YCoCg(A)
      }
      desc.push_back("PermutePlanes");  // permute RGB to GRB
      desc.push_back("Bounds");  // get the bounds of the color spaces
    }
    // only use palette/CB if we're lossless, because lossy and palette don't go well together...
    if (options.palette_size == -1) {
        options.palette_size = DEFAULT_MAX_PALETTE_SIZE;
        if (nb_pixels * images.size() / 3 < DEFAULT_MAX_PALETTE_SIZE) {
          options.palette_size = nb_pixels * images.size() / 3;
        }
    }
    if (!options.loss && options.palette_size != 0) {
        desc.push_back("Palette_Alpha");  // try palette (including alpha)
        desc.push_back("Palette");  // try palette (without alpha)
    }
    if (!options.loss) {
    if (options.acb == -1) {
      // not specified if ACB should be used
      if (nb_pixels * images.size() > 10000) {
        desc.push_back("Color_Buckets");  // try auto color buckets on large images
      }
    } else if (options.acb) {
      desc.push_back("Color_Buckets");  // try auto color buckets if forced
    }
    }
    if (options.method.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels * images.size() < 10000) options.method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else options.method.encoding=flifEncoding::interlaced; // default method: interlacing
    }
    if (images.size() > 1) {
        desc.push_back("Duplicate_Frame");  // find duplicate frames
        if (!options.loss) { // only if lossless
          if (options.frs) desc.push_back("Frame_Shape");  // get the shapes of the frames
          if (options.lookback) desc.push_back("Frame_Lookback");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
        }
    }
    if (options.learn_repeats < 0) {
        // no number of repeats specified, pick a number heuristically
        options.learn_repeats = TREE_LEARN_REPEATS;
        //if (nb_pixels * images.size() < 5000) learn_repeats--;        // avoid large trees for small images
        if (options.learn_repeats < 0) options.learn_repeats=0;
    }
    bool result = true;
    if (!options.just_add_loss) {
      FILE *file = NULL;
      if (!strcmp(argv[0],"-")) file = stdout;
      else file = fopen(argv[0],"wb");
      if (!file) return false;
      FileIO fio(file, (file == stdout? "to standard output" : argv[0]));
      if (!flif_encode(fio, images, desc, options)) result = false;
    } else {
      BlobIO bio; // will just contain some unneeded FLIF header stuff
      if (!flif_encode(bio, images, desc, options)) result = false;
      else if (!images[0].save(argv[0])) result = false;
    }
    // get rid of palette
    images[0].clear();
    return result;
}
Пример #20
0
bool encode_load_input_images(int argc, char **argv, Images &images, flif_options &options) {
    int nb_input_images = argc-1;
    int nb_actual_images = 0;
    metadata_options md;
    md.icc = options.color_profile;
    md.xmp = options.metadata;
    md.exif = options.metadata;
    while(argc>1) {
      int maxlength = strlen(argv[0])+100;
      std::vector<char> vfilename(maxlength);
      char *filename = argv[0];
      int framecounter = 0;
      int stop_searching = 0;
      bool multiple=false;
      if (!file_exists(argv[0]) && strchr(argv[0],'%')) {
        multiple=true;
        filename = &vfilename[0];
      }
      for ( ; framecounter < 0xFFFFFFF && stop_searching < 1000; framecounter++ ) {
        if (multiple) {
             snprintf(filename,maxlength,argv[0],framecounter);
             if (!file_exists(filename)) {
                stop_searching++;
                continue;
             }
             stop_searching = 0;
        }
        Image image;
        if (options.keep_palette) image.palette = true; // tells the PNG loader to keep palette intact
        v_printf_tty(2,"\r");
        if (!image.load(filename,md)) {
            e_printf("Could not read input file: %s\n", argv[0]);
            return false;
        };
        if (image.numPlanes() > 0) {
          nb_actual_images++;
          images.push_back(std::move(image));
          Image& last_image = images.back();
          if (last_image.rows() != images[0].rows() || last_image.cols() != images[0].cols()) {
            e_printf("Dimensions of all input images should be the same!\n");
            e_printf("  First image is %ux%u\n",images[0].cols(),images[0].rows());
            e_printf("  This image is %ux%u: %s\n",last_image.cols(),last_image.rows(),filename);
            return false;
          }
          if (last_image.numPlanes() < images[0].numPlanes()) {
            if (images[0].numPlanes() == 3) last_image.ensure_chroma();
            else if (images[0].numPlanes() == 4) last_image.ensure_alpha();
            else { e_printf("Problem while loading input images, please report this.\n"); return false; }
          } else if (last_image.numPlanes() > images[0].numPlanes()) {
            if (last_image.numPlanes() == 3) { for (Image& i : images) i.ensure_chroma(); }
            else if (last_image.numPlanes() == 4) { for (Image& i : images) i.ensure_alpha(); }
            else { e_printf("Problem while loading input images, please report this.\n"); return false; }
          }
        } else {
          if (images.size() == 0) {
            e_printf("First specify the actual image(s), then the metadata.\n");
            return false;
          }
          for (size_t i=0; i<image.metadata.size(); i++)
              images[0].metadata.push_back(image.metadata[i]);
        }
        if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
        if (!multiple) break;
      }
      argc--; argv++;
    }
    if (nb_actual_images > 0) return true;
    e_printf("Error: no actual input images to be encoded!\n");
    return false;
}
Пример #21
0
template<typename Rac, typename Coder> void flif_decode_FLIF2_inner(Rac &rac, std::vector<Coder> &coders, Images &images, const ColorRanges *ranges, const int beginZL, const int endZL, int quality, int scale)
{
    ColorVal min,max;
    int nump = images[0].numPlanes();
//    if (quality >= 0) {
//      quality = plane_zoomlevels(image, beginZL, endZL) * quality / 100;
//    }
    // flif_decode
    for (int i = 0; i < plane_zoomlevels(images[0], beginZL, endZL); i++) {
      std::pair<int, int> pzl = plane_zoomlevel(images[0], beginZL, endZL, i);
      int p = pzl.first;
      int z = pzl.second;
      if ((100*pixels_done > quality*pixels_todo) ||  1<<(z/2) < scale) {
              flif_decode_FLIF2_inner_interpol(images, ranges, i, beginZL, endZL, (z%2 == 0 ?1:0), scale);
              return;
      }
      if (endZL == 0) v_printf(2,"\r%i%% done [%i/%i] DEC[%i,%ux%u]  ",(int)(100*pixels_done/pixels_todo),i,plane_zoomlevels(images[0], beginZL, endZL)-1,p,images[0].cols(z),images[0].rows(z));
      pixels_done += images[0].cols(z)*images[0].rows(z)/2;
      if (ranges->min(p) >= ranges->max(p)) continue;
      ColorVal curr;
      Properties properties((nump>3?NB_PROPERTIESA[p]:NB_PROPERTIES[p]));
      if (z % 2 == 0) {
          for (uint32_t r = 1; r < images[0].rows(z); r += 2) {
#ifdef CHECK_FOR_BROKENFILES
            if (rac.isEOF()) {
              v_printf(1,"Row %i: Unexpected file end. Interpolation from now on.\n",r);
              flif_decode_FLIF2_inner_interpol(images, ranges, i, beginZL, endZL, (r>1?r-2:r), scale);
              return;
            }
#endif
            for (int fr=0; fr<(int)images.size(); fr++) {
              Image& image = images[fr];
              if (image.seen_before >= 0) { for (uint32_t c=0; c<image.cols(z); c++) image.set(p,z,r,c,images[image.seen_before](p,z,r,c)); continue; }
              uint32_t begin=image.col_begin[r*image.zoom_rowpixelsize(z)]/image.zoom_colpixelsize(z), end=1+(image.col_end[r*image.zoom_rowpixelsize(z)]-1)/image.zoom_colpixelsize(z);
              if (fr>0) {
                for (uint32_t c = 0; c < begin; c++)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
                for (uint32_t c = end; c < image.cols(z); c++)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
              } else {
                if (nump>3 && p<3) {begin=0; end=image.cols(z);}
              }
              for (uint32_t c = begin; c < end; c++) {
                     if (nump>3 && p<3 && image(3,z,r,c) == 0) { image.set(p,z,r,c,predict(image,z,p,r,c)); continue;}
                     if (nump>4 && p<4 && image(4,z,r,c) > 0) { image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c)); continue;}
                     ColorVal guess = predict_and_calcProps(properties,ranges,image,z,p,r,c,min,max);
                     if (p==4 && max > fr) max = fr;
                     curr = coders[p].read_int(properties, min - guess, max - guess) + guess;
                     image.set(p,z,r,c, curr);
              }
            }
        }
      } else {
          for (uint32_t r = 0; r < images[0].rows(z); r++) {
#ifdef CHECK_FOR_BROKENFILES
            if (rac.isEOF()) {
              v_printf(1,"Row %i: Unexpected file end. Interpolation from now on.\n", r);
              flif_decode_FLIF2_inner_interpol(images, ranges, i, beginZL, endZL, (r>0?r-1:r), scale);
              return;
            }
#endif
            for (int fr=0; fr<(int)images.size(); fr++) {
              Image& image = images[fr];
              if (image.seen_before >= 0) { for (uint32_t c=1; c<image.cols(z); c+=2) image.set(p,z,r,c,images[image.seen_before](p,z,r,c)); continue; }
              uint32_t begin=(image.col_begin[r*image.zoom_rowpixelsize(z)]/image.zoom_colpixelsize(z)),
              end=(1+(image.col_end[r*image.zoom_rowpixelsize(z)]-1)/image.zoom_colpixelsize(z))|1;
              if (begin>1 && ((begin&1) ==0)) begin--;
              if (begin==0) begin=1;
              if (fr>0) {
                for (uint32_t c = 1; c < begin; c+=2)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
                for (uint32_t c = end; c < image.cols(z); c+=2)
                            if (nump>3 && p<3 && image(3,z,r,c) == 0) image.set(p,z,r,c, predict(image,z,p,r,c));
                            else if (p !=4 ) image.set(p,z,r,c,images[fr-1](p,z,r,c));
/*                            else if (nump>4 && p<4 && image(4,z,r,c) > 0) image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c));
                            else { int oldframe=fr-1;  image.set(p,z,r,c,images[oldframe](p,z,r,c));
                                   while(p == 4 && image(p,z,r,c) > 0) {oldframe -= image(p,z,r,c); assert(oldframe>=0); image.set(p,z,r,c,images[oldframe](p,z,r,c));}}
*/
              } else {
                if (nump>3 && p<3) {begin=1; end=image.cols(z);}
              }
              for (uint32_t c = begin; c < end; c+=2) {
                     if (nump>3 && p<3 && image(3,z,r,c) == 0) { image.set(p,z,r,c,predict(image,z,p,r,c)); continue;}
                     if (nump>4 && p<4 && image(4,z,r,c) > 0) { image.set(p,z,r,c,images[fr-image(4,z,r,c)](p,z,r,c)); continue;}
                     ColorVal guess = predict_and_calcProps(properties,ranges,image,z,p,r,c,min,max);
                     if (p==4 && max > fr) max = fr;
                     curr = coders[p].read_int(properties, min - guess, max - guess) + guess;
                     image.set(p,z,r,c, curr);
              }
            }
        }
      }
      if (endZL==0) {
          v_printf(3,"    read %li bytes   ", rac.ftell());
          v_printf(5,"\n");
      }
    }
}
Пример #22
0
bool encode_flif(int argc, char **argv, Images &images, int palette_size, int acb, flifEncodingOptional method, int lookback,
                 int learn_repeats, std::vector<int> &frame_delay, int divisor=CONTEXT_TREE_COUNT_DIV, int min_size=CONTEXT_TREE_MIN_SUBTREE_SIZE,
                 int split_threshold=CONTEXT_TREE_SPLIT_THRESHOLD, int yiq=1, int plc=1, int frs=1, int cutoff=2, int alpha=19, int crc_check=-1, int loss=0) {
    bool flat=true;
    unsigned int framenb=0;
    for (Image& i : images) { i.frame_delay = frame_delay[framenb]; if (framenb+1 < frame_delay.size()) framenb++; }
    for (Image &image : images) if (image.uses_alpha()) flat=false;
    if (flat && images[0].numPlanes() == 4) {
        v_printf(2,"Alpha channel not actually used, dropping it.\n");
        for (Image &image : images) image.drop_alpha();
    }
    bool grayscale=true;
    for (Image &image : images) if (image.uses_color()) grayscale=false;
    if (grayscale && images[0].numPlanes() == 3) {
        v_printf(2,"Chroma not actually used, dropping it.\n");
        for (Image &image : images) image.drop_color();
    }
    uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
    std::vector<std::string> desc;
    if (nb_pixels > 2) {         // no point in doing anything for 1- or 2-pixel images
      if (plc && !loss) {
        desc.push_back("Channel_Compact");  // compactify channels (not if lossy, because then loss gets magnified!)
      }
      if (yiq) {
        desc.push_back("YCoCg");  // convert RGB(A) to YCoCg(A)
      }
      desc.push_back("Bounds");  // get the bounds of the color spaces
    }
    if (!loss) {
    // only use palette/CB if we're lossless, because lossy and palette don't go well together...
    if (palette_size == -1) {
        palette_size = 1024;
        if (nb_pixels * images.size() / 2 < 1024) {
          palette_size = nb_pixels * images.size() / 2;
        }
    }
    if (palette_size != 0) {
        desc.push_back("Palette_Alpha");  // try palette (including alpha)
    }
    if (palette_size != 0) {
        desc.push_back("Palette");  // try palette (without alpha)
    }
    if (acb == -1) {
      // not specified if ACB should be used
      if (nb_pixels * images.size() > 10000) {
        desc.push_back("Color_Buckets");  // try auto color buckets on large images
      }
    } else if (acb) {
      desc.push_back("Color_Buckets");  // try auto color buckets if forced
    }
    }
    if (method.o == Optional::undefined) {
        // no method specified, pick one heuristically
        if (nb_pixels * images.size() < 10000) method.encoding=flifEncoding::nonInterlaced; // if the image is small, not much point in doing interlacing
        else method.encoding=flifEncoding::interlaced; // default method: interlacing
    }
    if (images.size() > 1) {
        desc.push_back("Duplicate_Frame");  // find duplicate frames
        if (!loss) { // only if lossless
          if (frs) desc.push_back("Frame_Shape");  // get the shapes of the frames
          if (lookback) desc.push_back("Frame_Lookback");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
        }
    }
    if (learn_repeats < 0) {
        // no number of repeats specified, pick a number heuristically
        learn_repeats = TREE_LEARN_REPEATS;
        if (nb_pixels * images.size() < 5000) learn_repeats--;        // avoid large trees for small images
        if (learn_repeats < 0) learn_repeats=0;
    }
    FILE *file = fopen(argv[0],"wb");
    if (!file)
        return false;
    FileIO fio(file, argv[0]);
    return flif_encode(fio, images, desc, method.encoding, learn_repeats, acb, palette_size, lookback, divisor, min_size, split_threshold, cutoff, alpha, crc_check, loss);
}
Пример #23
0
void Pipeline::run(const bool save_clouds, const bool show_clouds)
{
	Logger _log("Pipeline");

	/**
	 * Stage 0: Load images from file
	 */
	Images images;
	load_images(folder_path, images);


	/**
	 * Stage 1: Detect features in loaded images
	 */
	CamFrames cam_Frames;
	DescriptorsVec descriptors_vec;
	extract_features(images, cam_Frames, descriptors_vec);

	// Free Image.gray
	for (int i = 0; i < images.size(); i++)
		const_cast<cv::Mat&>(images[i].gray).release();


	/**
	 * Stage 2: Calculate descriptors and find image pairs through matching
	 */
	ImagePairs image_pairs;
	find_matching_pairs(images, cam_Frames, descriptors_vec, image_pairs);


	// Free some memory
	DescriptorsVec().swap(descriptors_vec);



	/**
	 * State 3: Compute pairwise R and t
	 */
	register_camera(image_pairs, cam_Frames);


	/**
	 * Stage 4: Construct associativity matrix and spanning tree
	 */
	Associativity assocMat(cam_Frames.size());
	for (int p = 0; p < image_pairs.size(); p++)
	{
		ImagePair* pair = &image_pairs[p];
		int i = pair->pair_index.first,
		    j = pair->pair_index.second;

		if (pair -> R.empty()) continue;

		assocMat(i, j) = pair;
		assocMat(j, i) = pair;

		assert(assocMat(i, j) == assocMat(j, i));
		assert(assocMat(i, j)->pair_index.first  == i &&
		       assocMat(i, j)->pair_index.second == j);
	}

	Associativity tree;
	const int camera_num = build_spanning_tree(image_pairs, assocMat, tree);


	/**
	 * Stage 5: Compute global Rs and ts
	 */
	CameraPoses gCameraPoses;
	glo_cam_poses(images, gCameraPoses, image_pairs, tree);


	/**
	 * Stage 6: Find and cluster depth points from local camera frame to global camera frame
	 */
	PointClusters pointClusters;
	PointMap pointMap;
	find_clusters(assocMat, gCameraPoses, cam_Frames, pointClusters, pointMap);

	// Free some memory
	ImagePairs().swap(image_pairs);


	/**
	 * Stage 7: get center of mass from clusters
	 */
	PointCloud pointCloud(pointClusters.size());
	find_CoM(pointClusters, pointCloud);

	// Free pointClusters
	for (int i = 0; i < pointClusters.size(); i++)
		PointCluster().swap(pointClusters[i]);
	PointClusters().swap(pointClusters);


	// Save cloud before BA
	Viewer viewer("Before BA");
	auto cloud  = viewer.createPointCloud(images, gCameraPoses, cameraMatrix);
	int  n      = cloud->points.size();
	auto time   = ptime::second_clock::local_time();
	auto tstamp = ptime::to_iso_string(time);
	auto folder = fs::path(folder_path).filename().string();
	auto fname  = (fmt("%s_%s_%d_noBA.pcd") % folder % tstamp % n).str();

	if (save_clouds)
		viewer.saveCloud(cloud, fname);
	if (show_clouds)
		viewer.showCloudPoints(cloud, false);


	/**
	 * State 8: Bundle Adjustment
	 */
	bundle_adjustment(pointMap, cam_Frames, false, gCameraPoses, pointCloud);
	_log.tok();

	/**
	 * Show calculated point cloud
	 */
	Viewer viewer_ba("After BA no Depth");
	cloud = viewer_ba.createPointCloud(images, gCameraPoses, cameraMatrix);
	n     = cloud->points.size();
	fname = (fmt("%s_%s_%d_BA_noD.pcd") % folder % tstamp % n).str();


	if (save_clouds)
		viewer_ba.saveCloud(cloud, fname);
	if (show_clouds)
		viewer_ba.showCloudPoints(cloud,false);

	bundle_adjustment(pointMap, cam_Frames, true, gCameraPoses, pointCloud);

	// Free some memory
	PointMap().swap(pointMap);
	CamFrames().swap(cam_Frames);
	PointCloud().swap(pointCloud);

	/**
	 * Show calculated point cloud
	 */
	Viewer viewer_baD("After BA with Depth");
	cloud = viewer_baD.createPointCloud(images, gCameraPoses, cameraMatrix);
	n     = cloud->points.size();
	fname = (fmt("%s_%s_%d_BA_D.pcd") % folder % tstamp % n).str();

	// Free some memory
	Images().swap(images);
	CameraPoses().swap(gCameraPoses);

	if (save_clouds)
		viewer_baD.saveCloud(cloud, fname);
	if (show_clouds)
		viewer_baD.showCloudPoints(cloud);



}
Пример #24
0
int main(int argc, char **argv)
{
    Images images;
    int mode = 0; // 0 = encode, 1 = decode
    int method = 0; // 1=non-interlacing, 2=interlacing
    int quality = 100; // 100 = everything, positive value: partial decode, negative value: only rough data
    int learn_repeats = -1;
    int acb = -1; // try auto color buckets
    int scale = 1;
    int frame_delay = 100;
    int palette_size = 512;
    int lookback = 1;
    if (strcmp(argv[0],"flif") == 0) mode = 0;
    if (strcmp(argv[0],"dflif") == 0) mode = 1;
    if (strcmp(argv[0],"deflif") == 0) mode = 1;
    if (strcmp(argv[0],"decflif") == 0) mode = 1;
    static struct option optlist[] = {
        {"help", 0, NULL, 'h'},
        {"encode", 0, NULL, 'e'},
        {"decode", 0, NULL, 'd'},
        {"first", 1, NULL, 'f'},
        {"verbose", 0, NULL, 'v'},
        {"interlace", 0, NULL, 'i'},
        {"no-interlace", 0, NULL, 'n'},
        {"acb", 0, NULL, 'a'},
        {"no-acb", 0, NULL, 'b'},
        {"quality", 1, NULL, 'q'},
        {"scale", 1, NULL, 's'},
        {"palette", 1, NULL, 'p'},
        {"repeats", 1, NULL, 'r'},
        {"frame-delay", 1, NULL, 'f'},
        {"lookback", 1, NULL, 'l'},
        {0, 0, 0, 0}
    };
    int i,c;
    while ((c = getopt_long (argc, argv, "hedvinabq:s:p:r:f:l:", optlist, &i)) != -1) {
        switch (c) {
        case 'e': mode=0; break;
        case 'd': mode=1; break;
        case 'v': verbosity++; break;
        case 'i': if (method==0) method=2; break;
        case 'n': method=1; break;
        case 'a': acb=1; break;
        case 'b': acb=0; break;
        case 'p': palette_size=atoi(optarg);
                  if (palette_size < -1 || palette_size > 30000) {fprintf(stderr,"Not a sensible number for option -p\n"); return 1; }
                  if (palette_size == 0) {v_printf(2,"Palette disabled\n"); }
                  break;
        case 'q': quality=atoi(optarg);
                  if (quality < -1 || quality > 100) {fprintf(stderr,"Not a sensible number for option -q\n"); return 1; }
                  break;
        case 's': scale=atoi(optarg);
                  if (scale < 1 || scale > 128) {fprintf(stderr,"Not a sensible number for option -s\n"); return 1; }
                  break;
        case 'r': learn_repeats=atoi(optarg);
                  if (learn_repeats < 0 || learn_repeats > 1000) {fprintf(stderr,"Not a sensible number for option -r\n"); return 1; }
                  break;
        case 'f': frame_delay=atoi(optarg);
                  if (frame_delay < 0 || frame_delay > 60000) {fprintf(stderr,"Not a sensible number for option -f\n"); return 1; }
                  break;
        case 'l': lookback=atoi(optarg);
                  if (lookback < -1 || lookback > 256) {fprintf(stderr,"Not a sensible number for option -l\n"); return 1; }
                  break;
        case 'h':
        default: show_help(); return 0;
        }
    }
    argc -= optind;
    argv += optind;

  v_printf(3,"  _____  __  (__) _____");
  v_printf(3,"\n (___  ||  | |  ||  ___)   ");v_printf(2,"FLIF 0.1 [2 October 2015]");
  v_printf(3,"\n  (__  ||  |_|__||  __)    Free Lossless Image Format");
  v_printf(3,"\n    (__||______) |__)      (c) 2010-2015 J.Sneyers & P.Wuille, GNU GPL v3+\n");
  v_printf(3,"\n");
  if (argc == 0) {
        //fprintf(stderr,"Input file missing.\n");
        if (verbosity == 1) show_help();
        return 1;
  }
  if (argc == 1) {
        fprintf(stderr,"Output file missing.\n");
        show_help();
        return 1;
  }

    if (file_exists(argv[0])) {
            if (mode == 0 && file_is_flif(argv[0])) {
              v_printf(2,"Input file is a FLIF file, adding implicit -d\n");
              mode = 1;
            }
            char *f = strrchr(argv[0],'/');
            char *ext = f ? strrchr(f,'.') : strrchr(argv[0],'.');
            if (mode == 0) {
                    if (ext && ( !strcasecmp(ext,".png") ||  !strcasecmp(ext,".pnm") ||  !strcasecmp(ext,".ppm")  ||  !strcasecmp(ext,".pgm") ||  !strcasecmp(ext,".pbm") ||  !strcasecmp(ext,".pam"))) {
                          // ok
                    } else {
                          fprintf(stderr,"Warning: expected \".png\" or \".pnm\" file name extension for input file, trying anyway...\n");
                    }
            } else {
                    if (ext && ( !strcasecmp(ext,".flif")  || ( !strcasecmp(ext,".flf") ))) {
                          // ok
                    } else {
                          fprintf(stderr,"Warning: expected file name extension \".flif\" for input file, trying anyway...\n");
                    }
            }
    } else if (argc>0) {
          fprintf(stderr,"Input file does not exist: %s\n",argv[0]);
          return 1;
    }


  if (mode == 0) {
        int nb_input_images = argc-1;
        while(argc>1) {
          Image image;
          v_printf(2,"\r");
          if (!image.load(argv[0])) {
            fprintf(stderr,"Could not read input file: %s\n", argv[0]);
            return 2;
          };
          images.push_back(image);
          if (image.rows() != images[0].rows() || image.cols() != images[0].cols() || image.numPlanes() != images[0].numPlanes()) {
            fprintf(stderr,"Dimensions of all input images should be the same!\n");
            fprintf(stderr,"  First image is %ux%u, %i channels.\n",images[0].cols(),images[0].rows(),images[0].numPlanes());
            fprintf(stderr,"  This image is %ux%u, %i channels: %s\n",image.cols(),image.rows(),image.numPlanes(),argv[0]);
            return 2;
          }
          argc--; argv++;
          if (nb_input_images>1) {v_printf(2,"    (%i/%i)         ",(int)images.size(),nb_input_images); v_printf(4,"\n");}
        }
        v_printf(2,"\n");
        bool flat=true;
        for (Image &image : images) if (image.uses_alpha()) flat=false;
        if (flat && images[0].numPlanes() == 4) {
              v_printf(2,"Alpha channel not actually used, dropping it.\n");
              for (Image &image : images) image.drop_alpha();
        }
        uint64_t nb_pixels = (uint64_t)images[0].rows() * images[0].cols();
        std::vector<std::string> desc;
        desc.push_back("YIQ");  // convert RGB(A) to YIQ(A)
        desc.push_back("BND");  // get the bounds of the color spaces
        if (palette_size > 0)
          desc.push_back("PLA");  // try palette (including alpha)
        if (palette_size > 0)
          desc.push_back("PLT");  // try palette (without alpha)
        if (acb == -1) {
          // not specified if ACB should be used
          if (nb_pixels > 10000) desc.push_back("ACB");  // try auto color buckets on large images
        } else if (acb) desc.push_back("ACB");  // try auto color buckets if forced
        if (method == 0) {
          // no method specified, pick one heuristically
          if (nb_pixels < 10000) method=1; // if the image is small, not much point in doing interlacing
          else method=2; // default method: interlacing
        }
        if (images.size() > 1) {
          desc.push_back("DUP");  // find duplicate frames
          desc.push_back("FRS");  // get the shapes of the frames
          if (lookback != 0) desc.push_back("FRA");  // make a "deep" alpha channel (negative values are transparent to some previous frame)
        }
        if (learn_repeats < 0) {
          // no number of repeats specified, pick a number heuristically
          learn_repeats = TREE_LEARN_REPEATS;
          if (nb_pixels < 5000) learn_repeats--;        // avoid large trees for small images
          if (learn_repeats < 0) learn_repeats=0;
        }
        encode(argv[0], images, desc, method, learn_repeats, acb, frame_delay, palette_size, lookback);
  } else {
        char *ext = strrchr(argv[1],'.');
        if (ext && ( !strcasecmp(ext,".png") ||  !strcasecmp(ext,".pnm") ||  !strcasecmp(ext,".ppm")  ||  !strcasecmp(ext,".pgm") ||  !strcasecmp(ext,".pbm") ||  !strcasecmp(ext,".pam"))) {
                 // ok
        } else {
           fprintf(stderr,"Error: expected \".png\", \".pnm\" or \".pam\" file name extension for output file\n");
           return 1;
        }
        if (!decode(argv[0], images, quality, scale)) return 3;
        if (scale>1)
          v_printf(3,"Downscaling output: %ux%u -> %ux%u\n",images[0].cols(),images[0].rows(),images[0].cols()/scale,images[0].rows()/scale);
        if (images.size() == 1) {
          if (!images[0].save(argv[1],scale)) return 2;
        } else {
          int counter=0;
          std::vector<char> vfilename(strlen(argv[1])+6);
          char *filename = &vfilename[0];
          strcpy(filename,argv[1]);
          char *a_ext = strrchr(filename,'.');
          for (Image& image : images) {
             sprintf(a_ext,"-%03d%s",counter++,ext);
             if (!image.save(filename,scale)) return 2;
             v_printf(2,"    (%i/%i)         \r",counter,(int)images.size()); v_printf(4,"\n");
          }
        }
        v_printf(2,"\n");
  }
  for (Image &image : images) image.clear();
  return 0;
}
Пример #25
0
void Pipeline::extract_features(const Images& images,CamFrames& cam_Frames,DescriptorsVec& descriptors_vec)
{
	Logger _log("Step 1 (features)");

	const int n     = images.size();
	cam_Frames      = CamFrames(n);
	descriptors_vec = DescriptorsVec(n);

	// Create a SIFT detector
	// Bernhard-checked
	const int    feature_num      = 0;    // Default: 0
	const int    octavelayers_num = 4;    // Default: 3
	const double constrast_thresh = .04f; // Default: 0.04 (larger: less feats)
	const double edge_threshold   = 4.0f; // Default: 10   (larger: more feats)
	const double sigma            = 1.6f; // Default: 1.6
	Ptr<Feature2D> sift_detector = SIFT::create(feature_num,
		octavelayers_num, constrast_thresh, edge_threshold, sigma);

	// create brist detector
	// parameters for brisk : int thresh = 30, int octaves = 3, float patternScale = 1.0f
	// const int thresh  = 70;
	// const int octaves = 2;
	// Ptr<Feature2D> brisk_detector = BRISK::create(thresh, octaves);

	// detect features in a loop
#pragma omp parallel for
	for (int i = 0; i < n; ++i)
	{
		Image image = images[i];

		KeyPoints key_points;
		Descriptors descriptors;

		// Detect keypoints and calculate descriptor vectors
		sift_detector->detectAndCompute(image.gray, noArray(), key_points, descriptors);

		KeyPoints   keep_key_points;
		Descriptors keep_descriptors;
		Depths      keep_depths;

		// Keep keypoints with valid depth only
		// Valid depth is [0.4, 8]m
		for (size_t k = 0; k < key_points.size(); k++)
		{
			float d = image.dep.at<float>(key_points[k].pt);
			if (d < 400.f || d > 8000) continue;

			keep_key_points.push_back(key_points[k]);
			keep_descriptors.push_back(descriptors.row(k));
			keep_depths.push_back(d);
		}

		// wrap keypoints to cam_Frame and add in to cam_Frames
		cam_Frames[i]      = (CamFrame) {i, keep_key_points,keep_depths};
		descriptors_vec[i] = keep_descriptors;

		_log("Found %d key points in image %d.", keep_key_points.size(), i);
	}

	_log.tok();
}