สร้างเครื่องมือช่วยทำความสะอาดภาพเพื่อเพิ่มความแม่นยำให้ OCR ด้วย Scala

7 นาที 15 views บันทึกเป็น PDF

อยากให้ OCR อ่านข้อความได้แม่นขึ้นไหม? มาดูวิธีสร้าง PrepOCR เครื่องมือปรับแต่งภาพก่อนส่งไปประมวลผล พร้อมเรียนรู้การทำระบบ Backend ด้วย Scala

OCR คืออะไรและทำไมภาพถึงสำคัญ

เวลาเราถ่ายรูปเอกสารแล้วอยากให้คอมพิวเตอร์อ่านข้อความออกมาเป็นไฟล์ที่เราแก้ไขได้ เราจะใช้เทคนิคที่เรียกว่า OCR (Optical Character Recognition หรือ การแปลงภาพตัวอักษรให้เป็นข้อความที่แก้ไขได้) ซึ่งเปรียบเสมือนดวงตาของโปรแกรมที่คอยจ้องมองภาพแล้วเดาว่าลายเส้นเหล่านั้นคือตัวอักษรตัวไหน

ลองนึกภาพว่าคุณกำลังพยายามอ่านหนังสือในที่มืดสนิทหรือในห้องที่มีควันฟุ้งกระจาย คุณย่อมอ่านไม่ออกแน่นอน OCR ก็เช่นกัน ถ้าภาพที่ส่งเข้าไปมีคุณภาพแย่ ต่อให้ใช้โปรแกรมที่ฉลาดแค่ไหน ผลลัพธ์ที่ได้ก็มักจะผิดพลาดหรืออ่านไม่ออกเลย

ปัญหาที่พบบ่อยคือภาพเอียง แสงน้อย หรือมีจุดรบกวนเต็มไปหมด สิ่งเหล่านี้คือตัวการที่ทำให้โปรแกรมทำงานพลาด นักพัฒนาซอฟต์แวร์ ส่วนใหญ่มักจะพยายามแก้ปัญหาด้วยการหาโมเดลใหม่ที่เก่งกว่าเดิม ทั้งที่จริงแล้ววิธีแก้ที่ง่ายและได้ผลดีที่สุดคือการทำความสะอาดภาพก่อนส่งไปให้โปรแกรมอ่าน

รู้จักกับ PrepOCR ตัวช่วยทำความสะอาดภาพ

ผมสร้าง PrepOCR ขึ้นมาเพื่อเป็นเครื่องมือเล็กๆ ที่ช่วยจัดการภาพก่อนส่งเข้ากระบวนการอ่านข้อความ หน้าที่หลักของมันคือการปรับแต่งภาพให้ชัดเจนที่สุด เพื่อให้โปรแกรมอ่านตัวอักษรทำงานได้แม่นยำขึ้นโดยไม่ต้องพึ่งพาระบบที่ซับซ้อน

มันถูกออกแบบมาให้เน้นทำสิ่งที่จำเป็นจริงๆ เช่น การหมุนภาพให้ตรง การเพิ่มความคมชัด และการเปลี่ยนภาพให้เป็นขาวดำสนิท ซึ่งขั้นตอนสุดท้ายนี้ถือเป็นกุญแจสำคัญที่ทำให้ OCR ทำงานได้แม่นยำขึ้นแบบก้าวกระโดดสำหรับเอกสารที่เป็นกระดาษ

เครื่องมือนี้เหมาะสำหรับคนที่ต้องจัดการกับเอกสารจำนวนมาก หรือคนที่กำลังสร้างระบบอ่านฟอร์มต่างๆ คุณสามารถอัปโหลดไฟล์ภาพเข้าไป เลือกการปรับแต่งที่ต้องการ แล้วระบบจะส่งไฟล์ที่ถูกปรับปรุงคุณภาพแล้วกลับมาให้ในรูปแบบไฟล์บีบอัด (Zip)

ขั้นตอนการทำงานของระบบหลังบ้าน

ในส่วนของ Backend (ระบบหลังบ้านที่ทำงานบนเซิร์ฟเวอร์) ผมใช้ภาษา Scala ร่วมกับเฟรมเวิร์ก http4s ซึ่งเป็นเครื่องมือที่จัดการการรับส่งข้อมูลได้รวดเร็ว โดยกระบวนการเริ่มต้นจากการรับไฟล์ผ่านคำสั่ง Multipart Request (การส่งข้อมูลหลายส่วนในคราวเดียว)

เมื่อได้ไฟล์มา ระบบจะตรวจสอบความถูกต้องทันที ไม่ใช่แค่ดูที่นามสกุลไฟล์ แต่เราเช็คไปถึง Magic Bytes (เลขรหัสเฉพาะที่บอกประเภทไฟล์จริงๆ) เพื่อให้มั่นใจว่าเป็นไฟล์รูปภาพที่ถูกต้องจริงๆ หลังจากนั้นจึงเข้าสู่ขั้นตอนการประมวลผลตามที่ผู้ใช้เลือกไว้

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

// ตัวอย่างการประมวลผลภาพแบบขนานใน Scala
val images = List(img1, img2, img3, img4)
// ใช้ parTraverseN เพื่อรันคำสั่งหลายตัวพร้อมกัน
images.parTraverseN(4)(processImage) 

บรรทัดแรกคือการสร้างรายการรูปภาพที่ต้องการประมวลผล ส่วนบรรทัดที่สองใช้ฟังก์ชัน parTraverseN เพื่อบอกให้ระบบแบ่งงานออกเป็น 4 ส่วนทำงานพร้อมกันในเวลาเดียวกัน ผลลัพธ์ที่ได้คือเวลาในการประมวลผลลดลงจาก 7 วินาที เหลือเพียง 2 วินาทีบนเครื่องที่มี 14 คอร์

บทเรียนสำคัญเรื่องทรัพยากรเซิร์ฟเวอร์

ตอนที่ผมเอาไปรันบนโฮสต์ฟรี ผมเจอปัญหาที่น่าสนใจคือความเร็วไม่ได้เร็วขึ้นตามที่คาดหวังไว้ เพราะเซิร์ฟเวอร์จำกัดการใช้งาน CPU ไว้ค่อนข้างเข้มงวด ทำให้คำว่า "ทำงานพร้อมกัน" กลายเป็นแค่การสลับคิวงานทำงานไปมาอย่างรวดเร็วเท่านั้น

บทเรียนราคาแพงที่ผมได้รับคือคำสั่ง Runtime.getRuntime.availableProcessors() (คำสั่งเช็คจำนวนหน่วยประมวลผลที่มี) มักจะหลอกเราถ้าเราใช้งานในสภาพแวดล้อมที่แชร์ทรัพยากรร่วมกับคนอื่น ระบบจะบอกว่ามีคอร์เยอะ แต่ในความเป็นจริงเราถูกจำกัดการใช้งานไว้ไม่ให้เกินขีดจำกัดที่กำหนด

สำหรับมือใหม่ที่กำลังทำโปรเจกต์ อย่าเพิ่งตกใจถ้าโค้ดที่เขียนว่าเร็วบนเครื่องตัวเอง แต่พอเอาขึ้น Deploy (การเอาโค้ดขึ้นเซิร์ฟเวอร์จริง) แล้วช้าลง ให้จำไว้ว่าสภาพแวดล้อมที่ต่างกันส่งผลกระทบต่อประสิทธิภาพการทำงานได้มหาศาลเสมอ

แนวทางการพัฒนาเพื่อมือใหม่

การสร้าง PrepOCR ครั้งนี้เป็นเพียง MVP (สินค้าที่มีฟีเจอร์น้อยที่สุดพอที่จะใช้งานได้จริง) ผมสร้างขึ้นมาเพราะผมต้องการใช้เองจริงๆ ไม่ใช่เพราะมีงานวิจัยรองรับความต้องการของตลาด การเริ่มทำโปรเจกต์จากปัญหาที่เราเจอเองเป็นวิธีฝึกทักษะที่ดีที่สุด

ถ้าคุณกำลังฝึกเขียนโค้ด ผมแนะนำให้ลองสร้างเครื่องมือเล็กๆ ที่แก้ปัญหาในชีวิตประจำวันของคุณดู ไม่ว่าจะเป็นการย่อขนาดไฟล์ การเปลี่ยนชื่อไฟล์อัตโนมัติ หรือการดึงข้อมูลจากหน้าเว็บ การทำโปรเจกต์เล็กๆ แบบนี้จะทำให้คุณเข้าใจพื้นฐานของ HTTP (โปรโตคอลหลักในการรับส่งข้อมูลบนเว็บ) และการจัดการไฟล์ได้ดีกว่าการอ่านตำรา

อย่ากลัวที่จะเริ่มทำอะไรที่ดูเหมือนจะมีคนทำไปแล้ว เพราะหัวใจสำคัญไม่ใช่การสร้างสิ่งใหม่ที่ไม่เคยมีมาก่อน แต่คือการได้ลงมือเขียนโค้ดจริงๆ ได้เจอบั๊ก ได้ลองแก้ปัญหา และได้เรียนรู้ว่าเครื่องมือแต่ละอย่างทำงานร่วมกันอย่างไรในโลกความเป็นจริง

สรุป: การนำไปใช้จริง

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

ตัวอย่างการนำไปใช้จริง: สมมติคุณทำแอปพลิเคชันเก็บใบเสร็จรับเงิน คุณสามารถใช้ PrepOCR เป็นขั้นตอนแรก เพื่อปรับภาพใบเสร็จให้ตรงและคมชัด ก่อนส่งภาพนั้นเข้าโมเดลอ่านข้อความ Google Vision หรือ Tesseract จะทำให้แอปของคุณอ่านยอดเงินได้แม่นยำขึ้นหลายเท่าตัว

จำไว้ว่าโปรแกรมเมอร์ที่เก่ง ไม่ได้ดูที่ว่าเขียนโค้ดซับซ้อนแค่ไหน แต่ดูที่ว่าแก้ปัญหาให้ผู้ใช้ได้ตรงจุดและเรียบง่ายเพียงใด ลองเอาแนวคิดการเตรียมข้อมูลก่อนนำไปประมวลผลไปปรับใช้กับทุกงานที่คุณทำ แล้วคุณจะเห็นความเปลี่ยนแปลงของผลลัพธ์อย่างชัดเจน


ที่มา: I built a free image preprocessor to get better OCR results (PrepOCR) — DEV Community

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เรียนรู้วิธีเขียนแอป Flutter เชื่อมต่อ Meta Smart Glasses ให้ทำงานเร็ว ไม่กระตุก ด้วยการวางสถาปัตยกรรมโค้ดและการจัดการข้อมูลแบบมือโปรที่มือใหม่ทำตามได้จริง

ที่มา: DEV Community

5 hours ago 10 นาที
5 views
เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

อยากทำระบบ Real-Time แต่ไม่รู้จะเลือกใช้ Polling, SSE หรือ WebSocket ดี? มาดูวิธีเลือกใช้ให้เหมาะกับงาน เพื่อให้แอปของคุณทำงานลื่นไหลและประหยัดทรัพยากรเซิร์ฟเวอร์

ที่มา: DEV Community

8 hours ago 10 นาที
4 views