82702


_**前提・実現したいこと**_  
ある画像の各色が何を表しているのかをカラーバーの様に棒状にして画像に加えたいと考えています（ヒートマップの凡例をつくる）。例として下記の画像を示します。この色は標高何メートルと決めて標記したいです。緑色は0～100ｍ、オレンジ色は300～400ｍであったりとかいう感じです。画像は次のURLから引用しています。  
<https://www.gsi.go.jp/KIDS/KIDS07.html>  
[![画像の説明をここに入力](https://i.stack.imgur.com/ODKMg.png)](https://i.stack.imgur.com/ODKMg.png)

_**発生している問題・エラーメッセージ**_  
初心者で大変申し訳ないですが、この表し方が分かりません。調査した結果、カラーバーとは自分がカラーマップを作成しそれを利用して作るといったものだと理解しています。上記の画像にある自分が表したい色を用いたカラーマップを自作する必要があるのか、はたまた画像の色を読み取りそれをカラーバーの様に表す事が出来るのかが分からない状態です。試しに任意で等高線を作り、カラーバーを表示してみました。この等高線の様に上記の画像を基に、カラーバーの軸を0、100、200、300、400・・・の様にしたいです。エラーメッセージは出ませんでした。

_**該当のソースコード**_  
任意の等高線とそのカラーバーを作ったソースコードを示します。しかしこれはあくまでこの様な等高線のカラーバーはこの様に表したいというイメージであり、実際に私が求めるのは上記のURLにある画像の色をカラーバーの様に表したいという事です。

[code]

    import matplotlib.pyplot as plt
    import numpy as np
    
    
    # データを作成する。
    def f(x, y):
        return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
    
    
    x = np.linspace(0, 5, 50)
    y = np.linspace(0, 5, 40)
    X, Y = np.meshgrid(x, y)
    Z = f(X, Y)
    
    # 等高線を作成する。
    fig, ax = plt.subplots()
    c = ax.contourf(X, Y, Z, 20, cmap="jet")
    fig.colorbar(c)
    
    plt.show()
    
[/code]

出力は以下の様です。  
[![画像の説明をここに入力](https://i.stack.imgur.com/rJyyp.png)](https://i.stack.imgur.com/rJyyp.png)

_**試したこと**_  
調査した結果、カラーバーとは自分がカラーマップを作成しそれを利用して作るといったものだと理解しています。上記の画像にある自分が表したい色を用いたカラーマップを自作する必要があるのか、はたまた画像の色を読み取りそれをカラーバーの様に表す事が出来るのかが分からない状態です。とりあえずイメージを考えたいとの事で、任意の等高線とカラーバーを作成しました。

_**補足情報（FW/ツールのバージョンなど）**_  
言語：Python  
環境：Windows10  
ブラウザ：Google chrome（Google Colaboratory)  
＊ノートパソコンです。全て最新バージョンです。プログラミング中はcolab以外のタブ、アプリは開いていません。  
＊急ぎの内容の為、以下のサイトでも同様の質問をさせていただいています。他サイトで解決した場合、こちらでも明記します。

<https://teratail.com/questions/361494>


CC BY-SA 4.0
2021-09-27T02:01:52.063
82701
2021-09-28T06:55:02.370
2021-09-27T22:32:30.843
48040
48040
question
python google-colaboratory 画像処理
画像の各色をカラーバーの様に表したい


ご質問の意図は「既存の画像を使用する(つまり図形や色の変更はできない)」「各色の意味をカラーバーで表示する」ものと読み取りました。  
上記の前提では等高線図を差し替えると図形や色が変更になるので、pythonを使って画像から標高ごとに色を特定しようとすると、おそらく「泥臭いコード」になります。  
(特定ピクセルからRGB値を読み取ってカラーバーに反映する処理を自動化するロジックは、色を読み取るピクセルの座標設定などが不可能ではありませんが困難です)

そのため下記のご質問の回答は、「読み込む画像の生成ロジックや仕様が明示されていれば実現可能ですが、ご質問から読み取れなかったので自作する方が現実的です」となります。

>
> 上記の画像にある自分が表したい色を用いたカラーマップを自作する必要があるのか、はたまた画像の色を読み取りそれをカラーバーの様に表す事が出来るのかが分からない状態です。

現実的な案として、あらかじめ各色の値を画像編集ソフトで読み取っておき、決め打ちで値を指定するサンプルコードをおいておきます。

**サンプルコード**

[code]

    from PIL import Image
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    
    # 画像の色を指定する
    cmap = mpl.colors.ListedColormap(['#00ff00', '#ccff66', '#ffcc66', '#ff9900', '#ff6600'])
    # 不連続なカラーバーを作成する
    bounds = [b for b in range(0, 501, 100)]
    norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
    
    # カレントディレクトリの地形画像を読み込む
    with Image.open("000137042.png") as img:
        plt.imshow(img, cmap=cmap, norm=norm)
        cbar = plt.colorbar()
        # カラーバーの目盛(0,100,200,300,400 over)を指定する
        cbar.ax.set_yticklabels(['0','100','200','300', '400 over', ''])
        plt.show()
    
[/code]

**出力結果**

![出力イメージ](https://i.stack.imgur.com/bykiS.png)

**参考資料**

  * [カラーバー](http://hydro.iis.u-tokyo.ac.jp/%7Eakira/page/Python/contents/plot/general/colorbar.html)
  * [Discrete Color Bar](https://jakevdp.github.io/PythonDataScienceHandbook/04.07-customizing-colorbars.html#Discrete-Color-Bars)
  * [matplotlib: colorbars and its text labels](https://stackoverflow.com/q/15908371)


CC BY-SA 4.0
2021-09-27T03:01:37.217
82702
2021-09-27T08:51:32.837
2021-09-27T08:51:32.837
9820
9820
82701
answer


以下は回答ではなく調査報告の様なものですが、何らかの参考にはなるかもしれません。

まず、対象の画像に関してですが、含まれている色数を調べてみます。

[code]

    $ identify -format '%k\n' 000137042.png                                                         
    5493
    
    $ identify -verbose 000137042.png
      Format: PNG (Portable Network Graphics)
      Colorspace: sRGB
      Type: TrueColor
      Depth: 8-bit
      Channel depth:
        red: 8-bit
        green: 8-bit
        blue: 8-bit
           :
    
[/code]

結果は 5493 色ですが、これは TrueColor(24 bit
color)であるのと、おそらくは紙の書籍からスキャンされた画像なのではないかと推測します。それでは 512 色に減色して color bar
を作成してみます。

[code]

    $ convert \( 000137042.png -colors 512 \) \
          \( -size x50 xc:white \) \
          \( \
             -size 2x25 \
             $(convert 000137042.png -colors 512 -format %c histogram:info:- |
               awk '{printf "xc:%s ", $3}') +append  \
          \) \
        -append colorbar-512.png
    
[/code]

[![colorbar-512](https://i.stack.imgur.com/0DOSq.png)](https://i.stack.imgur.com/0DOSq.png)

これでは意味(意義)がありませんね。。。

次に量子化の粒度(離散化の程度)を変更してみます。

[code]

    f=000137042.png
    w=$(identify -format '%w' $f)
    for c in 8 12 16
    do
      convert \( $f -colors $c \) \
              \( -size x50 xc:white \) \
              \( \
                 -size $((w/c))x25 -bordercolor black -border 1x1 \
                 $(convert $f -colors $c -format %c histogram:info:- |
                   sort -nr -k1,1 | awk '{printf "xc:%s ", $3}') +append  \
              \) \
            -append colorbar-${c}.png
    done
    
[/code]

##### 8色に減色

[![color-8](https://i.stack.imgur.com/LmXNx.png)](https://i.stack.imgur.com/LmXNx.png)

##### 12色に減色

[![color-12](https://i.stack.imgur.com/UEUse.png)](https://i.stack.imgur.com/UEUse.png)

##### 16色に減色

[![color-16](https://i.stack.imgur.com/5UBwA.png)](https://i.stack.imgur.com/5UBwA.png)

8色や12色では量子化の粒度が粗すぎて部分的に色が変化してしまっている事が判るかと思います。結果として、この画像に対しては16の異なる「色」が最低限必要なのでしょう。

では、この後どうするのかという事ですが、対象の画像ではバックグラウンドが白(white)で、annotation
の文字列は黒(black)に近いので、「色の距離」(color distance)を計算して、前述の16色から黒や白色に「近い」色を除外して、なおかつ
histogram の大きい順に色を選んで行く、といったところでしょうか(適切な結果は得られませんでしたが)。


CC BY-SA 4.0
2021-09-28T06:55:02.370
82729
2021-09-28T06:55:02.370
47127
82701
answer