Wed, 05 Aug 2009 17:10:56 +0100
add README
philpem@5 | 1 | /* |
philpem@5 | 2 | # |
philpem@5 | 3 | # File : image2ascii.cpp |
philpem@5 | 4 | # ( C++ source file ) |
philpem@5 | 5 | # |
philpem@5 | 6 | # Description : A basic image to ASCII-art converter. |
philpem@5 | 7 | # This file is a part of the CImg Library project. |
philpem@5 | 8 | # ( http://cimg.sourceforge.net ) |
philpem@5 | 9 | # |
philpem@5 | 10 | # Copyright : David Tschumperle |
philpem@5 | 11 | # ( http://www.greyc.ensicaen.fr/~dtschump/ ) |
philpem@5 | 12 | # |
philpem@5 | 13 | # License : CeCILL v2.0 |
philpem@5 | 14 | # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html ) |
philpem@5 | 15 | # |
philpem@5 | 16 | # This software is governed by the CeCILL license under French law and |
philpem@5 | 17 | # abiding by the rules of distribution of free software. You can use, |
philpem@5 | 18 | # modify and/ or redistribute the software under the terms of the CeCILL |
philpem@5 | 19 | # license as circulated by CEA, CNRS and INRIA at the following URL |
philpem@5 | 20 | # "http://www.cecill.info". |
philpem@5 | 21 | # |
philpem@5 | 22 | # As a counterpart to the access to the source code and rights to copy, |
philpem@5 | 23 | # modify and redistribute granted by the license, users are provided only |
philpem@5 | 24 | # with a limited warranty and the software's author, the holder of the |
philpem@5 | 25 | # economic rights, and the successive licensors have only limited |
philpem@5 | 26 | # liability. |
philpem@5 | 27 | # |
philpem@5 | 28 | # In this respect, the user's attention is drawn to the risks associated |
philpem@5 | 29 | # with loading, using, modifying and/or developing or reproducing the |
philpem@5 | 30 | # software by the user in light of its specific status of free software, |
philpem@5 | 31 | # that may mean that it is complicated to manipulate, and that also |
philpem@5 | 32 | # therefore means that it is reserved for developers and experienced |
philpem@5 | 33 | # professionals having in-depth computer knowledge. Users are therefore |
philpem@5 | 34 | # encouraged to load and test the software's suitability as regards their |
philpem@5 | 35 | # requirements in conditions enabling the security of their systems and/or |
philpem@5 | 36 | # data to be ensured and, more generally, to use and operate it in the |
philpem@5 | 37 | # same conditions as regards security. |
philpem@5 | 38 | # |
philpem@5 | 39 | # The fact that you are presently reading this means that you have had |
philpem@5 | 40 | # knowledge of the CeCILL license and that you accept its terms. |
philpem@5 | 41 | # |
philpem@5 | 42 | */ |
philpem@5 | 43 | |
philpem@5 | 44 | // Tell CImg not to use display capabilities. |
philpem@5 | 45 | #undef cimg_display |
philpem@5 | 46 | #define cimg_display 0 |
philpem@5 | 47 | #include "CImg.h" |
philpem@5 | 48 | using namespace cimg_library; |
philpem@5 | 49 | |
philpem@5 | 50 | // The lines below are necessary when using a non-standard compiler as visualcpp6. |
philpem@5 | 51 | #ifdef cimg_use_visualcpp6 |
philpem@5 | 52 | #define std |
philpem@5 | 53 | #endif |
philpem@5 | 54 | #ifdef min |
philpem@5 | 55 | #undef min |
philpem@5 | 56 | #undef max |
philpem@5 | 57 | #endif |
philpem@5 | 58 | |
philpem@5 | 59 | /*--------------------------- |
philpem@5 | 60 | |
philpem@5 | 61 | Main procedure |
philpem@5 | 62 | |
philpem@5 | 63 | --------------------------*/ |
philpem@5 | 64 | int main(int argc,char **argv) { |
philpem@5 | 65 | cimg_usage("A simple image to ASCII-art converter.\n\nUsage : image2ascii [options] image"); |
philpem@5 | 66 | |
philpem@5 | 67 | // Read command line parameters |
philpem@5 | 68 | const char *geom = cimg_option("-g","79x40","Output size"); |
philpem@5 | 69 | const int alphabet = cimg_option("-a",0,"Alphabet type (0=full, 1=numbers, 2=letters, 3=signs, 4=minimal"); |
philpem@5 | 70 | const bool invert = cimg_option("-invert",false,"Invert image intensities"); |
philpem@5 | 71 | const float contour = (float)cimg_option("-contour",0.0f,"Use image contours higher than specified threshold"); |
philpem@5 | 72 | const float blur = (float)cimg_option("-blur",0.8f,"Image pre-blur"); |
philpem@5 | 73 | const float sigma = (float)cimg_option("-sigma",1.5f,"Font pre-blur"); |
philpem@5 | 74 | const char *file_i = cimg_argument1(0,"-invert"); |
philpem@5 | 75 | int w = 79, h = 40; |
philpem@5 | 76 | std::sscanf(geom,"%d%*c%d",&w,&h); |
philpem@5 | 77 | if (cimg_option("-h",false,0)) std::exit(0); |
philpem@5 | 78 | |
philpem@5 | 79 | // Init fonts |
philpem@5 | 80 | const CImgList<> font_full = CImgList<>::font(11,false); |
philpem@5 | 81 | const int fw = font_full['A'].dimx(), fh = font_full['A'].dimy(); |
philpem@5 | 82 | CImgList<> font, font_blur; |
philpem@5 | 83 | CImgList<unsigned char> font_code; |
philpem@5 | 84 | |
philpem@5 | 85 | switch (alphabet) { |
philpem@5 | 86 | case 1: { |
philpem@5 | 87 | font_code.insert(CImg<>::vector(' ')); |
philpem@5 | 88 | for (unsigned char l='0'; l<='9'; l++) font_code.insert(CImg<>::vector(l)); |
philpem@5 | 89 | } break; |
philpem@5 | 90 | case 2: { |
philpem@5 | 91 | font_code.insert(CImg<>::vector(' ')); |
philpem@5 | 92 | for (unsigned char l='A'; l<='Z'; l++) font_code.insert(CImg<>::vector(l)); |
philpem@5 | 93 | } break; |
philpem@5 | 94 | case 3: { |
philpem@5 | 95 | font_code.insert(CImg<>::vector(' ')); |
philpem@5 | 96 | font_code.insert(CImg<>::vector('-')); |
philpem@5 | 97 | font_code.insert(CImg<>::vector('_')); |
philpem@5 | 98 | font_code.insert(CImg<>::vector('|')); |
philpem@5 | 99 | font_code.insert(CImg<>::vector('/')); |
philpem@5 | 100 | font_code.insert(CImg<>::vector('\\')); |
philpem@5 | 101 | font_code.insert(CImg<>::vector('+')); |
philpem@5 | 102 | font_code.insert(CImg<>::vector('.')); |
philpem@5 | 103 | font_code.insert(CImg<>::vector('*')); |
philpem@5 | 104 | font_code.insert(CImg<>::vector('=')); |
philpem@5 | 105 | font_code.insert(CImg<>::vector(']')); |
philpem@5 | 106 | font_code.insert(CImg<>::vector('[')); |
philpem@5 | 107 | font_code.insert(CImg<>::vector('(')); |
philpem@5 | 108 | font_code.insert(CImg<>::vector(')')); |
philpem@5 | 109 | font_code.insert(CImg<>::vector('{')); |
philpem@5 | 110 | font_code.insert(CImg<>::vector('}')); |
philpem@5 | 111 | font_code.insert(CImg<>::vector('"')); |
philpem@5 | 112 | font_code.insert(CImg<>::vector('!')); |
philpem@5 | 113 | font_code.insert(CImg<>::vector('$')); |
philpem@5 | 114 | } break; |
philpem@5 | 115 | case 4: { |
philpem@5 | 116 | font_code.insert(CImg<>::vector(' ')); |
philpem@5 | 117 | font_code.insert(CImg<>::vector('.')); |
philpem@5 | 118 | font_code.insert(CImg<>::vector('/')); |
philpem@5 | 119 | font_code.insert(CImg<>::vector('\\')); |
philpem@5 | 120 | font_code.insert(CImg<>::vector('_')); |
philpem@5 | 121 | font_code.insert(CImg<>::vector('_')); |
philpem@5 | 122 | font_code.insert(CImg<>::vector('|')); |
philpem@5 | 123 | } break; |
philpem@5 | 124 | default: { for (unsigned char l=' '; l<='~'; l++) font_code.insert(CImg<>::vector(l)); } break; |
philpem@5 | 125 | } |
philpem@5 | 126 | cimglist_for(font_code,l) { |
philpem@5 | 127 | font.insert(font_full(font_code[l](0))); |
philpem@5 | 128 | font_blur.insert(font[l].get_resize(fw,fh,1,1).blur(sigma).normalize(0,255)); |
philpem@5 | 129 | } |
philpem@5 | 130 | |
philpem@5 | 131 | // Init images |
philpem@5 | 132 | CImg<> img; |
philpem@5 | 133 | if (!file_i) { float white[3] = { 255,255,255 }; img.assign().draw_text(0,0," CImg\nRocks !",white); } |
philpem@5 | 134 | else img.assign(file_i); |
philpem@5 | 135 | img.pointwise_norm().resize(fw*w,fh*h); |
philpem@5 | 136 | if (blur) img.blur(blur); |
philpem@5 | 137 | if (contour>0) { |
philpem@5 | 138 | CImgList<> grad = img.get_gradient("xy",4); |
philpem@5 | 139 | img = (grad[0].pow(2) + grad[1].pow(2)).sqrt().normalize(0,100).threshold(contour); |
philpem@5 | 140 | } |
philpem@5 | 141 | img.normalize(0,255); |
philpem@5 | 142 | if (invert) img = 255.0f-img; |
philpem@5 | 143 | CImg<unsigned char> dest(w,h,1,1,0); |
philpem@5 | 144 | |
philpem@5 | 145 | // Render ASCII-art image, using a simple correlation method. |
philpem@5 | 146 | CImg<> neigh; |
philpem@5 | 147 | cimg_forY(dest,y) { cimg_forX(dest,x) { |
philpem@5 | 148 | neigh = img.get_crop(x*fw,y*fh,(x+1)*fw,(y+1)*fh); |
philpem@5 | 149 | float scoremin = 2e28f; |
philpem@5 | 150 | unsigned int best = 0; |
philpem@5 | 151 | cimglist_for(font_code,l) { |
philpem@5 | 152 | const CImg<>& letter = font_blur[l]; |
philpem@5 | 153 | const float score = (float)((letter-neigh).pow(2).sum()); |
philpem@5 | 154 | if (score<scoremin) { scoremin = score; best = l; } |
philpem@5 | 155 | } |
philpem@5 | 156 | dest(x,y) = best; |
philpem@5 | 157 | std::fprintf(stdout,"%c",font_code[dest(x,y)](0)); |
philpem@5 | 158 | } |
philpem@5 | 159 | std::fprintf(stdout,"\n"); |
philpem@5 | 160 | } |
philpem@5 | 161 | |
philpem@5 | 162 | std::exit(0); |
philpem@5 | 163 | return 0; |
philpem@5 | 164 | } |