DEV Community

Pavat
Pavat

Posted on

Digital Image Processing ผ่านการคำนวณฮิสโตแกรมและการปรับสมดุล

ฮิสโตแกรม คืออะไร ?
ฮิสโตแกรมจะแสดงถึงระดับความเข้มของแต่ละสีในภาพ ทำให้การคำนวณฮิสโตแกรมนั้น จะช่วยให้เราสร้างเกณฑ์ที่ใช้ในการกรองรูปภาพหรือดึงข้อมูลจากรูปภาพได้

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

ขั้นตอนที่ 1 : Import Libraries

ติดตั้งไลบรารีที่ต้องใช้ ดังนี้

  1. OpenCV (Open Source Computer Vision Library) ใช้ในการ จัดการรูปภาพ
  2. NumPy (Numerical Python) ใช้ในการจัดการ Array
  3. PyPlot (Python Plotting) ใช้ในการพัฒนาและนำเสนอผลลัพธ์ใน งานวิจัย การวิเคราะห์ข้อมูล หรือการนำเสนอผลงานทางวิทยาศาสตร์และ เทคโนโลยีในรูปแบบของกราฟและภาพ
import cv2
from matplotlib import pyplot as pt
Enter fullscreen mode Exit fullscreen mode

ขั้นตอนที่ 2 : นำข้อมูลรูปภาพเข้า

เลือกรูปภาพที่สนใจมา 1 รูป โดยในตัวอย่างนี้จะเลือกรูปนี้มา

Image description

เมื่อนำรูปมาใส่ในไฟล์แล้ว จะทำการอ่านและเก็บไว้ในตัวแปร cat

cat = cv2.imread("cat_01.jpg", 0)
cat_equalized = cv2.equalizeHist(cat)
cat_hist = cv2.calcHist(cat, [0], None, [256], [0, 256])
Enter fullscreen mode Exit fullscreen mode

แล้วตัวแปร cat ไปผ่านกระบวนปรับสีให้กลายเป็นสีเทา และหาค่าฮิสโตแกรมของรูปภาพ

pt.figure()
pt.tight_layout()
pt.subplot(1, 3, 1)
pt.title("Original image")
pt.imshow(cat, cmap='gray')

pt.subplot(1, 3, 2)
pt.title("Equalized Histogram Image")
pt.imshow(cat_equalized, cmap='gray')

pt.subplot(1, 3, 3)
pt.plot(cat_hist)
pt.title('Cat Histogram')
pt.show()
Enter fullscreen mode Exit fullscreen mode

ผลลัพธ์ที่ได้

Image description

อย่างที่เห็น มันค่อนข้างที่จะทำได้ง่ายโดยการใช้ไลบรารีของ OpenCV
แต่ imshow ที่มาจาก Pyplot นั้น ไม่สามารถทำงานได้ตามที่คาดหวังไว้
ถ้าเราไม่ได้ระบุสีไว้ใฟ้เหมือนกับตัวอย่างข้างต้น

ขั้นตอนที่ 3 : การทำให้ฮิสโตแกรมเป็นมาตรฐาน

การที่จะทำให้ฮิสโตแกรมเป็นมาตรฐานนั้นจะต้องแปลงการกระจายตัวของความเข้มแบบไม่ต่อเนื่องให้เป็นการแจกแจงความน่าจะเป็นแบบไม่ต่อเนื่อง

ทำให้เราต้องแบ่งแต่ละค่าของฮิสโตแกรมด้วยจำนวนของพิกเซล
โดยเราจะต้องหารฮิสโตแกรมที่เท่ากันด้วยจำนวนพิกเซลทั้งหมด

pt.figure()
pt.tight_layout()
pt.subplot(2, 2, 1)
pt.title("Original image")
pt.imshow(cat, cmap='gray')

pt.subplot(2, 2, 2)
pt.title("Equalized Histogram Image")
pt.imshow(cat_equalized, cmap='gray')

pt.subplot(2, 2, 3)
pt.plot(cat_hist)
pt.title('Cat Histogram')

pt.subplot(2, 2, 4)
pt.plot(cat_hist_normalized)
pt.title('Cat Histogram Normalized')
pt.show()
Enter fullscreen mode Exit fullscreen mode

ก็จะได้ผลลัพธ์แบบนี้

Image description

จะเห็นได้จากรูปฝั่งขวาล่าง ค่าช่วงได้รับการปรับนั้นจะมีขนาดที่น้อยลง

แต่ภาพสีเทาจะมีไบนารี่ที่ระนาบกับพิกเซลเพียงระนาบเดียว
ส่วน RGB นั้นประกอบด้วย 3 ระนาบ โดยที่แต่ละสีจะมีระนาบเป็นของตัวเอง

รู้หรือไม่ ?

ไลบรารีของ OpenCV นั้นจะอ่านรูปภาพตามลำดับของระนาบที่ต่างกัน
ไม่ใช่แบบ RGB แต่เป็นแบบ BGR

ขั้นตอนที่ 4 : สร้างฟังก์ชันประมวลผลภาพดิจิทัลออกมา

src = cv.imread("efr.jpg")

bgr_planes = cv.split(src)
hist_size = 256
hist_range = (0, 256)  # the upper boundary is exclusive

r_hist = cv.calcHist(bgr_planes, [0], None, [hist_size], hist_range, accumulate=False)
g_hist = cv.calcHist(bgr_planes, [1], None, [hist_size], hist_range, accumulate=False)
b_hist = cv.calcHist(bgr_planes, [2], None, [hist_size], hist_range, accumulate=False)

hist_width = 512
hist_height = 400
bin_weight = int(round(hist_width / hist_size))

hist_image = np.zeros((hist_width, hist_height, 3), dtype=np.uint8)

cv.normalize(r_hist, r_hist, alpha=0, beta=hist_height, norm_type=cv.NORM_MINMAX)
cv.normalize(g_hist, g_hist, alpha=0, beta=hist_height, norm_type=cv.NORM_MINMAX)
cv.normalize(g_hist, g_hist, alpha=0, beta=hist_height, norm_type=cv.NORM_MINMAX)

for i in range(1, hist_size):
    cv.line(hist_image, (bin_weight * (i - 1), hist_height - int(b_hist[i - 1])),
            (bin_weight * i, hist_height - int(b_hist[i])),
            (255, 0, 0), thickness=2)
    cv.line(hist_image, (bin_weight * (i - 1), hist_height - int(g_hist[i - 1])),
            (bin_weight * i, hist_height - int(g_hist[i])),
            (0, 255, 0), thickness=2)
    cv.line(hist_image, (bin_weight * (i - 1), hist_height - int(r_hist[i - 1])),
            (bin_weight * i, hist_height - int(r_hist[i])),
            (0, 0, 255), thickness=2)
Enter fullscreen mode Exit fullscreen mode

นี้คือรูปที่จะเอามาใช้ในตัวอย่างนี้

Image description

และนี้คือ ผลลัพธ์ที่ได้จาก"ฟังก์ชันประมวลผลภาพดิจิทัล"

Image description

สรุปผล

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

Reference

Top comments (0)