Faulty Barcode Detection
อันนี้เป็นโครงงานเล็ก ๆ จากวิชา Computer Vision หัวข้อคือ ทำไงก็ได้ให้คอมมันรู้ได้ว่าภาพบาร์โค้ดมันสกปรก มีภาพตัวอย่างมาให้ด้วย



ดูแล้วก็แบบ เอ่อ มันสกปรกตรงไหนเนี่ย แต่ก็นั่นล่ะ เจ้าของโจทย์จริง ๆ เป็นบริษัทที่พิมพ์พวกบรรจุภัณฑ์กระดาษ เลยต้องการวิธีตรวจคุณภาพการพิมพ์ที่มันอัตโนมัติ (จริง ๆ แล้วซอฟท์แวร์อ่านบาร์โค้ดสมัยนี้มันฉลาดมาก เบี้ยวก็อ่านได้ เบลอก็อ่านได้)
จริง ๆ แล้วโจทย์มีสามข้อ คือ (1) ทำภาพแบบที่มีเอฟเฝ็กท์ประหลาด ๆ เช่น แขนขายืดออก ตัวหมุนเป็นเกลียว (ไอเดียคือตัดเอาส่วนเล็ก ๆ ของภาพในแต่ละเฟรมตามเวลามาต่อ ๆ กัน) (2) ใช้ภาพถ่ายของวัตถุเดียวกันสองภาพในตำแหน่งที่ต่างกันมาหาระยะห่างระหว่างวัตถุกับกล้อง และข้อสุดท้ายก็บาร์โค้ดนี่ล่ะ
เลือกข้อบาร์โค้ดนี่เพราะว่าข้อแรกคนทำเยอะมาก (เพราะเห็นผลชัดเจน) ตัวเปรียบเทียบเยอะ (ฮา) ส่วนข้อที่สองนี่ก็มีสูตรคณิตศาสตร์อยู่แล้ว เลือกข้อสุดท้ายนี่แหละ ท่าจะมันส์
เอาเข้าจริงมันก็มันส์ไปหน่อย งานวิชาอื่นก็ดันมาส่งพร้อม ๆ กัน (บอกผมสิว่าคุณไม่ดองงาน) ไอเดียในการแก้ปัญหามันเลยแอบเผา แต่อย่างน้อยมันก็ทำงานได้ตามจุดประสงค์เท่าที่มีตัวอย่างน่ะนะ
ข้อความข้างล่างนี้ไปอาจจะน่าเบื่อไปหน่อย จริง ๆ ข้ามไปดูวิดีโอข้างล่างสุดได้เลย เอ๊ะ แต่ก็อยากให้อ่านแฮะ
ไอเดียคร่าว ๆ ก็คือใช้ความ "เส้นเยอะ" (ไม่ใช่เส้นใหญ่) ของบาร์โค้ด ตอนแรกก็จับภาพนั้นมาหาเส้นก่อน ด้วย Hough transform (แปลไทยว่า "การแปลงฮัฟ" เท่สลัด ๆ) จะได้เส้นเยอะ ๆ ออกมา ซึ่งเส้นส่วนมากที่ได้จะมาจากบาร์โค้ด จากนั้นก็ดูมุมของความชันของเส้นพวกนั้น จัดการแบ่งมุมที่พบออกเป็นกลุ่มย่อย ๆ ก็จะพบว่ามีช่วงของขนาดมุมหนึ่ง ๆ ที่มีจำนวนเยอะกว่าช่วงอื่น (เช่น ถ้าบาร์โค้ดมันเอียงอยู่ประมาณ 45 องศา เราก็จะพบเส้นที่มีมุม 45 องศาเยอะกว่าเส้นที่ตั้งตรง) เราก็ถือเอาว่าช่วงมุมนั้นล่ะ เป็นมุมของความเอียงของบาร์โค้ด แล้วก็หมุนภาพให้บาร์โค้ดมันตั้งตรงซะ
เมื่อบาร์โค้ดมันตรงแล้ว อะไร ๆ ก็ง่ายขึ้น ก็จัดการหาขอบแนวตั้งซะก่อน คือ หาเส้นที่ตั้งตรง (ความชันเข้าใกล้อินฟินิตี้) แล้วเลือกเส้นที่อยู่นอกสุดสองฝั่งมา (ซึ่งวิธีนี้มันใช้ไม่ได้กับทุกสถานการณ์ ถ้ามีเส้นตั้งตรงอื่นอยู่นอกบาร์โค้ดแล้วจะจบเห่ อาศัยมองโลกในแง่ดีว่าถ้าจะให้คอมมันดูบาร์โค้ดให้แล้ว คนก็คงไม่ถ่ายภาพที่มันเป็นมุมกว้างมากมาให้หรอกมั้ง ฮา)
ต่อมาขอบแนวนอนนี่ปัญหาเลย เพราะบาร์โค้ดมันไม่มีขอบแนวนอน จะหารูปแบบของเส้นที่มันไม่ค่อยปะติดปะต่อกันแบบนั้นก็คงจะยากไป เลยจัดการ "ขยาย" (Dilate) แต่ละแท่งในบาร์โค้ดนั้นตามแนวนอน มันก็จะมาเชื่อมกัน กลายเป็นกล่อง มีขอบแนวนอนแล้ว เย้ (จริง ๆ ก็ขยายออกทางข้างแม่งทั้งภาพนั่นแหละ เพียงแต่ขยายนิดเดียว ส่วนอื่นของภาพไม่มีผลกระทบมาก แต่ช่องว่างในบาร์โค้ดมันแคบ เลยเชื่อมกันได้)
เจอปัญหาอีก คือพอจะหาเส้นแนวนอนแล้วมัน (เป็นไปได้ที่จะ) เสือกเจอหลายเส้น นอกเหนือจากขอบของบาร์โค้ด ก็แก้ปัญหาเฉพาะหน้า (งานโคตรเผา ฮา) ด้วยการเอาเส้นแนวตั้งสองเส้น กับเส้นแนวนอนทั้งหลายนั่นมาใช้แทนเส้นกริด เสมือนตัดภาพออกเป็นสี่เหลี่ยมหลาย ๆ อัน แล้วดูว่าสี่เหลี่ยมไหนที่บรรจุเส้นมากที่สุด นั่นล่ะบาร์โค้ด
เมื่อตัดเอาบาร์โค้ดออกมาได้แล้ว จะหารอยเปื้อนได้ยังไง คิดอยู่พักใหญ่เลย จะหาขอบของรอยเปื้อน จุดมันก็เล็กเกินไป ปกติในการหาความแตกต่างของภาพสองภาพ วิธีเบื้องต้นสุด ๆ คือการเอาสองภาพนั้นมาลบกัน (ลองนึกตามว่ามีภาพ (1) จุดสามจุด กับภาพ (2) จุดเดียวตรงกลาง เอาภาพ (2) ลบออกจากภาพ (1) ก็น่าจะได้จุดข้าง ๆ ที่เหลือ) ทีนี้ ถ้าเรามีภาพบาร์โค้ดเปื้อน ๆ อยู่ จะเอาภาพบาร์โค้ดสะอาด ๆ ที่ไหนมาลบออกไปล่ะ จ้องไปจ้องมาพบว่า เฮ้ย เราตั้งบาร์โค้ดได้แล้ว ถ้าเรา "หด" (Erode) ภาพบาร์โค้ดเปื้อนนั้นตามแนวตั้งเนี่ย พวกจุดก็จะหายไป แต่เส้นยังอยู่ (เพราะเส้นแนวตั้งมันยาว หดไปบ้างแต่ไม่หายไป) แล้วขยายกลับคืนตามแนวตั้ง ก็จะได้ภาพบาร์โค้ดสะอาด ๆ มา เอาไปลบออกจากภาพเดิมที่เปื้อนอยู่ ก็จะได้รอยเปื้อน!
ที่เหลือก็แค่นับรอยเปื้อน ซึ่งตรงนี้ก็เจอปัญหาอีกนิดหน่อย เพราะจากการที่เราหมุนภาพในตอนแรก มันทำให้เส้นขอบของแต่ละแท่งมันไม่ได้เรียบตรงเดี๊ยะ พอมายืด ๆ หด ๆ ตามแนวตั้งมันก็ยิ่งเปลี่ยนแปลง เมื่อเอาไปเทียบความแตกต่างกับรูปต้นฉบับจะพบว่าเกิดความแตกต่าง (ที่ไม่ใช่รอยเปื้อนจริง ๆ) พอสมควร ทางแก้ก็คือ แปลงภาพทั้งสอง (ภาพดั้งเดิมกับภาพสะอาด) ให้เป็นภาพขาวดำจริง ๆ ซะก่อน (คือมีแต่ขาวกับดำเท่านั้น) เอามาลบกัน จะพบว่าถ้าภาพดั้งเดิมมันสะอาด ผลต่างที่ได้จะเป็นแค่เส้นแนวดิ่งเล็ก ๆ กว้างไม่เกินหนึ่งพิกเซล (จากการหมุน) อย่างนี้ก็เสร็จโจร เราก็นับแค่เส้นแนวนอนที่ยาวสองพิกเซลขึ้นไป แล้วก็ดูว่าถ้ามีไอ้เส้นพวกนี้มากเท่าไรจึงจะตัดสินว่าภาพมันเปื้อน
มันน่าสับสนสินะ ใครที่อ่านข้างบนมานี่แล้วเข้าใจทั้งหมดผมแม่งโคตรนับถือเลยอะ ผมแนบวิดีโอสาธิตมาด้วยข้างล่างนี้ มีให้เห็นแต่ละขั้นตอนด้วย
เท่านั้นไม่พอ มีรายงาน (pdf ประมาณ 7 เม็กฯ) กับโค้ดกาก ๆ (เขียนด้วย Python ใช้ไลบรารี่ OpenCV) ให้เอาไปหัวเราะเยาะด้วยเอ้า (อยากจะหาเวลาศึกษาการเขียนโค้ดแบบ Pythonic อยู่ครับ ไอ้แบบ tewsonic ที่เขียนนี่มันอนาถสิ้นดี)
แล้วก็ ผมเชื่อว่ามีวิธีที่ฉลาดกว่านี้อยู่มากมาย ใครเห็นใจก็บอกกันหน่อยนะจ๊ะ



เจ๊งมาก
เจ๊งมาก หลายอันเรายังคิดไม่ถึงเลย
แหล่มสุดๆ
เฮ้ย ยังไม่เจ๊ง
เฮ้ย ยังไม่เจ๊ง
เยี่ยมครับ อนาคตนักวิจัย
เยี่ยมครับ อนาคตนักวิจัย อิอิ
เอ้ย สระผิดตัวนึง 55555
เอ้ย สระผิดตัวนึง 55555
เจ๋งๆ เมพมากๆ
เจ๋งๆ เมพมากๆ
เป็นวิธีที่เจ๋งดีครับ ผมลองคิ
เป็นวิธีที่เจ๋งดีครับ
ผมลองคิดเล่นๆ อีกวิธี
แบ่ง barcode เป็นแถบบางๆ (เพราะตอนอ่านจริงๆ เครื่องอ่านก็อ่านแค่แถวเดียว)
แล้วใช้อัลกอริทึมสำหรับ "อ่าน barcode" มาลองไล่อ่าน
คำนวณว่า "zone ที่อ่านออก(ได้รหัสถูกต้อง) คิดเป็นกี่ % ของ barcode ทั้งหมด"
--> แต่แบบนี้มันก็ไม่ใช่โปรเจค computer vision สินะ
มั่วๆ ครับ
นี้เป็นข้อมูลที่น่าสนใจ
นี้เป็นข้อมูลที่น่าสนใจ บล็อกของคุณเป็นจริงที่เป็นประโยชน์สำหรับผู้ใช้มือใหม่ ฉันเป็นผู้ใช้มือใหม่ให้ข้อมูลที่มีอยู่ในหัวข้อนี้ใดจะน่าสนใจเพื่อฉัน
http://www.queentorrent.com
Post new comment