2 คะแนน โดย GN⁺ 2026-01-18 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • พัฒนา เทคนิคการเรนเดอร์ ASCII ที่คงเส้นขอบและรูปทรงของภาพ เพื่อแก้ปัญหาขอบเบลอของวิธีแบบเดิม
  • แทนที่จะแมปความสว่างแบบง่าย ๆ ในระดับพิกเซล ใช้ แนวทางแบบเวกเตอร์มิติสูง ที่วัดและจับคู่ รูปร่างเชิงภาพ (shape) ของแต่ละอักขระ
  • วัดความหนาแน่นของแต่ละอักขระในบริเวณบน·ล่าง·ซ้าย·ขวา เพื่อสร้าง shape vector ที่ขยายจาก 2 มิติเป็น 6 มิติ ทำให้เลือกอักขระได้แม่นยำยิ่งขึ้น
  • ใช้อัลกอริทึม เพิ่มคอนทราสต์แบบทั่วทั้งภาพและแบบมีทิศทาง (contrast enhancement) เพื่อให้เส้นขอบคมชัดขึ้น
  • ด้วยการเร่งความเร็วด้วย GPU การแคช และการค้นหาด้วย k-d tree ทำให้ได้ ประสิทธิภาพการเรนเดอร์ ASCII แบบเรียลไทม์ และเอฟเฟกต์ภาพคุณภาพสูง

การแปลงภาพเป็น ASCII

  • ASCII มีอักขระที่พิมพ์ได้ 95 ตัว และใช้ ฟอนต์โมโนสเปซ เพื่อแบ่งภาพเป็นกริด
    • คำนวณความสว่างของแต่ละช่อง แล้วแมปตามความหนาแน่นของอักขระ
  • การอินเตอร์โพเลตแบบ nearest-neighbor อย่างง่ายจะทำให้เกิด jaggies หรือขอบหยักไม่เรียบ
  • หากใช้ supersampling เพื่อเก็บหลายตัวอย่างภายในแต่ละช่องแล้วคำนวณค่าเฉลี่ยความสว่าง ภาพจะนุ่มนวลขึ้น แต่ขอบก็ยังเบลออยู่
  • แก่นของปัญหาคือการ ปฏิบัติต่ออักขระเหมือนพิกเซล โดยไม่ได้คำนึงถึงรูปร่างเฉพาะของอักขระ

การใช้รูปร่างของอักขระ (Shape)

  • อักขระแต่ละตัวมี การกระจายความหนาแน่นเชิงภาพ ภายในช่องต่างกัน
    • ตัวอย่าง: T มีน้ำหนักด้านบนมาก ส่วน L มีน้ำหนักด้านล่างมาก
  • เพื่อวัดสิ่งนี้ จึงวาง วงกลมสำหรับการสุ่มตัวอย่าง ไว้ภายในช่อง และคำนวณสัดส่วนพื้นที่ที่อักขระครอบครองในแต่ละส่วน
  • แทนสัดส่วนการครอบครองของบริเวณบน·ล่างเป็นเวกเตอร์ เพื่อสร้าง shape vector แบบ 2 มิติ
  • คำนวณ shape vector ของแต่ละอักขระไว้ล่วงหน้า แล้วเลือกอักขระที่ใกล้กับเวกเตอร์ตัวอย่างของภาพมากที่สุดด้วย Euclidean distance

การขยายเป็นเวกเตอร์รูปร่าง 6 มิติ

  • ข้อมูล 2 มิติเฉพาะบน·ล่างยังไม่เพียงพอสำหรับอักขระอย่าง -, p, q ที่มีจุดศูนย์กลางอยู่ตรงกลางหรือเอนซ้าย·ขวา
  • ขยายช่องเป็นวงกลมสำหรับการสุ่มตัวอย่าง 6 จุด เพื่อจับทั้งความต่างของ บน·กลาง·ล่าง และซ้าย·ขวา
  • shape vector 6 มิติ สะท้อนรูปร่างของอักขระได้ละเอียดขึ้นมาก และถ่ายทอดอักขระทรงกลมหรือเส้นทแยงได้ดี
  • เมื่อใช้เรนเดอร์ฉาก 3D แม้เส้นขอบภายนอกจะคมชัด แต่ยังเกิดปัญหาขอบระหว่างพื้นผิวดูเบลอ

การเพิ่มคอนทราสต์ (Contrast Enhancement)

  • ปรับองค์ประกอบแต่ละตัวของเวกเตอร์ตัวอย่างด้วย เลขชี้กำลัง (exponent) เพื่อให้ค่ามืดมืดยิ่งขึ้น ขณะที่ค่าที่สว่างยังคงเดิม
    • นอร์มัลไลซ์เวกเตอร์ก่อน ใช้เลขชี้กำลัง แล้วจึงคืนกลับสู่ช่วงเดิม
  • กระบวนการนี้ช่วย เพิ่มความต่างของเส้นขอบในเชิงภาพ ทำให้การเลือกอักขระชัดเจนขึ้น
  • ในบริเวณที่มีความสว่างสม่ำเสมอแทบไม่เกิดการเปลี่ยนแปลง จึงยัง รักษาไล่ระดับที่นุ่มนวล ไว้ได้
  • อย่างไรก็ตาม ขอบบางส่วนอาจเกิดอาการ staircasing เป็นขั้นบันได

การเพิ่มคอนทราสต์แบบมีทิศทาง (Directional Contrast Enhancement)

  • วาง วงกลมสำหรับการสุ่มตัวอย่างภายนอก ไว้นอกแต่ละช่องด้วย เพื่อเก็บข้อมูลความสว่างของบริเวณรอบข้าง
  • ค่าสว่างในเวกเตอร์ตัวอย่างภายนอกจะไปปรับให้องค์ประกอบที่สอดคล้องกันของเวกเตอร์ภายในมืดลง เป็นการ เพิ่มคอนทราสต์ตามทิศทางของขอบ
  • เมื่อขยายการสุ่มตัวอย่างภายนอกให้ส่งผลระหว่างส่วนบน·กลาง·ล่างได้กว้างขึ้น ก็สามารถ ถ่ายทอดขอบที่นุ่มนวลและคมชัด ได้
  • เมื่อนำไปรวมกับการเพิ่มคอนทราสต์แบบทั่วทั้งภาพ จะได้ การเรนเดอร์ ASCII สำหรับฉาก 3D ที่ขอบเด่นชัดและอ่านง่าย

การเพิ่มประสิทธิภาพ

  • หากเลือกอักขระด้วย การค้นหาเพื่อนบ้านใกล้สุด แบบวนซ้ำตรง ๆ จะช้า จึงใช้ k-d tree เพื่อค้นหาอย่างรวดเร็วในปริภูมิหลายมิติ
  • ใช้แคชเพื่อนำผลลัพธ์ของเวกเตอร์ตัวอย่างเดิมกลับมาใช้ซ้ำ
    • ควอนไทซ์แต่ละเวกเตอร์เป็นหน่วย 5 บิต เพื่อสร้าง คีย์แคชที่ประหยัดหน่วยความจำ
    • ตั้งช่วงค่าไว้ที่ 8 เพื่อรักษาสมดุลระหว่างคุณภาพกับการใช้หน่วยความจำ
  • การค้นหาจากแคชทำได้รวดเร็วมาก และ สามารถประมวลผลอักขระหลายพันตัวแบบเรียลไทม์ได้
  • ย้ายการคำนวณเวกเตอร์ตัวอย่างไปทำบน GPU เพื่อให้ การสุ่มตัวอย่างภายใน·ภายนอก และการเพิ่มคอนทราสต์ถูกประมวลผลใน shader pipeline
    • ประสิทธิภาพสูงกว่า CPU หลายเท่า

บทสรุป

  • แนวทางที่แปลงรูปร่างของอักขระเป็นเวกเตอร์เชิงตัวเลขแล้วนำมาใช้ ช่วยยกระดับความละเอียดและความคมชัดของการเรนเดอร์ ASCII อย่างมาก
  • วิธีนี้มีแนวคิดคล้ายกับ word embedding และอาจประยุกต์ใช้กับปัญหาด้านภาพอื่น ๆ ได้
  • แม้การทำงานช่วงแรกจะช้า แต่ด้วย GPU acceleration, caching และการค้นหาด้วย k-d tree ก็ทำให้ได้ FPS ที่ลื่นไหลแม้บนมือถือ
  • บทความนี้ยังไม่ได้กล่าวถึงการแสดงผล ASCII แบบอิงสี และชี้ว่าต่อไปยังสามารถทดลองการผสมผสานรูปทรง·คอนทราสต์ได้หลากหลายขึ้น
  • การเรนเดอร์ ASCII ไม่ได้เป็นเพียงเอฟเฟกต์ภาพธรรมดา แต่เป็นตัวอย่างที่แสดงให้เห็นถึง ศักยภาพในการขยายการรู้จำรูปทรงและการแทนค่าแบบเวกเตอร์

1 ความคิดเห็น

 
GN⁺ 2026-01-18
ความเห็นจาก Hacker News
  • ถ้าทำการ normalize เวกเตอร์แล้วคำนวณ ระยะห่างแบบยุคลิด ก็สามารถได้ผลลัพธ์เดียวกันด้วยการทำ matrix multiplication (matmul) ธรรมดา
    เพราะสำหรับเวกเตอร์ที่ถูก normalize แล้ว ระยะห่างแบบยุคลิดเป็น linear transform ของ cosine distance
    ถ้าสิ่งที่สำคัญคือแค่ ลำดับอันดับ (ranking) ไม่ใช่ค่าระยะจริง ก็ข้ามการคำนวณ sqrt ได้และจะได้ผลลัพธ์เหมือนเดิม พร้อมคำนวณได้เร็วขึ้นเล็กน้อย

    • ถ้ารู้เรื่องแบบนี้ตอนพัฒนาเกมเอนจินในยุค 90s ก็คงดีมากจริง ๆ
  • ชอบบทความแนวนี้มาก ภายนอกดูเหมือนง่าย แต่ถ้าจะทำให้ออกมาดีจริง ๆ ต้องมี การเจาะลึกอย่างจริงจัง
    ข้อเขียนของ Lucas Pope ตอนพัฒนาระบบ dithering ของ Return of The Obra Dinn ก็แนะนำเช่นกัน
    บันทึกการพัฒนาของ Lucas Pope

  • สะดุดใจกับประโยคที่ว่า “สร้างภาพดาวเสาร์ด้วย ChatGPT”
    ทั้งที่ภาพถ่ายดาวเสาร์จริงมีอยู่เต็มไปหมดใน public domain เลยสงสัยว่าทำไมต้องสร้างภาพปลอมมาทำให้อินเทอร์เน็ตปนเปื้อนด้วย

    • ทำให้นึกถึง ข่าวประเด็น ‘ภาพดวงจันทร์ปลอม’ ของ Samsung ขึ้นมา หรือว่าดาวเคราะห์เองก็อาจไม่ใช่ของจริง?
    • ไม่เข้าใจว่าทำไมต้องให้มัน สร้างซ้ำ ภาพที่น่าจะมีอยู่ในชุดข้อมูลฝึกอยู่แล้วด้วย
    • “สร้างภาพดาวเสาร์ด้วย ChatGPT” เป็นแค่จุดเริ่มต้นเท่านั้น
      สักวันหนึ่งเราอาจไม่ต้องเขียนวิกิหรือเว็บไซต์หรือแม้แต่ฟอรัมด้วยตัวเองแล้วก็ได้
      ถ้าสามารถสร้าง “ภาพดาวเสาร์คอนทราสต์สูงขนาด X×Y” ได้ทันที นั่นคงเป็น การเปลี่ยนแปลงระดับเวทมนตร์
      เช่นเดียวกับที่เครื่องคิดเลขหรืออินเทอร์เน็ตไม่ได้ฆ่าความคิดสร้างสรรค์ มนุษย์จะเลือกใช้ เครื่องมือที่มีแรงเสียดทานน้อยที่สุด และยังคงมุ่งหน้าไปหาดวงดาวต่อไปเสมอ
  • ทุกครั้งที่ดูตัวอย่างจะคิดว่า “ก็ดีนะ แต่ยังปรับปรุงได้อีกนี่?” แล้วก็ทึ่งที่ผู้เขียนแก้ปัญหานั้นให้จริง ๆ
    เป็นบทความที่สวยงามมาก และทั้งบล็อกก็มี ความลึกในระดับนี้ จนคุ้มค่าที่จะติดตาม
    alexharri.com/blog

  • ตอนทำโปรเจกต์ ascii-side-of-the-moon เคยลังเลว่าจะลองเขียน ASCII renderer เองดีไหม
    สุดท้ายใช้ chafa แต่ก็คิดว่าไว้วันหนึ่งจะลองใหม่อีกครั้ง
    เลยสงสัยว่ามีแผนจะปล่อยสิ่งนี้เป็นไลบรารีไหม หรือสามารถอ้างอิงจาก โค้ดของเว็บไซต์ ได้หรือเปล่า

    • เครื่องมือ ASCII Moon สนุกมากจริง ๆ
      ตอนนี้ยังไม่มีแผนทำเป็นไลบรารี แต่ถ้าต้องการก็หยิบโค้ดจากเว็บไซต์ไปใช้ได้อย่างอิสระ
      ถ้าจะทำจริง ๆ ก็น่าจะต้องมี การแปลง WebGL 2 → WebGL 1 เพื่อให้รองรับได้กว้างขึ้น และต้องมีเครื่องมือสำหรับคำนวณ shape vector ของแต่ละฟอนต์ล่วงหน้าด้วย
  • สำหรับคำพูดที่ว่า “ไม่เคยเห็นตัวอย่างใน ASCII art ที่ใช้ shape มาก่อน” จริง ๆ แล้วมีตัวสร้างที่ใช้ shape อยู่
    เป็นโปรเจกต์ชื่อ ascii-silhouettify ซึ่งใช้อัลกอริทึมที่เลือกอักขระที่ใหญ่ที่สุดให้สอดคล้องกับเส้นขอบของพื้นที่สี

    • ตัวอย่างใน แกลเลอรีขาวดำ ดูยอดเยี่ยมมาก
    • แต่ดูเหมือนจะช้ากว่าประมาณ 150 เท่า ถ้าเพิ่มความละเอียดในการ sampling ก็น่าจะได้ความคมชัดใกล้เคียงกัน
  • Acerola เคยลองทำ ASCII rendering แบบอิง edge detection ในปี 2024
    วิธีคือซ้อนสัญลักษณ์ที่มีทิศทาง (| / - \) ทับบนพาสที่อิงความสว่าง
    ดูได้ในวิดีโอที่เกี่ยวข้อง

    • รู้สึกว่าในพื้นที่นี้ยังมี ช่องว่างด้านสไตล์ อีกมาก
      เช่น อาจลองใช้เส้นขอบหนาแบบงาน 2D ดั้งเดิม หรือแสดงคอนทราสต์แสงเงานุ่ม ๆ แบบ Chiaroscuro ก็ยังได้
  • ฟิลเตอร์ ASCII ส่วนใหญ่ไม่ได้คำนึงถึง รูปร่าง (shape) ของ glyph
    chafa จัดการ glyph แต่ละตัวเป็นบิตแมป 8×8 ซึ่งเป็นแนวทางที่น่าประทับใจ
    พอดู ซอร์สของ chafa กับ แกลเลอรี ก็จะรู้สึกได้ถึงความประณีตนั้น

    • ในแกลเลอรีของ chafa ดูเหมือนไม่มีตัวอย่างการเรนเดอร์ข้อความ ASCII ไม่แน่ใจว่ามีตัวอย่างแบบนั้นไหม
    • ตอนเรียนมหาวิทยาลัยก็เคยใช้วิธีแปลงบิตแมป 8×8 เป็นจำนวนเต็ม 64 บิตแล้วเทียบด้วย popcnt เหมือนกัน
      เลยสงสัยว่าแนวทางที่เน้นทิศทางจะถ่ายทอดรูปทรงที่ใหญ่กว่าได้ดีกว่าหรือไม่
    • ส่วนตัวชอบ glyph ของ IBM Code Page 437 มากที่สุด
      ดู oldschool PC fonts แล้วเหมือนหลุดเข้าไปในโพรงกระต่ายที่ไม่มีที่สิ้นสุดจริง ๆ
  • ตอนว่างกำลังทดลองทำ กราฟิกสีแบบอิงอักษรเบรลล์ อยู่
    ความละเอียดมีพอ แต่ความแม่นยำของการแสดงสีไม่พอ จึงต้องมี การปรับคอนทราสต์ (contrast fixup) หลังจาก sampling
    คิดว่าน่าจะลองเอาเทคนิค sampling ของผู้เขียนมาปรับใช้เพื่อเสริมคอนทราสต์ของสีได้
    ก่อนหน้านี้เคยพยายามเพิ่มคอนทราสต์ด้วย Sobel filter แต่ไม่สำเร็จเพราะมันไม่ตรงกับการจัดแนวของกริดตัวอักษร

  • เป็นแนวทางเชิงเทคนิคที่ยอดเยี่ยมและวิเคราะห์ได้ลึกมาก
    ตอนท้ายแอบหวังว่าจะได้เห็น Cognition cube array เวอร์ชันปรับปรุง แต่ก็ไม่มีเลยน่าเสียดาย
    ทำให้นึกถึงนักออกแบบคนหนึ่งบน YouTube ที่เคยทำ favicon ให้ดีขึ้นด้วย subpixel color contrast
    บทความที่เกี่ยวข้อง (Web Archive)

    • ฉันก็อยากเห็น เวอร์ชันเพิ่มคอนทราสต์ของโลโก้ Cognition เหมือนกัน
      ถึงอย่างนั้นตัวบทความเองก็ยอดเยี่ยม และตัวอย่างแบบโต้ตอบก็ประทับใจมาก