DEV Community

Khokhwan Weangoukost
Khokhwan Weangoukost

Posted on

สร้างโค้ดสีจากรูปภาพ โดยใช้ Python

สายกราฟฟิก หรือสาย Web designer คนไหนเคยอยากคุมโทนสีตามเรฟที่เป็นรูปภาพ แต่ดูดสีออกมายังไงก็ไม่ได้ดั่งใจไหมคะ? เดี๋ยวเราจะพามาให้รู้จักกับ K-means Algorithm ที่จะทำให้ชีวิตเราง่ายขึ้นเยอะะ เพราะสามารถดูดสีออกมาได้เป๊ะอย่างงี้ 👍🏼💯

บทความนี้เราจะทำการดูดสีรูปภาพโดยใช้ K-mean Clustering ( ในส่วนของ Image Processing ☝🏼🖼️ ) ในการตรวจจับกลุ่มสีต่าง ๆ ในรูป เพื่อนำค่า RGB ของจุดศูนย์กลางของกลุ่มสีนั้น ๆ มาสร้างเป็นโค้ดสี โดยทั้งหมดเราจะรันโค้ดผ่าน Google Colab

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

ทำการเรียกใช้ไลบรารีที่จำเป็น ดังนี้

  1. Scikit-learn ไลบรารีหลักสำหรับ Machine Learning ในภาษา Python ที่มีฟังก์ชันการทำงานที่ครอบคลุม และรองรับอัลกอริธึมที่หลากหลาย ซึ่งแน่นอนว่าการจัดกลุ่ม (Clustering) ก็เป็นหนึ่งในนั้น
  2. Matplotlib สำหรับสร้างกราฟวงกลม (Pie Chart)
  3. NumPy (Numerical Python) สำหรับการจัดการ Array
  4. OpenCV (Open Source Computer Vision Library) สำหรับการจัดการรูปภาพ
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import cv2
from collections import Counter
from skimage.color import rgb2lab, deltaE_cie76
import os

%matplotlib inline
Enter fullscreen mode Exit fullscreen mode

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

เลือกรูปที่สนใจมา 1 รูป โดยในตัวอย่างนี้จะใช้เป็นรูปน้องหนูเจอรี่ 🤓👇🏻

Image description

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

from google.colab import drive

drive.mount('/content/drive')
file_path = '/content/drive/MyDrive/hey.JPG'

image = cv2.imread(file_path)
print("The type of this input is {}".format(type(image)))
print("Shape: {}".format(image.shape))
plt.imshow(image)
Enter fullscreen mode Exit fullscreen mode

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

Image description

แต่เราจะสังเกตได้ว่ารูปที่ได้สีจะเพี้ยนไปจากรูปตัวอย่าง เพราะว่าการอ่านรูปของ OpenCV โดย default ทำให้เราได้รูปออกมาเป็น BGR

ดังนั้น เราจะทำการเปลี่ยนให้เป็น RGB ด้วย

image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
Enter fullscreen mode Exit fullscreen mode

ก็จะได้แบบนี้
Image description

เมื่อสีรูปตรงกับต้นฉบับแล้ว เราก็ไปดูดสีกันได้เลยย 🙌🏼

ขั้นตอนที่ 3 : สร้างฟังก์ชันจำแนกสี

  • สร้างฟังก์ชันให้สีที่จำแนกออกมาอยู่ในรูปของค่า hex (โค้ดสี)
def RGB2HEX(color):
    return "#{:02x}{:02x}{:02x}".format(int(color[0]), int(color[1]), int(color[2]))
Enter fullscreen mode Exit fullscreen mode
  • สร้างฟังก์ชันวิเคราะห์ค่าสีออกมา
def get_colors(image, number_of_colors, show_chart):

    modified_image = cv2.resize(image, (600, 400), interpolation = cv2.INTER_AREA)
    modified_image = modified_image.reshape(modified_image.shape[0]*modified_image.shape[1], 3)

    clf = KMeans(n_clusters = number_of_colors)
    labels = clf.fit_predict(modified_image)

    counts = Counter(labels)
    # sort to ensure correct color percentage
    counts = dict(sorted(counts.items()))

    center_colors = clf.cluster_centers_
    # We get ordered colors by iterating through the keys
    ordered_colors = [center_colors[i] for i in counts.keys()]
    hex_colors = [RGB2HEX(ordered_colors[i]) for i in counts.keys()]
    rgb_colors = [ordered_colors[i] for i in counts.keys()]

    if (show_chart):
        plt.figure(figsize = (8, 6))
        plt.pie(counts.values(), labels = hex_colors, colors = hex_colors)

    return rgb_colors
Enter fullscreen mode Exit fullscreen mode

ขั้นตอนที่ 4 : ทดลองนำมาใช้กับรูปตัวอย่าง

get_colors(image, 8, True)
Enter fullscreen mode Exit fullscreen mode

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

Image description

คำถามชวนคิด

จากผลลัพธ์ข้างต้น คิดว่าถ้าเราสามารถดูดสีจากรูปได้ เราจะสามารถดูดรูปจากสีได้เหมือนกันไหม 🧐

มาลองดูกันน! 😼💪🏻

ขั้นตอนสำหรับการค้นหารูปจากโค้ดสี

  • ก่อนอื่นเราจะต้องมีคลังรูปภาพไว้ใน images ก่อน
IMAGE_DIRECTORY = '/content/drive/MyDrive/gallery'
COLORS = {
    'RED': [255, 0, 0],
    'BLUE': [0, 0, 128],
    'YELLOW': [255, 255, 0]
}
images = []

for file in os.listdir(IMAGE_DIRECTORY):
    if not file.startswith('.'):
        images.append(get_image(os.path.join(IMAGE_DIRECTORY, file)))
Enter fullscreen mode Exit fullscreen mode

ลองแสดงรูปภาพทั้งหมดในแกลลอรี่

plt.figure(figsize=(20, 10))
for i in range(len(images)):
    plt.subplot(1, len(images), i+1)
    plt.imshow(images[i])
Enter fullscreen mode Exit fullscreen mode

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

  • ต่อมาสร้างฟังก์ชันที่จะเลือกจับคู่สีหลัก ๆ ของรูปภาพมา 10 สี จากนั้นจะเอา 5 สีแรกจากรูปมาคำนวณหาความแตกต่างกับสีที่เราต้องการ

ซึ่งแน่นอนว่าเราไม่สามารถจับคู่ค่าสี (hex) ได้ตรงเป๊ะ ดังนั้น เราจะดูจากสัดส่วนค่าความต่างสี ถ้าน้อยแสดงว่าทั้งสองสีมีความใกล้เคียงกัน เราก็จะแสดงรูปนั้นเลย เพื่อประกาศว่าสีตรงกับรูปนี้นะ

โดยเราจะใช้ rgb2lab เพื่อแปลงค่าให้สามารถนำมาเปรียบเทียบกันได้ และใช้ deltaE_cie76 สำหรับการหาความต่างสี ได้ดังนี้

def match_image_by_color(image, color, threshold = 60, number_of_colors = 10): 

    image_colors = get_colors(image, number_of_colors, False)
    selected_color = rgb2lab(np.uint8(np.asarray([[color]])))

    select_image = False
    for i in range(number_of_colors):
        curr_color = rgb2lab(np.uint8(np.asarray([[image_colors[i]]])))
        diff = deltaE_cie76(selected_color, curr_color)
        if (diff < threshold):
            select_image = True

    return select_image

def show_selected_images(images, color, threshold, colors_to_match):
    index = 1

    for i in range(len(images)):
        selected = match_image_by_color(images[i],
                                        color,
                                        threshold,
                                        colors_to_match)
        if (selected):
            plt.subplot(1, 5, index)
            plt.imshow(images[i])
            index += 1
Enter fullscreen mode Exit fullscreen mode

จากนั้นทดลองหารูปที่มีสีแดง ❤️

# Search for RED
plt.figure(figsize = (20, 10))
show_selected_images(images, COLORS['RED'], 60, 5)
Enter fullscreen mode Exit fullscreen mode

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

Image description

ทดลองหารูปที่มีสีฟ้า💙

# Search for BLUE
plt.figure(figsize = (20, 10))
show_selected_images(images, COLORS['BLUE'], 60, 5)
Enter fullscreen mode Exit fullscreen mode

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

Image description

ทดลองหารูปที่มีสีเหลือง💛

# Search for YELLOW
plt.figure(figsize = (20, 10))
show_selected_images(images, COLORS['YELLOW'], 60, 5)
Enter fullscreen mode Exit fullscreen mode

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

สรุปผล 👩🏻‍🎨🗯️
เราสามารถดึงสีมาจากรูปได้โดยการใช้ K-mean Clustering แต่ในทางกลับกันหากนำโค้ดมาทำการค้นหารูปก็อาจจะไม่สามารถทำได้ดีเท่าที่ควร เห็นได้จากตอนค้นหารูปที่มีสีฟ้า มีการแสดงทุกรูปที่มีออกมาเลย ส่วนนึงเนื่องมาจากการเทียบโค้ดสี hex ให้ตรงกันนั้นเป็นไปได้ยาก จึงง่ายต่อการคลาดเคลื่อน หรือก็คืออาจจะได้รูปที่ไม่ตรงกับสีที่ค้นหา

Reference :

Top comments (0)