質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.63%

python PIL 画像処理

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,130

fia

score 48

 やりたいこと

pythonでの画像処理で読み込んだ画像の色情報を変更して描画する。

 発生している問題

matplotlibで画像をプロットしてクリックした地点の色を別の色に変更しようとした際、中途半端に変更される。
また、クリックした地点から数ピクセル離れたところの色情報が取得される。

 ソースコード

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import sys

class im:
    def __init__(self,image):
        self.image=image
    def onclick(self,event):
        plist=self.image[int(event.ydata)][int(event.xdata)]
        print(plist)
        h, w, c = self.image.shape
        for i in range(h):
            for j in range(w):
                if (self.image[i][j] == plist).all():
                    self.image[i][j] = [255, 255, 255]
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.imshow(self.image)
        plt.show()

# 画像を読み込む
img = Image.open( "./test.png")
img=np.array(img)
c_event=im(img)
fig=plt.figure()
ax=fig.add_subplot(111)
ax.imshow(img)
cid = fig.canvas.mpl_connect('button_press_event', c_event.onclick)
plt.show()

 試したこと

plistの色情報を手動指定
変更したいところの色が[255,0,0]の場合に、クリックしたときに取得した色情報が[255,0,0]であること、画像の変更がおかしいことを確認し、plist=[255,0,0]の固定情報になるよう書き換えて再実行したところ、うまく変更がされた。

追記

元画像
イメージ説明
変更後
イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

クリックしたピクセルと同色のピクセルを白く塗りつぶすプログラムのようですね。

matplotlibで画像をプロットしてクリックした地点の色を別の色に変更しようとした際、中途半端に変更される。

中途半端というのがよく分からないのですが、クリックのたびに新しいウインドウが表示されました。
これは意図した動作ではないと思われるので、最後に示すように、ウインドウ内の画像更新するようにコード修正しました。

 原因を追記

現象再現できました。plistは実際には画像のクリックされたセル値を指しているだけです。
よってforループ中にクリックされたピクセル値の値を更新するとplistの値も更新され、それ以降の判定がおかしくなってしまっています。
回避するにはplistに対して実値を(深い)コピー代入する必要があります。

 ついでに

forループからnumpyで一括操作する手法に修正してみました。
ディープコピーなどを心配せずにかつ高速で処理できます。
参考:python,OpenCV,numpyによる色抽出・変換

また、クリックした地点から数ピクセル離れたところの色情報が取得される。

再現できませんでした。
ウインドウを拡大、移動などしてクリックしてみましたが、問題なくクリックされたピクセルが更新されました。
厳密にいえば、intで切り捨てしているので、クリック点の左上に1ピクセルずれた位置が塗りつぶされますが。

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import sys

class im:
    def __init__(self,image,fig,ax):
        self.image=image
        self.fig = fig # 追加
        self.ax = ax   # 追加

    def onclick(self,event):

        """ forループする手法
        plist = np.copy(self.image[int(event.ydata)][int(event.xdata)]) # 自身のピクセル値がかわらないようにディープコピーする!
        print(plist)
        h, w, c = self.image.shape
        for i in range(h):
            for j in range(w):
                if (self.image[i][j] == plist).all():
                    self.image[i][j] = [255, 255, 255]
        """

        # numpy一括操作する手法
        # python,OpenCV,numpyによる色抽出・変換
        # https://teratail.com/questions/100301
        plist = self.image[int(event.ydata)][int(event.xdata)]
        self.image[np.logical_and.reduce(self.image == plist, axis=2)] = [255,255,255]

        # 修正
        self.ax.imshow(self.image)
        fig.canvas.draw()
        #fig = plt.figure()
        #ax = fig.add_subplot(111)
        #ax.imshow(self.image)
        #plt.show()

# 画像を読み込む
img = Image.open( "./test.png") # 
img=np.array(img)

# pngのアルファチャンネルを除去する
if img.shape[2] == 4:
    img = img[:,:,0:3]

fig=plt.figure()
ax=fig.add_subplot(111)
c_event=im(img,fig,ax) # データと描画更新のためにfig,axを渡す

ax.imshow(img)
cid = fig.canvas.mpl_connect('button_press_event', c_event.onclick)
plt.show()


イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/10 22:48

    ウインドウの更新ができるようにしていただきありがとうございます。
    中途半端という表現はあまり良くなかったですね。申し訳ありません。
    追加で変更後の画像を投稿したいと思います。

    キャンセル

  • 2018/11/11 08:22

    追記への対応ありがとうございます。
    単純な代入だと参照渡しになっていたのが原因だったのですね。
    一括操作する手法も回答いただきありがとうございました。

    キャンセル

  • 2018/11/11 08:31

    そうですね、他言語での参照と同じ動作です。
    pythonでは、わりとひっかかりやすい罠です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.63%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る