26
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

GitHubのIdenticonの生成と取得

はじめに

 GitHubのプロフィール画像を自分で変更したのですが,初期のものに戻したくなりました.
 また,そもそもGitHubの初期プロフィール画像はどのように生成されているのか気になって調べてみました.

 本記事では,初期プロフィール画像の生成方法と初期プロフィール画像への戻し方を解説します. -> プロフィール画像の戻し方

Identiconの生成

Identiconとは

 GitHubにはIdenticonと呼ばれるアイコンが存在します.GitHubアカウントを作成したときにプロフィール画像になってるこんなやつです.

Identiconの生成方法

 GitHubのBlogにIdenticonの生成に関する記事があります.

 Identicons! - The GitHub Blog

Our Identicons are simple 5x5 "pixel" sprites that are generated using a hash of the user's ID. The algorithm walks through the hash and turns pixels on or off depending on even or odd values. These generated patterns, combined with hash-determined color values, ensures a huge number of unique Identicons.

 Identiconは5x5のピクセルで,ユーザーIDのハッシュ値を元に生成されているそうです.ハッシュ値が偶数か奇数かで各ピクセルのon/offを決定してパターンを生成します.また,Identiconの色も同様に,ハッシュ値に依存して決定しています.これによって,多数のユニークなIdenticonsを保証しているとのことです.

Identiconを生成してみる

 ユーザーIDのハッシュを利用して各ユーザーのIdenticonを決定していることがわかりました.実際にIdenticonを生成してみたいと思います.

  1. ハッシュ値の生成
     ユーザーIDをMD5します.128[bit](16進数で32桁)のハッシュ値が得られます.

 ex) 19229051 -> 73e516f03ddfd989d9ab2975dcbcdbac

  1. パターンの決定
    パターンは以下のように,70×70を1ピクセルした5x5のピクセルから成ります.

 ハッシュ値の前から15文字を使って以下のようにパターンを決定します.ハッシュ値が偶数ならピクセルをON,奇数ならピクセルをOFFにします.順番は真ん中の列の上から下,その右の列の上から下,最後に右端の列の上から下の順です.

 ex) 73e516f03ddfd98

 真ん中の列を中心に線対称に折り返します.これでパターンが完成します.

  1. 色の決定
     ハッシュ値の最後の7文字を使って色を決定します.色はHSL色空間で表現されていて,色相3文字,彩度2文字,輝度2文字で決定しています.

 ex) cbcdbac -> 色相:cbc 彩度:db 輝度:ac

 各16進数を10進数に変換して各パラメータを決定します.色相は0から360の範囲なので,0から4095を0から360の範囲に変換します.彩度と輝度は0から100の範囲です.GitHubでは0から255を0から20の範囲に変換して,それぞれ65,75から減算した値を使用しています.

色相:(cbc)_{10} \times \frac{360}{4095} = 3260 \times \frac{360}{4095} = 287\\
彩度:65 - (db)_{10} \times \frac{20}{255} = 65 - 219 \times \frac{20}{255} = 48\\
輝度:75 - (ac)_{10} \times \frac{20}{255} = 75 - 172 \times \frac{20}{255} = 62

 最後にHSL色空間からRGBへ変換します.HSLからRGBへの変換方法は以下のサイトを参考にしました.ぐぐればすぐにわかると思います.
 
 RGBとHSLの相互変換ツールと変換計算式 - PEKO STEP

 これで色を決定することができました.Identiconの完成です.

注意

 GitHubは詳しいIdenticon生成アルゴリズムを公開していません.本記事で生成方法として紹介したハッシュアルゴリズムや色の決定方法が実際にGitHubで使用されているアルゴリズムと100%同じかどうか分かりません.あくまでGitHubのIdenticon風の画像を生成する方法としてご理解ください.

プログラム

 GitHubのIdenticon風の画像を生成するプログラムです.myidに任意のIDを書きます.画像の出力はOpenCVを使っています.

identicons.py
#coding: utf-8

import numpy as np
import hashlib
import cv2

myid = '19229051'

size = 420 #画像のサイズ
pixel = 70 #1ピクセルのサイズ
frame = 35 #余白のサイズ
background = 240 #背景の色(0-255)

def create_pattern(hash_value):
    pat = np.array([int(hash,16)%2 for hash in hash_value[:15]])
    pat = pat.reshape(3,5).T
    pat = np.append(pat[:,-1:0:-1], pat, axis=1)

    return pat

def create_color(hash_value):
    hue = ''
    for i in range(3): hue += hash_value[25+i]
    hue = int(hue,16) / 4095 * 360
    sat = ''
    for i in range(2): sat += hash_value[28+i]
    sat = 65 - int(sat,16) / 255 * 20
    lum = ''
    for i in range(2): lum += hash_value[30+i]
    lum = 75 - int(lum,16) / 255 * 20

    #print('hue =',hue,'lum =',lum,'sat =',sat)

    if lum < 50:
        max = 2.55 * (lum + lum * (sat/100))
        min = 2.55 * (lum - lum * (sat/100))
    elif lum >= 50:
        max = 2.55 * (lum + (100-lum) * (sat/100))
        min = 2.55 * (lum - (100-lum) * (sat/100))

    if 0 <= hue < 60:
        red   = max
        green = (hue/60) * (max-min) + min
        blue  = min
    elif 60 <= hue < 120:
        red   = ((120-hue)/60) * (max-min) + min
        green = max
        blue  = min
    elif 120 <= hue < 180:
        red   = min
        green = max
        blue  = ((hue-120)/60) * (max-min) + min
    elif 180 <= hue < 240:
        red   = min
        green = ((240-hue)/60) * (max-min) + min
        blue  = max
    elif 240 <= hue < 300:
        red   = ((hue-240)/60) * (max-min) + min
        green = min
        blue  = max
    elif 300 <= hue <= 360:
        red   = max
        green = min
        blue  = ((360-hue)/60) * (max-min) + min

    return [red,green,blue]

def create_image(pattern, colors):
    image = np.full([size,size,3],background)

    for i in range(5):
        for j in range(5):
                for k in range(pixel):
                    for l in range(pixel):
                        if pattern[i][j] == 0:
                            image[frame+i*pixel+k][frame+j*pixel+l][0] = colors[2]
                            image[frame+i*pixel+k][frame+j*pixel+l][1] = colors[1]
                            image[frame+i*pixel+k][frame+j*pixel+l][2] = colors[0]
                        elif pattern[i][j] == 1:
                            image[frame+i*pixel+k][frame+j*pixel+l][:] = background

    return image

if __name__ == '__main__':

    print('ID  =', myid)

    #MD5の計算
    hash_value = hashlib.md5(myid.encode()).hexdigest()
    print('md5 =', hash_value, '\n')

    #パターンの生成
    pat = create_pattern(hash_value)
    print('pattern')
    print(pat, '\n')

    #色の生成
    colors = create_color(hash_value)
    print('RGB colors =', colors, '\n')

    #画像の生成
    image = create_image(pat, colors)
    cv2.imwrite(myid+'.png', image)
    print('Output', myid+'.png')
ID  = 19229051
md5 = 73e516f03ddfd989d9ab2975dcbcdbac 

pattern
[[1 0 1 0 1]
 [1 1 1 1 1]
 [1 0 0 0 1]
 [1 1 1 1 1]
 [0 1 1 1 0]] 

RGB colors = [182.8124831932773, 109.91120588235293, 203.78879411764703] 

Output 19229051.png

プロフィール画像の戻し方

 長々とIdenticonの生成方法を解説しましたが,自分のプロフィール画像を初期のものに戻す方法は簡単です.
 https://github.com//<username>.png(2019/04/04修正) https://github.com/identicons/<username>.pngにアクセスすれば自分のIdenticonがあります.これをダウンロードしてプロフィールを変更するだけです.自分で画像を生成する必要はありません.

おわりに

 いい感じの形と色のIdenticonを生成するユーザーIDになるまで,アカウント作成リセマラとかできるのかな?

追記(2018/02/17)

 HSL→RGBに変換する部分を自分で書いたけど,実はライブラリがあった.
 (r,g,b) = colorsys.hls_to_rgb(h,l,s)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
26
Help us understand the problem. What are the problem?