Digital Image Processing ผ่านการคำนวณฮิสโตแกรมและการปรับสมดุล
Tags: ai, python
Published: 2024-04-13 11:47:11

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

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

## **ขั้นตอนที่ 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
```
## **ขั้นตอนที่ 2 : นำข้อมูลรูปภาพเข้า**
เลือกรูปภาพที่สนใจมา 1 รูป โดยในตัวอย่างนี้จะเลือกรูปนี้มา

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/juvjr64ligaqafzv3429.jpg)

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

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

แล้วตัวแปร 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()
```

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3urh5wotz6e7lorj9521.png)

อย่างที่เห็น มันค่อนข้างที่จะทำได้ง่ายโดยการใช้ไลบรารีของ 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()
```

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


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ebubrnxkz960q1wzzcoq.png)

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

แต่ภาพสีเทาจะมีไบนารี่ที่ระนาบกับพิกเซลเพียงระนาบเดียว 
ส่วน 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)
```

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oykcccbwm11gk0318sil.jpg)

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dppp33uzh4quyfwrgkpy.png)

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

## **Reference**

- https://medium.com/@vrnsky/digital-image-processing-histogram-calculation-equalization-and-normalization-ad09b0bba5b1
- https://www.pinterest.com