ตอนก่อนหน้า: บันทึก training data science EP 11: NLP & Spacy – สอนภาษารัก

ความสามารถอีกแขนงนึงของ Data Science คือการวิเคราะห์รูปภาพนะฮะ และแน่นอน Python มี Library ให้เราใช้งานเกี่ยวกับการประมวลผลภาพฮะ


ก่อนอื่นต้องเข้าใจก่อนว่า รูปภาพเนี่ยมันถูกประมวลผลในคอมพิวเตอร์เป็นตัวเลข รูปภาพสีโดยทั่วไปก็เป็น 24 บิตมาจาก 3 สี (RGB = Red, Green ,Blue) ซึ่งเป็นระบบสีแบบนึง คูณกับจำนวน 8 บิตต่อ 1 pixel ในรูปขาวดำฮะ ดังนั้นในหนึ่งจุด pixel เล็กๆ เนี่ย ข้อมูลรูปภาพที่เป็นสีนั้นจึงมีขนาดเท่ากับ 24 บิตหรือ 3 ไบท์ ( 1 ไบท์เท่ากับ 8 บิต) นั่นเอง

ทีนี้ในสเกลสีของระบบ RGB ก็จะแบ่งย่อยๆ เป็น 256 ระดับ นับตั้งแต่ 0 จนถึง 255 ตัวอย่างเช่น

Ref: http://dawnsbrain.com/the-rgb-color-wheel/

ถ้าเราเน้นสีแดงจนเด่นไปเลยค่าเดียว สีที่ได้ก็จะเป็นสีแดงแป๊ด (255, 0, 0) แต่ถ้าเราเติมสีเขียวไป เราจะได้สีผสม นั่นก็คือสีเหลืองฮะ (255, 255, 0) แต่ถ้าเราลดค่าลง เราจะได้สีที่มืดลง จนถึงสีดำที่มีค่า (0, 0, 0) กลับกัน สีขาวก็มีค่า (255, 255, 255) นั่นเองฮะ

skimage

คือ Library ตัวที่ว่านั่นแหละฮะ มันสามารถคำนวณรูปภาพมาได้ เพื่อประมวลผลในงานอื่นๆ เราติดตั้งโดยดูจากลิงก์นี้ได้เลยฮะ https://scikit-image.org/docs/stable/install.html

และแน่นอน เราก็ต้อง import skimage กันก่อน และเราก็มี matplotlib.pyplot เพื่อแสดงผลภาพได้จาก Jupyter notebook โดยตรงฮะ

เปิดรูปที่มี

ใช้คำสั่งนี้เพื่อเปิดไฟล์รูปฮะ

lynx = skimage.io.imread(img)
plt.imshow(lynx)

ตัวแปร lynx เนี่ยจะเก็บข้อมูลเป็น array of integers ตามค่าสีที่ได้เล่าไปข้างบนแล้วนะฮะ ด้วยความเป็น array นี่เอง เราก็ใช้คำสั่ง .shape เพื่อดูขนาดไฟล์ได้ด้วยแหละ ตามรูปเลย ไฟล์นี้มีความสูง (หรือก็คือจำนวนแถว) เป็น 423 pixel ความยาว (จำนวนคอลัมน์) เท่ากับ 640 pixel ส่วนเลข 3 นั่นคือแม่สีทั้งสามฮะ

และเมื่อมันเป็นตัวเลข เราก็เอาตัวเลขอะไรไปแปะเพื่อเปลี่ยนสีมันได้ ตามรูปข้างล่างฮะ

for i in range(30, 60):
    for j in range(60, 90):
        lynx[i,j] = [60, 60, 60]
plt.imshow(lynx)

คุมโทนสีให้เป็นขาวดำ

ใช้คำสั่งนี้เพื่อเปลี่ยนรูปสีให้เป็นขาวดำคุมโทนได้ง่ายๆ เลยฮะ

import skimage.color
plt.imshow(skimage.color.rgb2gray(lynx), cmap='gray')

ย่อขยายได้ตามใจ

คำสั่ง skimage.transform.resize() ทำให้รูปที่ออกมามีขนาดตามที่เราต้องการ แบบยืดหดขยายอะไรแบบนั้นฮะ โดยสังเกตว่า เราใช้ .shape[0] * 2 เพื่อให้ความสูงเพิ่มขึ้นสองเท่า และ .shape[1] * 1.5เพื่อให้ความยาวเพิ่มขึ้นอีกครึ่งนึงฮะ

import skimage.transform
plt.imshow(
    skimage.transform.resize(lynx, (lynx.shape[0] * 2, lynx.shape[1] * 1.5))
)

สร้างรูปทรงเรขาคณิต

เมื่อเรา import skimage.morphology เราจะมีฟังก์ชันสร้างรูปเรขาคณิตฮะ ดังตัวอย่างข้างล่างนี่เลย

star

diamond

rectangle

disk

เพิ่มฟิลเตอร์เบลอๆ

เราจะใช้ skimage.filter เพื่อเพิ่มรูปเรขาคณิตไปแปะบนรูปนะฮะ ผลคือรูปจะดูเบลอๆ ตามตัวอย่างข้างล่างนี้เลยฮะ

skimage.filter.median() + disk(5)

skimage.filter.median() + disk(10)

skimage.filter.median() + diamond(10)

skimage.filter.threshold_local()

และมันมีฟังก์ชัน .try_all_threshold() เพื่อดูผลของฟิลเตอร์หลายๆ แบบฮะ

skimage.filters.try_all_threshold(skimage.color.rgb2gray(lynx))

เทียบความแตกต่าง

สมมติเรามีรูปอยู่สามรูปดังนี้ฮะ

“latest”

“latest_2nd”

“first”

เราสามารถวัดความแตกต่างระหว่างสองรูปได้แบบนี้ฮะ

import skimage.metrics
skimage.metrics.mean_squared_error(a, b)

.mean_squared_error() ใช้สำหรับวัดค่า Mean-Squared Error (MSE) โดยพิจารณาที่ข้อมูล pixel ฮะ ยิ่งมีค่ามาก แปลว่าสองรูปนี้แตกต่างกันมากฮะ

import skimage.metrics
skimage.metrics.structural_similarity(a, b, multichannel=True)

.structural_similarity() คำนวณค่า Structural Similarity Index Measure (SSIM) ซึ่งคำนวณไปถึงค่า noise และ brightness ด้วยฮะ ยิ่งมีค่ามาก แปลว่าสองรูปนี้คล้ายกันมากฮะ

เราจะกำหนดรูปสามรูปไว้ดังนี้นะฮะ

จากรูปข้างบนจะเห็นได้เลยฮะว่า เทียบที่ค่า MSE และ SSIM แล้วนั้น รูป “latest” คล้ายกับรูป “latest_2nd” มากกว่ารูป “first” ฮะ

ความแตกต่างอย่างโดดเด่น

จากการคำนวณหาความแตกต่างระหว่างสองรูปแล้ว คราวนี้เราจะมาลองหาว่าจุดไหนของรูปที่ต่างกันให้เราเห็นชัดๆ บ้างฮะ

เราจะหาด้วยวิธีง่ายๆ นั่นคือ หา pixel ตำแหน่งเดียวกัน แต่มีค่าที่ต่างกันของรูปสองรูปน้อยกว่าค่าที่กำหนด ในที่นี้คือ 0.1 ฮะ ซึ่งรอบนี้เราจะใช้สองรูปแรกฮะ นั่นคือ “latest” กับ “latest_2nd”

change_px = np.abs(latest_gray - latest_2nd_gray) < 0.1
plt.imshow(change_px, cmap='gray')

ต่อมาเราก็จะลบ "รู" ที่มีขนาดเล็กกว่าค่าที่กำหนด นั่นคือ "area_threshold" ซึ่งในที่นี้เป็นค่า 400 pixel นั่นเองฮะ

ถึงตรงนี้ เราพอจะมองออกแล้วนะฮะว่าสองรูปนั้นต่างกันตรง "ถนน" นั่นเองฮะ เพราะถนนในรูปมีการเปลี่ยนแปลงจากรถต่างๆ

road = skimage.morphology.remove_small_holes(change_px, area-threshole=400)

และสุดท้ายเราก็ตกแต่ง "ถนน" โดยปรับค่าสีของ pixel ให้กลืนสีสว่างของ pixel ใกล้ๆ เป็นสีมืดฮะ

road = skimage.morphology.erosion(road)

Reference links:


นี่ก็เป็นความสามารถเล็กๆ น้อยๆ ของ library skimage ตัวนี้นะฮะ

เจอกันใหม่ บล็อกหน้าฮะ

บาย~

ตอนต่อไป: บันทึก training data science EP 13: Regularization – Optimization ด้วย Regularization