Python에서 이미지의 대표 색상 (?)을 취하는 연습

12273 단어 Python3scipy배색
이미지의 대표색을 조사하고 싶어졌다.
게다가 자신 나름대로 대표색을 찾는 방법을 생각하고 그것을 구현해 보는 연습을 하고 싶다고 생각했다.

큰 프레임에서 다음과 같은 방식을 생각해 실장했다.
  • 이미지의 픽셀을 k-means로 클러스터로 나눕니다.
  • 클러스터에 속하는 픽셀 수로 히스토그램을 만듭니다.
  • 히스토그램이 많은 순서로 꺼내 대표색으로 한다.

  • k-means보다 뛰어난 감색 알고리즘이 다수 있어, 그쪽을 사용하는 것도 손일지도 모르지만,
    자신은 일요일 프로그래밍으로 구현할 수 있는 자신이 없었기 때문에, 구현도 간단하고 scipy 에도 포함되어 있는 k-means 를 사용했다.
    픽셀을 클러스터에 할당하는 것도 scipy의 vq (Vector Quantization)를 그대로 사용하기로 했기 때문에 꽤 낭비했다.

    결과



    wkhtmltoimage 명령을 사용하여 여러 웹 페이지의 이미지를 가져 와서 대표 색상을 추출했습니다.
    빼낸 것만으로는 직관적으로는 모르기 때문에, 적당한 직사각형에 대표색을 같은 크기로 표시하기로 했다.
    이하, 근거는 없지만 「좋은 느낌」이라고 생각했다.

    Qiita





    Facebook





    코카콜라 공식 브랜드 사이트





    스크립트



    다음이 Python 3으로 작성된 스크립트.
    다른 numpy, scipy, pillow가 필요합니다.
    #!/usr/bin/env python
    import argparse
    
    import numpy
    
    import PIL
    import PIL.ImageDraw
    import scipy
    import scipy.cluster
    import scipy.misc
    
    
    def main():
        parser = argparse.ArgumentParser()
        parser.add_argument('source_image')
        parser.add_argument('summary_image')
        parser.add_argument('-n', type=int, default=4)
        args = parser.parse_args()
        img = PIL.Image.open(args.source_image)
        c = args.n + 1
        colors = top_n_colors(img, top_n=args.n, num_of_clusters=c)
        save_summary_image(args.summary_image, colors)
    
    
    def pillow_image_to_simple_bitmap(pillow_image):
        small_img = pillow_image.resize((100, 100))
        bitmap = scipy.misc.fromimage(small_img)
        shape = bitmap.shape
        bitmap = bitmap.reshape(scipy.product(shape[:2]), shape[2])
        bitmap = bitmap.astype(numpy.float)
        return bitmap
    
    
    def top_n_colors(pillow_image, top_n, num_of_clusters):
        clustering = scipy.cluster.vq.kmeans
        bitmap = pillow_image_to_simple_bitmap(pillow_image)
        clusters, _ = clustering(bitmap, num_of_clusters)
        quntized, _ = scipy.cluster.vq.vq(bitmap, clusters)
        histgrams, _ = scipy.histogram(quntized, len(clusters))
        order = numpy.argsort(histgrams)[::-1][:top_n]
        for idx in range(top_n):
            rgb = clusters.astype(int)[order[idx]].tolist()
            yield '#{:02x}{:02x}{:02x}'.format(*rgb)
    
    
    def save_summary_image(path, color_codes, width=300, height=100):
        color_codes = tuple(color_codes)
        image = PIL.Image.new('RGB', (width, height))
        draw = PIL.ImageDraw.Draw(image)
        single_width = width / len(color_codes)
        for i, color_code in enumerate(color_codes):
            starting = (int(single_width * i), 0)
            ending = (int(single_width * (i + 1)), height)
            draw.rectangle([starting, ending], fill=color_code)
        image.save(path, format='png')
    
    
    if __name__ == '__main__':
        main()
    

    사용법


    $ python ./image_top_n_color.py input.png output.png
    
    -n 선택적으로 클러스터 수를 지정할 수 있습니다.

    좋은 웹페이지 즐겨찾기