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



image-processing bitmap (1)

प्रस्तावना

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

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

सवाल

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

कुछ अड़चनें:

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

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


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[] को map[] हम बाइनरी खोज का उपयोग कर सकते हैं अन्यथा हमें O(n) खोज मिनट दूरी पाश या O(1) शब्दकोश की आवश्यकता है। कभी-कभी सादगी के लिए चरित्र map[] को रैखिक रूप से वितरित किया जा सकता है, जिसके कारण मामूली गामा विकृति आमतौर पर परिणाम में अनदेखी होती है जब तक कि आप नहीं जानते कि क्या देखना है।

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

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

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

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

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

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

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

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

अगर i==0 तो पिक्सेल / क्षेत्र काला है, अगर i==127 तो पिक्सेल / क्षेत्र ग्रे है और यदि i==255 तो पिक्सेल / क्षेत्र सफेद है। आप map[] अंदर विभिन्न पात्रों के साथ प्रयोग कर सकते हैं map[] ... 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 मेमो है जहां टेक्स्ट mm_log होता है
  • bmp इनपुट बिटमैप है
  • AnsiString VCL टाइप स्ट्रिंग इंडेक्सेड फॉर्म 1 है जो 0 से char* रूप में नहीं है char* !!!

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

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

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

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

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

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

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

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

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

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

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

  1. तो समान रूप से छवि को (ग्रे-स्केल) आयताकार क्षेत्रों डॉट को विभाजित करें
    • रेंडर किए गए फ़ॉन्ट वर्णों के समान आदर्श अनुपात के साथ आदर्श रूप में (यह पहलू अनुपात को संरक्षित करेगा, यह मत भूलो कि वर्ण आमतौर पर x अक्षर में थोड़ा ओवरलैप होते हैं)
  2. प्रत्येक क्षेत्र ( dot ) की तीव्रता की गणना करें
  3. इसे चरित्र map से चरित्र की जगह निकटतम तीव्रता / आकार से बदलें

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

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

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

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

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

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

वीसीएल आधारित रूपांतरण ऐप के लिए यहां पूरा कोड:

//---------------------------------------------------------------------------
#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) // charcter 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;     // temp 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 init buffers
        tmp=new Graphics::TBitmap; if (tmp==NULL) break;
            // allow 32bit 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 image by zoomed character size step
        xf-=xf/3; // characters are usually overlaping 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 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();
    }
//---------------------------------------------------------------------------

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

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

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

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

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

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

[Edit1] तुलना

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

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

[संपादित करें] शांत अनुप्रयोग

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

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

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

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

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

[Edit3]

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

  • जीएलएसएल में फ्लोटिंग-पॉइंट नंबरों को दशमलव अंकों में बदलें?




ascii-art