2025, Oct 22 16:47
RGB हिस्टोग्राम बनाम KMeans: टॉप 10 सटीक रंग बनाम डॉमिनेंट पैलेट
क्या वजह है कि Pillow के RGB हिस्टोग्राम के टॉप 10 रंग, टूल के डॉमिनेंट रंगों से अलग होते हैं? Python में getcolors, Counter और KMeans से सही तरीका चुनें.
दो स्क्रिप्टें ऊपर-ऊपर से एक ही समस्या हल करती दिख सकती हैं, फिर भी उनके नतीजे एक-दूसरे से बहुत अलग हो सकते हैं। यही होता है जब आप किसी कच्चे RGB हिस्टोग्राम से निकले “टॉप 10 रंग” की तुलना उन “डॉमिनेंट रंगों” से करते हैं, जिन्हें कुछ ऑनलाइन टूल लौटाते हैं। पहला तरीका पिक्सेल के सटीक RGB तिकड़ों की गिनती करता है। दूसरा आम तौर पर क्लस्टरिंग का इस्तेमाल करके छवि को 10‑रंगों की पैलेट में संकुचित कर देता है। ये दोनों बातों के जवाब एक जैसे नहीं होते।
समस्या की रूपरेखा
आप Pillow से एक छवि पढ़ते हैं, सभी रंगों को गिनते हैं और सबसे आम दस रंग रख लेते हैं। वही छवि किसी ऑनलाइन सेवा से गुजारें तो सूची बिल्कुल अलग निकलती है। शंका होती है कि PIL रंगों को किसी और तरह से प्रोसेस कर रहा होगा।
सटीक रंग गिनने वाला पुनरुत्पादनीय कोड
नीचे दिया स्निपेट getcolors से मिली असॉर्टेड सूची लेता है, आवृत्ति के आधार पर चलते-चलते “टॉप 10” बनाए रखता है, और अंत में उस शॉर्टलिस्ट को गिनती के अनुसार सॉर्ट करता है। यह लॉजिक जानबूझकर सटीक RGB तिकड़ों की गिनती करता है; मिलते-जुलते शेड्स को एक साथ नहीं जोड़ता।
from PIL import Image
pic = Image.open(image_url)
color_bag = pic.getcolors(maxcolors=100000)  # प्रत्येक अद्वितीय रंग उसकी आवृत्ति सहित
best_ten = color_bag[:10]
for entry in color_bag[9:]:
    tally = entry[0]
    current_counts = []
    for chosen in best_ten:
        current_counts.append(chosen[0])
    if tally > min(current_counts):
        replace_at = current_counts.index(min(current_counts))
        best_ten[replace_at] = entry
ranked_best = sorted(best_ten, key=lambda item: item[0], reverse=True)
print(ranked_best)
print(best_ten)
अंतर की असल वजह
दोनों आउटपुट इसलिए नहीं मिलते क्योंकि वे अलग सवालों का जवाब दे रहे होते हैं। सटीक तिकड़ों की गिनती करने से छवि में सबसे अधिक बार आने वाले पिक्सेल मान मिलते हैं, जो अक्सर एक ही ग्रे के बहुत पास-पास के शेड्स हो सकते हैं। दूसरी ओर, ऑनलाइन नतीजा पैलेट एक्सट्रैक्शन जैसा व्यवहार करता है। वह दस ऐसे प्रतिनिधि रंग चुनता है जो पूरी छवि का सार बताते हैं, न कि सबसे ज्यादा दोहराए गए सटीक RGB मान। यह व्यवहार पिक्सेल मानों पर KMeans क्लस्टरिंग से मेल खाता है।
एक अलग बात यह भी है: getcolors एक असॉर्टेड सूची लौटाता है, और ऊपर जैसा “रनिंग टॉप‑k” रखने वाला कोड उस क्रम के प्रति संवेदनशील होता है। यानी, अगर आप इनपुट के क्रम पर निर्भर हैं, तो जैसा इनपुट वैसा आउटपुट। लेकिन भले ही आप ऑर्डर ठीक कर लें, केवल आवृत्ति की सूची क्लस्टरिंग‑आधारित पैलेट से फिर भी नहीं मिलेगी, क्योंकि दोनों के लक्ष्य अलग हैं।
लक्ष्य पर निर्भर करते हुए “टॉप रंग” निकालने के दो तरीके
अगर लक्ष्य शाब्दिक रूप से “सबसे अधिक बार आने वाले 10 सटीक RGB तिकड़े” है, तो एक साधारण हिस्टोग्राम काफी है। अगर लक्ष्य “वह 10 रंग जो आप छवि को 10‑रंगों की पैलेट में संपीड़ित करने पर रखेंगे” है, तो KMeans के क्लस्टर सेंटर्स चाहिए।
numpy + Counter के साथ सटीक आवृत्तियाँ:
from collections import Counter
import numpy as np
from PIL import Image
pixels = np.asarray(Image.open('image.jpg'))
freqs = Counter(tuple(v) for v in pixels.reshape(-1, 3))
print(freqs.most_common(10))
KMeans के साथ क्लस्टर‑आधारित पैलेट:
from sklearn.cluster import KMeans
import numpy as np
from PIL import Image
pixels = np.asarray(Image.open('image.jpg'))
km = KMeans(n_clusters=10, random_state=0, n_init="auto")
km.fit(pixels.reshape(-1, 3))
print(km.cluster_centers_)
क्लस्टर सेंटर्स पिक्सेल समूहों के औसत केंद्र होते हैं और उनके वास्तविक पिक्सेल मान होना आवश्यक नहीं है—यही अपेक्षित है। साथ ही, जब डेटा सतत (contiguous) हो तो H×W×3 एरे को N×3 में reshape करना केवल एक व्यू बनाता है, इसलिए सामान्यतः यह कदम लगभग मुफ़्त पड़ता है।
यह क्यों मायने रखता है
तरीका बदलते ही जवाब बदल जाता है। सख्त हिस्टोग्राम किसी दृश्य में हावी गहरे टोन के कई लगभग एक जैसे शेड्स को टॉप 10 में रख सकता है। KMeans पैलेट आम तौर पर हल्के टोन और दुर्लभ लेकिन दृश्य रूप से महत्वपूर्ण ह्यूज़ भी शामिल करता है, क्योंकि वह मिलते-जुलते रंगों को समूहित कर प्रत्येक समूह को उसके केंद्र से प्रस्तुत करता है। अगर आप छवि को 10 रंगों में क्वांटाइज़ करना चाहते हैं, तो क्लस्टर सेंटर्स सही लक्ष्य हैं। और अगर आप सटीक रंग पुनरावृत्ति का ऑडिट कर रहे हैं, तो हिस्टोग्राम सही है।
मुख्य निष्कर्ष
कोड लिखने से पहले “टॉप रंग” का अर्थ साफ़ करें। अगर मतलब सटीक RGB मानों की सबसे अधिक आवृत्ति है, तो फ़्रीक्वेंसी काउंट लें। अगर मतलब डॉमिनेंट पैलेट रंग हैं, तो KMeans अपनाएँ। दोनों तरीकों के एक जैसे नतीजे की उम्मीद न करें—वे जानबूझकर अलग परिणामों के लिए ऑप्टिमाइज़ किए गए हैं। और अगर आप getcolors पर निर्भर हैं, तो आउटपुट को ऑर्डर माना न लें—स्थिर व्यवहार चाहिए तो स्पष्ट रूप से सॉर्ट करें।