เทคนิคแก้ไขความบิดเบี้ยวของหน้าเอกสาร
(mzucker.github.io)- โมเดล ท่าทาง 3D และความโค้ง เพื่อแปลงภาพถ่ายเอกสารที่โค้งงอให้เป็นภาพแบน และแก้เป็นปัญหา optimization ที่จัดแนวจุดอ้างอิงของข้อความ
- ดำเนินตามแนวทางแบบ Leptonica และ CTM คือแบ่งข้อความเป็นรายบรรทัด แล้วหา coordinate transform ที่ทำให้บรรทัดดูขนานกันและใกล้เคียงแนวนอน
- โมเดลประกอบด้วยเวกเตอร์การหมุน
r, เวกเตอร์การเลื่อนt, ความชันความโค้งα,β, และ offsetx,yของ text span โดยทำให้ reprojection error ต่ำที่สุด - Pipeline ประกอบด้วยการครอบขอบหน้าเอกสาร, ตรวจจับ contour ของข้อความ, ประกอบ span, สุ่มจุดอ้างอิง, สร้างค่าเริ่มต้น, Powell optimization, และ remapping ด้วย
cv2.remap - ในการรันตัวอย่าง มีพารามิเตอร์ 104~600 ตัว เวลารันรวม 5.3~24.8 วินาที โดยเวลาส่วนใหญ่ใช้กับ optimization จึงยังมีโอกาสเพิ่มความเร็วด้วย solver หรือภาษา compiled
แก้หน้าเอกสารที่โค้งงอในรูปแบบปัญหา optimization
- สคริปต์เดิมสำหรับแปลงภาพถ่ายลายมือเป็น PDF ทำได้เพียงใช้
adaptiveThresholdและรวมหลายภาพเป็น PDF แต่สำหรับภาพถ่ายเอกสารที่เก็บถาวร ข้อความจะบิดงอมากเพราะ การม้วนงอของหน้าเอกสาร - เป้าหมายคือสร้างโปรแกรมที่แปลงภาพถ่ายหน้าเอกสารที่โค้งงอให้เป็น ภาพเอกสารแบบแบน โดยอัตโนมัติ
- โค้ดเผยแพร่ไว้ที่ page_dewarp บน GitHub
แนวทางพื้นฐานจาก Leptonica และ CTM
- การแก้ความบิดเบี้ยวของภาพเอกสารเป็นปัญหาที่รู้จักกันอยู่แล้ว และมีการ implement ไว้ใน Leptonica ไลบรารีประมวลผลภาพโอเพนซอร์สของ Dan Bloomberg ด้วย
- เอกสารอ้างอิงมี สรุป ผลการแข่งขัน dewarping และ paper เกี่ยวกับวิธีที่ชนะอย่าง Coordinate Transform Model หรือ CTM
- Leptonica และ CTM แบ่งปัญหาออกเป็นสองขั้นตอนร่วมกัน
- แยกข้อความเป็น รายบรรทัด
- หา การบิดเบี้ยวหรือ coordinate transform ที่ทำให้บรรทัดขนานกันและเป็นแนวนอน
- implementation นี้แทนรูปร่างภายนอกของหน้าด้วยพารามิเตอร์หลายตัว
r,t: เวกเตอร์การหมุนและเวกเตอร์การเลื่อนที่แสดงทิศทางและตำแหน่ง 3D ของหน้าα,β: ความชันสองค่าที่กำหนดความโค้งของพื้นผิวหน้าy₁ ... yₙ: offset แนวตั้งของ span แนวนอนnช่วงบนหน้าxᵢ: offset แนวนอนสำหรับจุดอ้างอิงหลายจุดในแต่ละ span
พื้นผิวโค้ง 3D และ reprojection error
- รูปร่าง 3D ของหน้าเอกสารถูกแทนเป็นพื้นผิวที่สร้างจากการกวาดเส้นโค้งไปตามแกน
yภายในระบบพิกัดเฉพาะที่ - พิกัดแนวนอน
xของหน้าถูกแมปเป็นการกระจัดตามทิศzของพื้นผิว และหน้าตัดแนวนอนถูกโมเดลด้วย cubic spline- จุดปลายทั้งสองของ spline ถูกตรึงไว้ที่ 0
- รูปร่างของ spline ถูกกำหนดด้วยความชันปลาย
α,βเท่านั้น
- เมื่อกำหนดพารามิเตอร์ท่าทางและความโค้งแล้ว พิกัด
(x, y)แต่ละจุดของหน้าจะถูก project ไปยังตำแหน่งหนึ่งบนระนาบภาพ - ค้นหา keypoint ของ text span แนวนอนจากภาพต้นฉบับ และหาพารามิเตอร์ที่ลด reprojection error ของ keypoint ให้ต่ำที่สุด โดยเริ่มจากค่าประมาณเริ่มต้น
- ก่อน optimization จะสมมติว่าไม่มีความโค้ง ทำให้จุด reprojection อยู่บนเส้นตรง แต่หลัง optimization จุด projection ของโมเดลแทบจะทับกับ keypoint ที่ตรวจพบจริง
Pipeline ประมวลผลภาพ
-
ครอบขอบหน้าเอกสาร
- ไม่ได้ใช้ภาพทั้งหมด แต่ครอบเฉพาะบริเวณตรงกลางด้วย margin คงที่เพื่อหลีกเลี่ยงพื้นที่ไม่จำเป็นบริเวณขอบ
- ไม่ได้ใช้การตรวจจับขอบหน้าเอกสารแบบอัจฉริยะ
-
ตรวจจับ contour ของข้อความ
- ใช้ adaptive threshold ในขั้นแรก
- ทำ morphological dilation) ด้วยกล่องแนวนอน เพื่อเชื่อมพิกเซล mask ที่อยู่ติดกันในแนวนอน
- ทำ erosion) ด้วยกล่องแนวตั้ง เพื่อลบ noise สูงหนึ่งพิกเซล
- หลังทำ connected component analysis จะกรอง blob ที่สูงเกินไปหรือหนาเกินไปออก
- contour ของข้อความที่เหลือจะถูกประมาณเป็น line segment ที่ fit ดีที่สุดด้วย PCA
-
เสริมการตรวจจับเส้นแนวนอน
- input บางส่วนเป็นรูปแบบตารางที่มีข้อความแนวตั้งจำนวนมาก ดังนั้นหากตรวจพบข้อความแนวนอนไม่เพียงพอ ก็จะลองตรวจจับเส้นแนวนอนหรือ rule ด้วย
การสร้าง text span และการสุ่มจุดอ้างอิง
- เพื่อจัดกลุ่ม contour ที่ตรวจพบให้อยู่ใน span แนวนอนเดียวกัน จะสร้าง edge ผู้สมัครสำหรับ contour ทุกคู่และคำนวณต้นทุน
- หาก contour สองอันซ้อนทับกันมากในทิศตามความยาว อยู่ไกลเกินไป หรือมีมุมต่างกันมาก จะตั้งต้นทุนเป็น อนันต์
- ต้นทุนของ edge ที่ใช้ได้คำนวณจากผลรวมเชิงเส้นของระยะทางและการเปลี่ยนแปลงของมุม
- หลังเรียง edge ตามต้นทุน จะเชื่อมต่อเฉพาะเมื่อ contour ทั้งสองฝั่งยังไม่ได้เชื่อมต่อ โดยใช้วิธีแบบ greedy ที่ใช้เวลาเชิงกำลังสอง
- เนื่องจากเวลารันส่วนใหญ่ใช้กับ optimization ความซับซ้อนเวลาเชิงกำลังสองของขั้นตอนนี้จึงไม่ใช่ปัญหาใหญ่
- หลังสร้าง span แล้ว จะลบ span ที่เล็กเกินไปจนไม่ช่วยในการกำหนดโมเดลออก
- เนื่องจากโมเดลพารามิเตอร์ต้องการจุดอ้างอิงแบบไม่ต่อเนื่อง จึงเลือก keypoint หนึ่งจุดต่อ contour ข้อความประมาณทุก 20 พิกเซล
การสร้างค่าเริ่มต้นและ Powell optimization
- ประมาณทิศทางเฉลี่ยของ span ทั้งหมดด้วย PCA
- ใช้องค์ประกอบหลักจากผล PCA เพื่อตั้งค่าพิกัด
x,yเริ่มต้น และท่าทางของหน้าแบบแบนที่ไม่มีความโค้งในเชิงวิเคราะห์ - การ reprojection จะสุ่มตัวอย่าง cubic spline เพื่อรับ offset
zของจุดวัตถุ แล้ว project ไปยังระนาบภาพด้วยฟังก์ชันของ OpenCVcv2.solvePnPcv2.projectPoints
- ใช้
scipy.optimize.minimizeและ solver'Powell'สำหรับลด reprojection error- ใช้เป็นเครื่องมือ optimization แบบ black-box ที่ไม่ใช้อนุพันธ์
- ตัวปัญหาเองจัดเป็น non-linear least squares
- ไม่ได้ทดลอง solver อื่นหรือ solver non-linear least squares เฉพาะทางมากนัก
- เวลารันโปรแกรมเกือบ 100% ใช้ในขั้นตอน optimization นี้
Remapping และการสร้างภาพผลลัพธ์
- เมื่อ optimization เสร็จแล้ว จะแยกเฉพาะ
r,t,α,βออกมาเพื่อสร้าง coordinate transform - การ dewarp จริงทำได้โดย project dense mesh ของจุด 3D บนหน้าเอกสารด้วย
cv2.projectPointsแล้วส่งพิกัดภาพนั้นให้cv2.remap - ผลลัพธ์สุดท้ายถูกบันทึกเป็น PNG แบบ bi-level โดยใช้
cv2.adaptiveThresholdและ Pillow
ผลลัพธ์ตัวอย่างและเวลารัน
- repository บน GitHub มี example images หลายภาพ
- สถิติเมื่อรันบน MacBook Pro ปี 2012 เครื่องเดียวมีดังนี้
| อินพุต | Spans | Keypoints | Parameters | เวลา optimization | เวลารวม |
|---|---|---|---|---|---|
boston_cooking_a.jpg |
38 | 554 | 600 | 23.3 วินาที | 24.8 วินาที |
boston_cooking_b.jpg |
38 | 475 | 521 | 18.0 วินาที | 18.8 วินาที |
linguistics_thesis_a.jpg |
20 | 161 | 189 | 5.1 วินาที | 6.1 วินาที |
linguistics_thesis_b.jpg |
7 | 89 | 104 | 4.2 วินาที | 5.3 วินาที |
- แม้แต่โมเดลที่เล็กที่สุดก็มีพารามิเตอร์ 104 ตัว และโมเดลที่ใหญ่ที่สุดมี 600 ตัว จึงไม่ใช่ปัญหา optimization ขนาดเล็ก
- ความเร็วของ optimization อาจปรับปรุงได้ด้วยการลองวิธีอื่นหรือใช้ ภาษา compiled
ข้อจำกัดที่เหลืออยู่
- แนวทางทั้งหมดคืออ่านความรู้พื้นฐานเล็กน้อย แล้ว formalize ปัญหาทั้งหมดให้เป็น output ของกระบวนการ optimization
- วิธีนี้ทำให้นึกถึง deformable part models และ active appearance models แต่ไม่ได้ซับซ้อนเท่าทั้งสองอย่าง
- Leptonica และ CTM พยายามโมเดลและแก้ไข ความบิดเบี้ยวแนวนอน ด้วย ไม่ใช่เพียงความบิดเบี้ยวแนวตั้ง
- implementation นี้ไม่ได้จัดการถึงการแก้ความบิดเบี้ยวแนวนอน
- เนื่องจาก cubic spline ไม่ได้เป็นการ parameterize แบบ arc-length ข้อความจึงถูกบีบอัดเล็กน้อยในบริเวณที่ความชันของ spline สูง
- เนื่องจากโปรเจกต์นี้ส่วนใหญ่เป็น proof-of-concept จึงไม่ได้พัฒนาปัญหานี้ต่อ
- โค้ดสุดท้ายเผยแพร่ไว้ที่ GitHub repository และยังมีการเสริมคอมเมนต์อย่างละเอียดไม่เพียงพอ
1 ความคิดเห็น
ความคิดเห็นใน Hacker News
ควรระวังการใช้ การทำ threshold แบบแรงมาก กับผลลัพธ์เหมือนที่ผู้เขียนทำ
กับหน้าข้อความทั่วไปมันจับได้ค่อนข้างดี แต่ผมเคยเห็นหลายหน้าใน Google Books ที่ภาพประกอบหรือเชิงอรรถเล็ก ๆ พังจนอ่านไม่ได้เลย
ถ้าสแกนจาก Google Books เป็นแหล่งข้อมูลเดียว ก็แทบไปต่อไม่ได้เลย
พอหาเกณฑ์อ้างอิงได้แล้ว ก็น่าจะเอาพารามิเตอร์นั้นไปใช้กับภาพต้นฉบับได้
นี่ปี 2024 แล้ว แต่ก็น่าหงุดหงิดที่แอปสแกนเอกสารยังไม่ใส่ฟีเจอร์แบบนี้มาเป็นมาตรฐานสักที
ดูเหมือนว่าหัวใจที่ทำให้วิธีนี้ใช้ได้ผลคือการมี โมเดลการแปรรูปหน้ากระดาษมิติไม่สูง สำหรับใช้ปรับให้เหมาะที่สุด
นี่เป็นปัญหาที่เหมาะกับขนาด YC มาก อาจใช้เวลาไม่กี่สัปดาห์ก็ออกสู่ตลาดได้ และต้นทุนเปิดตัวก็น่าจะระดับไม่กี่แสนดอลลาร์
แอปมือถือของ Apple ต้องปรับด้วยมือมากเกินไป ส่วน Office Lens / Microsoft Lens ของ Microsoft ก็มีคนวิจารณ์ทำนองว่า “ขอบมันสุดท้ายก็เพี้ยนหนักและดูแย่มาก”
เพราะงั้นจึงน่าจะมีตลาดสำหรับสินค้าที่ใช้งานได้ดีจริง และก็อาจออกทางด้วยการขายให้ผู้เข้าซื้อกิจการที่พบได้ทั่วไป
พวกเขาคงมองว่ามันซับซ้อนและเป็นคณิตศาสตร์เกินไป แล้วตัดสินใจว่าเอาทรัพยากรไปทำโมเดลที่ส่องพฤติกรรมโซเชียลมีเดียของผู้ใช้เพื่อจับจังหวะแจ้งเตือนให้แม่นขึ้นจะช่วยตัวชี้วัดผู้ใช้ได้ดีกว่า
เป็นการตัดสินใจแบบยึดข้อมูลอย่างเข้มงวดของผู้มีอำนาจตัดสินใจ ระหว่างที่พยายามลด churn
หลังจาก John Warnock ลงจากตำแหน่ง CEO ของ Adobe เขาก็เข้าไปมีส่วนร่วมกับบริษัทอนุรักษ์หนังสือประวัติศาสตร์หายากชื่อ Octavo มากขึ้น
หนึ่งในโจทย์ที่พวกเขาเจอคือการคลี่ความโค้งของหน้าสแกนที่ไม่สามารถกดให้แผ่ออกได้
https://en.m.wikipedia.org/wiki/Rare_Book_Room
บทความยอดเยี่ยมมาก
ในบริษัทอาจเอาไปใช้อ้างอิงเป็นตัวอย่างของการบันทึกเอกสารสำหรับโปรเจกต์เทคนิคและการตัดสินใจต่าง ๆ ได้อย่างมีประสิทธิภาพ
ตอนเรียนมหาวิทยาลัยผมเคยพยายามทำแอปสแกนโน้ตที่แยกด้วยสี แล้วไปเจอปัญหาอีกแบบ
สีเพี้ยนจากบนลงล่างของหน้า ทำให้แยก ปากกาสีน้ำเงิน กับ ปากกาสีเขียว ได้ไม่เสถียร
ไว้สักวันคงต้องกลับไปดูใหม่
แบบนี้จะลบความเปลี่ยนแปลงของสี/ความสว่างความถี่ต่ำออกไปได้แทบหมด
มักใช้เพื่อลบเงาเวลาเอากระดาษไปถ่ายรูป และก็น่าจะใช้กับการไล่ระดับสีได้เหมือนกัน
ดูดีพอสมควรเลย
เพียงแต่ โมเดลการแปรรูป ดูจะเป็นแบบครอบคลุมทั้งภาพมากเกินไปหน่อย
ความบิดเบี้ยวที่ซับซ้อนกว่าบางส่วนของกระดาษจึงไม่ถูกโมเดลจับไว้ และยังเห็นเป็นความบิดเบี้ยวตกค้างในผลลัพธ์สุดท้าย
ระหว่างติดตั้งเจอข้อผิดพลาด:
ERROR: Could not find a version that satisfies the requirement cv2>=3.0 (from versions: none)ERROR: No matching distribution found for cv2>=3.0ผมเปิด GitHub issue ไว้แล้ว
เจ๋งมาก
อยากได้ แอปสแกนเอกสาร ดี ๆ ที่ใช้บนมือถือได้ แอปที่ทำทั้งการแก้ความบิดเบี้ยว การทำ threshold และการสร้าง PDF ได้ดี
ตอนนี้เหมือนถูกบังคับให้ใช้ Adobe Scan เพราะผลลัพธ์ยังดูดีที่สุดเท่าที่มี แต่ถึงอย่างนั้นการแก้ความบิดเบี้ยวก็ยังค่อนข้างแย่อยู่ดี
อ่านแล้วน่าสนใจมากจริง ๆ
เหมือนเป็นบทความจากปี 2016 ที่ผมพลาดไป แต่ชอบที่มันถ่ายทอดภาพรวมแบบ “มีปัญหานี้อยู่ แล้วก็ใช้เทคนิคฉลาด ๆ จนได้วิธีแก้ที่ใช้งานได้ดี” ออกมาได้ชัดเจน
ส่วนตัวคงไม่มีโอกาสต้องใช้สิ่งนี้ แต่เป็นตัวอย่างที่ดีมากของการรับมือปัญหาอย่างเหมาะสม และยอมประนีประนอมกับผลลัพธ์รวมถึงความคาดหวังในขอบเขตที่รับได้
เขียนก็ดี อธิบายก็ดี
ถ้าไม่จำเป็นต้องแสดงหนังสือในเชิงภาพ และต้องการแค่ทำ OCR ก็น่าจะข้ามขั้นตอนนี้ไปได้
Google แก้ปัญหานี้ได้ตั้งแต่กว่าสิบปีก่อนแล้ว: https://hardware.slashdot.org/story/09/05/15/1834246/how-goo...
ถ้าต้นฉบับมีคุณค่ามากจริง ๆ ก็สามารถแก้ความบิดเบี้ยวแบบไม่สัมผัสด้วยเอกซเรย์คอมพิวเตอร์ได้: https://scrollprize.org/tutorial1
ฝั่ง Google ใช้ฮาร์ดแวร์ และเรื่องเอกซเรย์คอมพิวเตอร์ก็มีกลิ่นแบบ ChatGPT มาก
ถึงอย่างนั้น วิธีในบทความนี้ก็ยังดูดีและเรียบง่ายเมื่อมองตามบริบทของปี 2016