Conversion d'image en art ASCII en C
La conversion d'une image bitmap en art ASCII implique d'utiliser des polices à espacement fixe et de garder le processus simple. Il existe deux approches principales :
Basée sur l'intensité des pixels/zones :
Cette approche traite chaque pixel ou zone de pixels comme un seul point. Il calcule l'intensité moyenne de l'échelle de gris du point et la remplace par un caractère d'intensité la plus proche.
Ajustement des caractères (hybride) :
Cette approche tente de remplacer les zones (en forme de caractère) avec des caractères d'intensité et de forme similaires. Cela conduit à de meilleurs résultats mais est plus lent en raison des calculs.
Mise en œuvre détaillée :
Basée sur l'intensité des pixels/surface :
Divisez l'image en pixels en niveaux de gris ou en zones rectangulaires (points). Calculez l'intensité de chaque point. Remplacez-le par un caractère d'une carte de caractères (intensités précalculées) avec l'intensité la plus proche.
Un exemple de carte de caractères : " .,:;ox%#@&"
Calcul de l'intensité :
<code class="C++">i = p[x+x+x+0]; i += p[x+x+x+1]; i += p[x+x+x+2]; i = (i*l)/768; s += m[l-i];</code>
où :
Ajustement des caractères :
Divisez l'image en zones rectangulaires avec le même rapport hauteur/largeur que les caractères . Divisez la zone de caractère en zones et calculez l'intensité de chaque zone. Trouvez le caractère sur la carte avec l'intensité et la forme les plus proches.
Cette approche conduit à des résultats optimaux et visuellement plus agréables lors de l'utilisation de polices plus grandes.
Exemple de code :
<code class="C++">class intensity { public: char c; // Character int il, ir, iu ,id, ic; // Intensity of part: left,right,up,down,center intensity() { c=0; reset(); } void reset() { il=0; ir=0; iu=0; id=0; ic=0; } void compute(DWORD **p,int xs,int ys,int xx,int yy) // p source image, (xs,ys) area size, (xx,yy) area position { int x0 = xs>>2, y0 = ys>>2; int x1 = xs-x0, y1 = ys-y0; int x, y, i; reset(); for (y=0; y<ys; y++) for (x=0; x<xs; x++) { i = (p[yy+y][xx+x] & 255); if (x<=x0) il+=i; if (x>=x1) ir+=i; if (y<=x0) iu+=i; if (y>=x1) id+=i; if ((x>=x0) && (x<=x1) && (y>=y0) && (y<=y1)) ic+=i; } // Normalize i = xs*ys; il = (il << 8)/i; ir = (ir << 8)/i; iu = (iu << 8)/i; id = (id << 8)/i; ic = (ic << 8)/i; } }; AnsiString bmp2txt_big(Graphics::TBitmap *bmp,TFont *font) // Character sized areas { int i, i0, d, d0; int xs, ys, xf, yf, x, xx, y, yy; DWORD **p = NULL,**q = NULL; // Bitmap direct pixel access Graphics::TBitmap *tmp; // Temporary bitmap for single character AnsiString txt = ""; // Output ASCII art text AnsiString eol = "\r\n"; // End of line sequence intensity map[97]; // Character map intensity gfx; // Input image size xs = bmp->Width; ys = bmp->Height; // Output font size xf = font->Size; if (xf<0) xf =- xf; yf = font->Height; if (yf<0) yf =- yf; for (;;) // Loop to simplify the dynamic allocation error handling { // Allocate and initialise buffers tmp = new Graphics::TBitmap; if (tmp==NULL) break; // Allow 32 bit pixel access as DWORD/int pointer tmp->HandleType = bmDIB; bmp->HandleType = bmDIB; tmp->PixelFormat = pf32bit; bmp->PixelFormat = pf32bit; // Copy target font properties to tmp tmp->Canvas->Font->Assign(font); tmp->SetSize(xf, yf); tmp->Canvas->Font ->Color = clBlack; tmp->Canvas->Pen ->Color = clWhite; tmp->Canvas->Brush->Color = clWhite; xf = tmp->Width; yf = tmp->Height; // Direct pixel access to bitmaps p = new DWORD*[ys]; if (p == NULL) break; for (y=0; y<ys; y++) p[y] = (DWORD*)bmp->ScanLine[y]; q = new DWORD*[yf]; if (q == NULL) break; for (y=0; y<yf; y++) q[y] = (DWORD*)tmp->ScanLine[y]; // Create character map for (x=0, d=32; d<128; d++, x++) { map[x].c = char(DWORD(d)); // Clear tmp tmp->Canvas->FillRect(TRect(0, 0, xf, yf)); // Render tested character to tmp tmp->Canvas->TextOutA(0, 0, map[x].c); // Compute intensity map[x].compute(q, xf, yf, 0, 0); } map[x].c = 0; // Loop through the image by zoomed character size step xf -= xf/3; // Characters are usually overlapping by 1/3 xs -= xs % xf; ys -= ys % yf; for (y=0; y<ys; y+=yf, txt += eol) for (x=0; x<xs; x+=xf) { // Compute intensity gfx.compute(p, xf, yf, x, y); // Find the closest match in map[] i0 = 0; d0 = -1; for (i=0; map[i].c; i++) { d = abs(map[i].il-gfx.il) + abs(map[i].ir-gfx.ir) + abs(map[i].iu-gfx.iu) + abs(map[i].id-gfx.id) + abs(map[i].ic-gfx.ic); if ((d0<0)||(d0>d)) { d0=d; i0=i; } } // Add fitted character to output txt += map[i0].c; } break; } // Free buffers if (tmp) delete tmp; if (p ) delete[] p; return txt; }</code>
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!