ASCII कला रूपांतरण के लिए छवि


102

प्रस्ताव

यह विषय यहां समय-समय पर स्टैक ओवरफ्लो पर पॉप अप होता है, लेकिन आमतौर पर लिखित प्रश्न होने के कारण इसे हटा दिया जाता है। मैंने ऐसे कई प्रश्न देखे और फिर ओपी (सामान्य कम प्रतिनिधि) से मौन रखा जब अतिरिक्त जानकारी का अनुरोध किया गया। समय-समय पर यदि इनपुट मेरे लिए पर्याप्त है, तो मैं एक उत्तर के साथ जवाब देने का निर्णय लेता हूं और यह आमतौर पर सक्रिय रहते हुए प्रति दिन कुछ अप-वोट प्राप्त करता है, लेकिन फिर कुछ हफ्तों के बाद प्रश्न हटा दिया जाता है / हटा दिया जाता है और सभी शुरू होता है इसकी शुरुआत हुई। इसलिए मैंने इस प्रश्नोत्तर को लिखने का निश्चय किया, इसलिए मैं इस तरह के प्रश्नों को सीधे उत्तर को फिर से लिखने के बिना संदर्भित कर सकता हूं…

एक और कारण यह भी है कि यह मेटा थ्रेड मुझ पर लक्षित है इसलिए यदि आपको अतिरिक्त इनपुट मिला है, तो टिप्पणी करने के लिए स्वतंत्र महसूस करें।

सवाल

मैं C ++ का उपयोग करके ASCII कला में बिटमैप छवि कैसे बदल सकता हूं ?

कुछ अड़चनें:

  • ग्रे स्केल छवियां
  • मोनो-स्पॉन्टेड फॉन्ट का उपयोग करना
  • इसे सरल रखना (शुरुआती स्तर के प्रोग्रामर के लिए बहुत उन्नत सामान का उपयोग नहीं करना)

यहाँ एक संबंधित विकिपीडिया पृष्ठ ASCII कला है (@RogerRowland के लिए धन्यवाद)।

यहाँ ASCII कला रूपांतरण Q & A के समान भूलभुलैया है


एक संदर्भ के रूप में इस विकी पृष्ठ का उपयोग करते हुए , क्या आप स्पष्ट कर सकते हैं कि आप किस प्रकार की ASCII कला का उल्लेख कर रहे हैं? यह मुझे लगता है जैसे "छवि से पाठ रूपांतरण" जो ग्रेस्केल पिक्सल से संबंधित पाठ चरित्र के लिए एक "सरल" लुक-अप है, इसलिए यदि आप कुछ अलग मतलब रखते हैं तो मैं सोच रहा हूं। ऐसा लगता है कि आप इसे वैसे भी खुद जवाब देने जा रहे हैं, लेकिन
रोजर रोलैंड


@RogerRowland दोनों सरल (केवल ग्रेस्केल तीव्रता आधारित) और अधिक उन्नत खाते में भी अक्षर का आकार ले रहे हैं (लेकिन अभी भी काफी सरल है)
Spektre

1
जबकि आपका काम महान है, मैं निश्चित रूप से उन नमूनों के चयन की सराहना करूंगा जो थोड़ा अधिक एसएफडब्ल्यू हैं।
22

@TimCastelijns यदि आप प्रस्तावना पढ़ते हैं, तो आप देख सकते हैं कि यह पहली बार नहीं है जब इस प्रकार के उत्तर का अनुरोध किया गया था (और शुरू से अधिकांश मतदाता जहां पिछले कुछ सवालों से परिचित थे, इसलिए बाकी सिर्फ उसी के अनुसार मतदान किया गया), जैसा कि यह प्रश्नोत्तर नहीं है क्यू मैं बहुत समय बर्बाद नहीं किया क्यू भाग के साथ (जो मेरी तरफ गलती है मैं मानता हूं) सवाल पर कुछ प्रतिबंध लगाए हैं अगर आपको बेहतर संपादित करने के लिए स्वतंत्र महसूस हुआ।
स्पेकट्रे

जवाबों:


152

ASCII कला रूपांतरण के लिए छवि के लिए अधिक दृष्टिकोण हैं जो ज्यादातर मोनो-स्पॉन्टेड फोंट का उपयोग करने पर आधारित हैं । सादगी के लिए, मैं केवल मूल बातों से चिपकता हूं:

पिक्सेल / क्षेत्र तीव्रता आधारित (छायांकन)

यह दृष्टिकोण पिक्सल के एक क्षेत्र के प्रत्येक पिक्सेल को एक डॉट के रूप में संभालता है। यह विचार इस बिंदु की औसत ग्रे स्केल तीव्रता की गणना करने के लिए है और फिर इसे गणना के लिए पर्याप्त तीव्रता के साथ चरित्र के साथ बदल दिया जाता है। उसके लिए हमें प्रयोग करने योग्य पात्रों की कुछ सूची चाहिए, जिनमें से प्रत्येक में एक पूर्वनिर्मित तीव्रता होती है। चलो इसे एक चरित्र कहते हैं map। अधिक तेज़ी से चुनने के लिए कि कौन सा चरित्र किस तीव्रता के लिए सबसे अच्छा है, दो तरीके हैं:

  1. रैखिक वितरित तीव्रता चरित्र मानचित्र

    इसलिए हम केवल उन पात्रों का उपयोग करते हैं जिनमें एक ही चरण के साथ तीव्रता का अंतर होता है। दूसरे शब्दों में, जब तब आरोही क्रमबद्ध होता है:

     intensity_of(map[i])=intensity_of(map[i-1])+constant;

    इसके अलावा जब हमारे चरित्र mapको क्रमबद्ध किया जाता है तो हम चरित्र की तीव्रता से सीधे गणना कर सकते हैं (कोई खोज की आवश्यकता नहीं)

     character = map[intensity_of(dot)/constant];
  2. मनमाना वितरण तीव्रता चरित्र मानचित्र

    इसलिए हमारे पास प्रयोग करने योग्य वर्ण और उनकी तीव्रता है। हमें गहनता को intensity_of(dot)फिर से खोजने की आवश्यकता है यदि हमने छांटा है map[], तो हम बाइनरी खोज का उपयोग कर सकते हैं, अन्यथा हमें एक O(n)न्यूनतम दूरी लूप या O(1)शब्दकोश की आवश्यकता है। कभी-कभी सादगी के लिए, चरित्र map[]को रैखिक रूप से वितरित के रूप में संभाला जा सकता है, जिससे थोड़ी सी गामा विरूपण होता है, आमतौर पर परिणाम में अनदेखी जब तक आप नहीं जानते कि क्या देखना है।

तीव्रता-आधारित रूपांतरण ग्रे-स्केल छवियों (न केवल काले और सफेद) के लिए भी महान है। यदि आप एक एकल पिक्सेल के रूप में डॉट का चयन करते हैं, तो परिणाम बड़े (एक पिक्सेल -> एकल चरित्र) हो जाता है, इसलिए बड़ी छवियों के लिए पहलू अनुपात को संरक्षित करने के लिए एक क्षेत्र (फ़ॉन्ट आकार का गुणा) का चयन किया जाता है और बहुत अधिक विस्तार न करें।

यह कैसे करना है:

  1. समान रूप से (ग्रे पैमाने पर) पिक्सल या में छवि को विभाजित (आयताकार) क्षेत्रों डॉट रों
  2. प्रत्येक पिक्सेल / क्षेत्र की तीव्रता की गणना करें
  3. इसे चरित्र मानचित्र से चरित्र द्वारा निकटतम तीव्रता से बदलें

चरित्र के रूप में mapआप किसी भी वर्ण का उपयोग कर सकते हैं, लेकिन परिणाम बेहतर हो जाता है यदि चरित्र में पिक्सेल समान रूप से वर्ण क्षेत्र के साथ बिखरे हुए हैं। शुरुआत के लिए आप उपयोग कर सकते हैं:

  • char map[10]=" .,:;ox%#@";

क्रमबद्ध अवरोही और रैखिक रूप से वितरित होने का दिखावा करते हैं।

इसलिए यदि पिक्सेल / क्षेत्र की तीव्रता है i = <0-255>तो प्रतिस्थापन चरित्र होगा

  • map[(255-i)*10/256];

यदि i==0तब पिक्सेल / क्षेत्र काला है, तो यदि i==127पिक्सेल / क्षेत्र ग्रे है, और यदि i==255पिक्सेल / क्षेत्र सफेद है। आप विभिन्न पात्रों के साथ प्रयोग कर सकते हैं map[]...

यहाँ C ++ और VCL में मेरा एक प्राचीन उदाहरण है:

AnsiString m = " .,:;ox%#@";
Graphics::TBitmap *bmp = new Graphics::TBitmap;
bmp->LoadFromFile("pic.bmp");
bmp->HandleType = bmDIB;
bmp->PixelFormat = pf24bit;

int x, y, i, c, l;
BYTE *p;
AnsiString s, endl;
endl = char(13); endl += char(10);
l = m.Length();
s ="";
for (y=0; y<bmp->Height; y++)
{
    p = (BYTE*)bmp->ScanLine[y];
    for (x=0; x<bmp->Width; x++)
    {
        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];
    }
    s += endl;
}
mm_log->Lines->Text = s;
mm_log->Lines->SaveToFile("pic.txt");
delete bmp;

जब तक आप Borland / Embarcadero वातावरण का उपयोग नहीं करते हैं, आपको VCL सामान को बदलने / अनदेखा करने की आवश्यकता है।

  • mm_log वह मेमो है जहां टेक्स्ट को आउटपुट किया जाता है
  • bmp इनपुट बिटमैप है
  • AnsiString1 से अनुक्रमित VCL प्रकार स्ट्रिंग है, 0 से नहीं char*!!!

यह परिणाम है: थोड़ा NSFW तीव्रता उदाहरण छवि

बाईं ओर ASCII कला आउटपुट (फ़ॉन्ट आकार 5 पिक्सेल) है, और दाईं ओर इनपुट छवि कुछ बार ज़ूम की गई है। जैसा कि आप देख सकते हैं, आउटपुट बड़ा पिक्सेल है -> चरित्र। यदि आप पिक्सेल के बजाय बड़े क्षेत्रों का उपयोग करते हैं तो ज़ूम छोटा होता है, लेकिन निश्चित रूप से आउटपुट नेत्रहीन सुखदायक होता है। यह दृष्टिकोण कोड / प्रक्रिया के लिए बहुत आसान और तेज़ है।

जब आप अधिक उन्नत चीजें जोड़ते हैं जैसे:

  • स्वचालित मानचित्र संगणना
  • स्वचालित पिक्सेल / क्षेत्र आकार चयन
  • पहलू अनुपात सुधार

तब आप बेहतर परिणामों के साथ अधिक जटिल छवियों को संसाधित कर सकते हैं:

यहाँ 1: 1 अनुपात (वर्णों को देखने के लिए ज़ूम) में परिणाम है:

तीव्रता उन्नत उदाहरण

बेशक, क्षेत्र के नमूने के लिए आप छोटे विवरण खो देते हैं। यह उसी आकार की एक छवि है जिसका पहला उदाहरण क्षेत्रों के साथ नमूना है:

थोड़ा NSFW तीव्रता उन्नत उदाहरण छवि

जैसा कि आप देख सकते हैं, यह बड़ी छवियों के लिए अधिक अनुकूल है।

चरित्र फिटिंग (छायांकन और ठोस ASCII कला के बीच संकर)

यह दृष्टिकोण समान तीव्रता और आकार वाले चरित्र के साथ क्षेत्र (कोई अधिक एकल पिक्सेल डॉट्स) को बदलने की कोशिश करता है। यह बेहतर परिणाम की ओर जाता है, यहां तक ​​कि पिछले दृष्टिकोण की तुलना में बड़े फोंट का उपयोग किया जाता है। दूसरी ओर, यह दृष्टिकोण थोड़ा धीमा है। ऐसा करने के लिए और अधिक तरीके हैं, लेकिन मुख्य विचार छवि क्षेत्र ( dot) और गाया चरित्र के बीच अंतर (दूरी) की गणना करना है । आप पिक्सेल के बीच पूर्ण अंतर की भोली राशि के साथ शुरू कर सकते हैं, लेकिन यह बहुत अच्छे परिणाम नहीं देगा क्योंकि एक-पिक्सेल पारी भी दूरी को बड़ा कर देगी। इसके बजाय आप सहसंबंध या विभिन्न मैट्रिक्स का उपयोग कर सकते हैं। समग्र एल्गोरिथ्म पिछले दृष्टिकोण के समान ही है:

  1. तो समान रूप से करने के लिए छवि को विभाजित (ग्रे पैमाने पर) आयताकार क्षेत्रों डॉट की

    रेंडर किए गए फ़ॉन्ट वर्णों के समान ही आदर्श अनुपात (यह पहलू अनुपात को संरक्षित करेगा। यह मत भूलो कि आमतौर पर अक्षर एक्स-अक्ष पर थोड़ा ओवरलैप करते हैं)

  2. प्रत्येक क्षेत्र की तीव्रता की गणना करें ( dot)

  3. इसे mapनिकटतम तीव्रता / आकार वाले चरित्र से एक चरित्र द्वारा प्रतिस्थापित करें

हम चरित्र और बिंदी के बीच की दूरी की गणना कैसे कर सकते हैं? यह इस दृष्टिकोण का सबसे कठिन हिस्सा है। प्रयोग करते समय, मैं इस समझौते को गति, गुणवत्ता और सरलता के बीच विकसित करता हूं:

  1. क्षेत्र को वर्णों में विभाजित करें

    क्षेत्र

    • अपने रूपांतरण वर्णमाला ( map) से प्रत्येक वर्ण के बाएँ, दाएँ, ऊपर, नीचे और केंद्र क्षेत्र के लिए एक अलग तीव्रता की गणना करें ।
    • , सभी तीव्रता को सामान्य है, इसलिए वे क्षेत्र आकार पर स्वतंत्र हैं i=(i*256)/(xs*ys)
  2. आयत क्षेत्रों में स्रोत छवि को संसाधित करें

    • (लक्ष्य फ़ॉन्ट के समान पहलू अनुपात के साथ)
    • प्रत्येक क्षेत्र के लिए, बुलेट # 1 की तरह तीव्रता की गणना करें
    • रूपांतरण वर्णमाला में तीव्रता से निकटतम मैच का पता लगाएं
    • फिट चरित्र का उत्पादन

यह फ़ॉन्ट आकार = 7 पिक्सेल के लिए परिणाम है

चरित्र फिटिंग उदाहरण

जैसा कि आप देख सकते हैं, आउटपुट नेत्रहीन रूप से मनभावन है, यहां तक ​​कि उपयोग किए जाने वाले एक बड़े फ़ॉन्ट आकार के साथ (पिछला दृष्टिकोण उदाहरण 5 पिक्सेल फ़ॉन्ट आकार के साथ था)। आउटपुट लगभग छवि आकार (ज़ूम नहीं) के समान है। बेहतर परिणाम प्राप्त होते हैं क्योंकि वर्ण मूल छवि के करीब होते हैं, न केवल तीव्रता से, बल्कि समग्र आकार से भी, और इसलिए आप बड़े फोंट का उपयोग कर सकते हैं और फिर भी विवरणों (एक बिंदु तक) को संरक्षित कर सकते हैं।

यहां VCL- आधारित रूपांतरण एप्लिकेशन का पूरा कोड दिया गया है:

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

TForm1 *Form1;
Graphics::TBitmap *bmp=new Graphics::TBitmap;
//---------------------------------------------------------------------------


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;
}


//---------------------------------------------------------------------------
AnsiString bmp2txt_small(Graphics::TBitmap *bmp)    // pixel sized areas
{
    AnsiString m = " `'.,:;i+o*%&$#@"; // Constant character map
    int x, y, i, c, l;
    BYTE *p;
    AnsiString txt = "", eol = "\r\n";
    l = m.Length();
    bmp->HandleType = bmDIB;
    bmp->PixelFormat = pf32bit;
    for (y=0; y<bmp->Height; y++)
    {
        p = (BYTE*)bmp->ScanLine[y];
        for (x=0; x<bmp->Width; x++)
        {
            i  = p[(x<<2)+0];
            i += p[(x<<2)+1];
            i += p[(x<<2)+2];
            i  = (i*l)/768;
            txt += m[l-i];
        }
        txt += eol;
    }
    return txt;
}


//---------------------------------------------------------------------------
void update()
{
    int x0, x1, y0, y1, i, l;
    x0 = bmp->Width;
    y0 = bmp->Height;
    if ((x0<64)||(y0<64)) Form1->mm_txt->Text = bmp2txt_small(bmp);
     else                  Form1->mm_txt->Text = bmp2txt_big  (bmp, Form1->mm_txt->Font);
    Form1->mm_txt->Lines->SaveToFile("pic.txt");
    for (x1 = 0, i = 1, l = Form1->mm_txt->Text.Length();i<=l;i++) if (Form1->mm_txt->Text[i] == 13) { x1 = i-1; break; }
    for (y1=0, i=1, l=Form1->mm_txt->Text.Length();i <= l; i++) if (Form1->mm_txt->Text[i] == 13) y1++;
    x1 *= abs(Form1->mm_txt->Font->Size);
    y1 *= abs(Form1->mm_txt->Font->Height);
    if (y0<y1) y0 = y1; x0 += x1 + 48;
    Form1->ClientWidth = x0;
    Form1->ClientHeight = y0;
    Form1->Caption = AnsiString().sprintf("Picture -> Text (Font %ix%i)", abs(Form1->mm_txt->Font->Size), abs(Form1->mm_txt->Font->Height));
}


//---------------------------------------------------------------------------
void draw()
{
    Form1->ptb_gfx->Canvas->Draw(0, 0, bmp);
}


//---------------------------------------------------------------------------
void load(AnsiString name)
{
    bmp->LoadFromFile(name);
    bmp->HandleType = bmDIB;
    bmp->PixelFormat = pf32bit;
    Form1->ptb_gfx->Width = bmp->Width;
    Form1->ClientHeight = bmp->Height;
    Form1->ClientWidth = (bmp->Width << 1) + 32;
}


//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
    load("pic.bmp");
    update();
}


//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
    delete bmp;
}


//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
    draw();
}


//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
    int s = abs(mm_txt->Font->Size);
    if (WheelDelta<0) s--;
    if (WheelDelta>0) s++;
    mm_txt->Font->Size = s;
    update();
}

//---------------------------------------------------------------------------

इसमें Form1एक एकल के साथ एक फॉर्म एप्लिकेशन ( ) सरल TMemo mm_txtहै। यह एक छवि को लोड करता है "pic.bmp", और फिर रिज़ॉल्यूशन के अनुसार, पाठ में परिवर्तित करने के लिए किस दृष्टिकोण का उपयोग करता है जिसे "pic.txt"विज़ुअलाइज़ करने के लिए मेमो में भेजा जाता है।

वीसीएल के बिना उन लोगों के लिए, वीसीएल सामान को अनदेखा करें और AnsiStringआपके पास किसी भी स्ट्रिंग प्रकार के साथ बदलें , और Graphics::TBitmapकिसी भी बिटमैप या छवि वर्ग के साथ जो आपके पास पिक्सेल पहुंच क्षमता के साथ निपटान में है।

एक बहुत ही महत्वपूर्ण नोट यह है कि यह सेटिंग्स का उपयोग करता है mm_txt->Font, इसलिए सुनिश्चित करें कि आपने सेट किया है:

  • Font->Pitch = fpFixed
  • Font->Charset = OEM_CHARSET
  • Font->Name = "System"

इस काम को ठीक से करने के लिए, अन्यथा फ़ॉन्ट को मोनो-स्पेस के रूप में नहीं संभाला जाएगा। माउस व्हील सिर्फ भिन्न फ़ॉन्ट आकारों पर परिणाम देखने के लिए फ़ॉन्ट आकार को ऊपर / नीचे बदलता है।

[टिप्पणियाँ]

  • वर्ड पोर्ट्रेट विज़ुअलाइज़ेशन देखें
  • बिटमैप / फ़ाइल एक्सेस और टेक्स्ट आउटपुट क्षमताओं वाली भाषा का उपयोग करें
  • मैं दृढ़ता से पहले दृष्टिकोण के साथ शुरू करने की सलाह देता हूं क्योंकि यह बहुत सरल और सरल है, और उसके बाद ही दूसरे पर जाएं (जो कि पहले के संशोधन के रूप में किया जा सकता है, इसलिए अधिकांश कोड वैसे भी रहता है)
  • उल्टे तीव्रता (काले पिक्सेल अधिकतम मूल्य है) के साथ गणना करना एक अच्छा विचार है क्योंकि मानक पाठ पूर्वावलोकन एक सफेद पृष्ठभूमि पर है, इसलिए बहुत बेहतर परिणाम देता है।
  • आप उपखंड क्षेत्रों के आकार, गणना और लेआउट के साथ प्रयोग कर सकते हैं या 3x3इसके बजाय कुछ ग्रिड का उपयोग कर सकते हैं ।

तुलना

अंत में यहाँ एक ही इनपुट पर दो दृष्टिकोणों के बीच तुलना है:

तुलना

हरे रंग की बिंदी के रूप में चिह्नित छवियां # 2 के साथ की जाती हैं और लाल वाले # 1 के साथ , सभी छह-पिक्सेल फ़ॉन्ट आकार पर। जैसा कि आप प्रकाश बल्ब छवि पर देख सकते हैं, आकार-संवेदनशील दृष्टिकोण बहुत बेहतर है (भले ही # 1 2x ज़ूम की गई स्रोत छवि पर किया गया हो)।

शांत अनुप्रयोग

आज के नए प्रश्नों को पढ़ते हुए, मुझे एक अच्छे अनुप्रयोग का विचार मिला जो डेस्कटॉप के चयनित क्षेत्र को पकड़ता है और लगातार ASCIIart कनवर्टर को खिलाता है और परिणाम देखता है। एक घंटे की कोडिंग के बाद, यह हो गया है और मैं इस परिणाम से इतना संतुष्ट हूं कि मुझे इसे यहां जोड़ना होगा।

ठीक है आवेदन सिर्फ दो खिड़कियों के होते हैं। पहली मास्टर विंडो मूल रूप से छवि चयन और पूर्वावलोकन के बिना मेरी पुरानी कनवर्टर विंडो है (ऊपर सभी सामान इसमें है)। इसमें ASCII पूर्वावलोकन और रूपांतरण सेटिंग हैं। दूसरी विंडो हड़पने वाले क्षेत्र के चयन के लिए पारदर्शी के साथ एक खाली रूप है (कोई भी कार्यक्षमता नहीं है)।

अब एक टाइमर पर, मैं सिर्फ चयनित क्षेत्र को चयन प्रपत्र द्वारा हड़पता हूं , इसे रूपांतरण में पास करता हूं , और ASCIIart का पूर्वावलोकन करता हूं

इसलिए आप उस क्षेत्र को संलग्न करते हैं जिसे आप चयन विंडो द्वारा परिवर्तित करना चाहते हैं और मास्टर विंडो में परिणाम देखते हैं। यह एक खेल, दर्शक आदि हो सकता है, यह इस तरह दिखता है:

ASCIIart धरनेवाला उदाहरण

इसलिए अब मैं मनोरंजन के लिए ASCIIart में भी वीडियो देख सकता हूं । कुछ बहुत अच्छे हैं :)।

हाथ

यदि आप इसे GLSL में लागू करने का प्रयास करना चाहते हैं, तो इस पर एक नज़र डालें:


30
आपने यहां एक अविश्वसनीय काम किया! धन्यवाद! और मुझे ASCII सेंसरिंग बहुत पसंद है!
एंडर बिगुरी

1
सुधार के लिए एक सुझाव: दिशात्मक व्युत्पन्न काम करें, न कि केवल तीव्रता।
यक्क - एडम नेवरुमोंट

1
@ याक देखभाल करने के लिए विस्तृत?
टेरिकब्लास

2
@tarik या तो न केवल तीव्रता पर मेल खाता है, बल्कि डेरिवेटिव पर: या, बैंड पास किनारों को बढ़ाता है। मूल रूप से तीव्रता केवल एक चीज नहीं है जिसे लोग देखते हैं: वे ग्रेडिएंट और किनारों को देखते हैं।
यक्क - एडम नेवरामोंट

1
@ यक ज़ोन उपखंड परोक्ष रूप से इस तरह के काम करता है। हो सकता है बेहतर होगा कि 3x3जोन के रूप में एक हैंडल कैरेक्टर किया जाए और डीसीटी की तुलना की जाए, लेकिन इससे मेरे प्रदर्शन में कमी आएगी।
स्पेकट्रे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.