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

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

新規登録して質問してみよう
ただいま回答率
86.12%
Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

解決済

温度分布画像予測の誤差の単位を温度に対応させたい

Vamosj1VIVA
Vamosj1VIVA

総合スコア3

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

2回答

0リアクション

0クリップ

423閲覧

投稿2022/09/10 06:30

編集2022/09/17 01:02

前提

私はある温度分布を予測して、その出力が本来の温度分布とどれだけ誤差があるのか調べたいと思っています。今回は日本の陸地の温度を予測したいとします。添付する画像において上の画像が本来の画像、下の画像が予測した画像だとします。黒いところが26度、灰色のところが25度、非常に分かりにくいですがその右の薄い灰色を24度と考えてください。すると誤差があると思います。これが単位を温度としてどれだけの誤差があるのかを数値化しようと考えているのですが、その方法が分かりません。尚その誤差を出す時に、海の部分は誤差を出す際に計算に入れないようにして、陸地部分のみでの誤差を出したいです。その際に行き詰ってしまいました。

実現したいこと

下の2枚の画像において陸地部分の温度の誤差がどれだけあるか、誤差の単位を温度で出力する方法をご教示いただけますでしょうか。それには先ず黒いところが26度、灰色のところが25度、薄い灰色が24度であるという事を含めないといけないと思います。無知で大変申し訳ございませんが、よろしくお願いいたします。
*今回は一例として示す為に以下から画像を取得しました。
URL:https://www.jma.go.jp/jma/kishou/know/suikei_kishou/kaisetsu.html
この画像をグレースケール画像に変換したものを、添付した画像としています。この添付した画像での温度の誤差を示したいと考えてください。1番下の画像が2値化したものです(海を黒、それ以外を255にしただけで境界線等は黒のままです)
本来の画像

予測した画像

イメージ説明

発生している問題・エラーメッセージ

問題は上記に示した通りです。エラーはありません。

該当のソースコード

以下に2値化画像取得、及び誤差を求めるプログラムを示します。これが解決した際に訂正したコードです。
①2値化画像取得プログラム

Python

import cv2 import numpy as np from pylab import * #imshowが無いというエラー防止 img = cv2.imread("/content/drive/MyDrive/mask_before.png",0) ret, thresh = cv2.threshold(img, 168, 255, cv2.THRESH_BINARY)#1つめの数以上の画素値は2つ目の数の画素値にする thresh[thresh > 0] = 255 # 0以外は255に cv2.imwrite("/content/drive/MyDrive/mask.png", thresh)

②誤差を求めるプログラム

Python

import cv2 import os import numpy as np import matplotlib.pyplot as plt TARGET_FILE = 'target.PNG' #print(TARGET_FILE) IMG_DIR = os.path.abspath(os.path.dirname("__file__")) + '/drive/MyDrive/images/'#imagesフォルダの中にあるファイルが比較対象 print(IMG_DIR) #IMG_SIZE = (312, 312) target_img_path = IMG_DIR + TARGET_FILE #比較対象を足す target_img = cv2.imread("/content/drive/MyDrive/images/target.PNG",0) print(target_img) #target_img = cv2.resize(target_img, IMG_SIZE) #target_hist = cv2.calcHist([target_img], [0], None, [256], [0, 256]) #ヒストグラムを出す際に使う #target_img = int(target_img_origin) target_img[target_img <= 36] = 26 target_img[((target_img >= 37) & (target_img <= 139))] = 25 target_img[((target_img >= 140) & (target_img <= 224))] = 24 target_img[target_img >= 225] = 23 print('TARGET_FILE: %s' % (TARGET_FILE)) #%sは文字列出力に使う、ターゲットファイルはどのpngファイルか #img_diff = cv2.diff(TARGET_FILE, IMG_DIR) #diffで差分の計算を行う #plt.imshow(img_diff) #img_diff = cv2.cvtColor(img_diff, cv2.COLOR_BGR2GRAY) mask_img = cv2.imread("/content/drive/MyDrive/mask.png",0) print(mask_img) #Noneが返ってきたらファイルが存在していないので、これで確かめる mask_img[mask_img > 0] = 1 # 0以外は1に files = os.listdir(IMG_DIR) #ディレクトリとファイルの一覧を取得 for file in files: if file == '.DS_Store' or file == TARGET_FILE: continue comparing_img_path = IMG_DIR + file comparing_img = cv2.imread(comparing_img_path,0) comparing_img[comparing_img<=36] = 26 comparing_img[((comparing_img>=37) & (comparing_img<=139))] = 25 comparing_img[((comparing_img>=140) & (comparing_img<=224))] = 24 comparing_img[comparing_img>=225] = 23 img_diff = target_img.astype(int) - comparing_img.astype(int) print(img_diff.max()) print(img_diff.min()) print((img_diff * mask_img).sum() / mask_img.sum()) print(np.average(img_diff, weights=mask_img)) print(np.abs(img_diff * mask_img).sum() / mask_img.sum()) print(np.average(np.abs(img_diff), weights=mask_img))

試したこと

上記のコードを書きました。これを全体的にどれだけの温度の誤差があるのか(例えばこの2枚を比較した際に0.27788度誤差があるの様に)を出力する様にしたいと考えていました。この誤差は図全体での平均での温度誤差に対応します。つまり1つの数値のみ出れば良いという考え方です。
以下に実際に出力されたものを示します(printの部分を変えているので、出力が一部足りないところがあると思います。最終的な出力が最後の4つになります)。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
/content/drive/MyDrive/images/
[[ 0 90 37 ... 176 255 255]
[190 226 225 ... 176 255 255]
[226 1 146 ... 176 255 255]
...
[168 168 168 ... 164 255 255]
[168 168 168 ... 167 255 255]
[168 168 168 ... 188 255 255]]
TARGET_FILE: target.PNG
3
-3
[[ 0 0 0 ... 255 255 255]
[255 255 253 ... 255 255 255]
[255 0 2 ... 255 255 255]
...
[ 0 0 0 ... 2 254 255]
[ 0 0 0 ... 0 254 255]
[ 0 0 0 ... 255 255 255]]
0.10114034578226946
0.10114034578226946
0.21099301078391514
0.21099301078391514

補足情報(FW/ツールのバージョンなど)

言語:Python
環境:Windows10
ブラウザ:Google Chrome(Google Colaboratory)
*ノートパソコンです。全て最新バージョンです。プログラミング中はcolab以外のタブ、アプリは開いていません。
*急を要する為、こちらでも同じ質問をさせていただいています。しかし1週間近く経過しても回答が無かった為、teratailでも質問させていただいてます。https://ja.stackoverflow.com/questions/90923/%e6%b8%a9%e5%ba%a6%e5%88%86%e5%b8%83%e7%94%bb%e5%83%8f%e4%ba%88%e6%b8%ac%e3%81%ae%e8%aa%a4%e5%b7%ae%e3%81%ae%e5%8d%98%e4%bd%8d%e3%82%92%e6%b8%a9%e5%ba%a6%e3%81%ab%e5%af%be%e5%bf%9c%e3%81%95%e3%81%9b%e3%81%9f%e3%81%84

以下のような質問にはリアクションをつけましょう

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

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

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

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

適切な質問に修正を依頼しましょう。

fana

2022/09/12 02:24 編集

マルチポストである旨については,SO側でも述べておくべきではないでしょうか. こういう状況の場合,話が複数個所でばらばらに繰り広げられてしまうと面倒でしょうから 「ここでは回答こなかったから別の場所にも質問したんで,何かあったらそっちに書いてくれ」とか述べておくとか.(そういうのがSO的にOKなのかまでは知らんですが)
jbpb0

2022/09/12 02:48

場所(地点)毎に温度差は違いますけど、それはどうしたいのでしょうか? 場所別の温度差が欲しいのでしょうか? それとも、平均するとかして一つの温度差に換算したいのでしょうか?
Vamosj1VIVA

2022/09/12 11:10 編集

@fanaさん SOではOKです。不備を謝罪します。本日中に対応いたします。 @jbpb0さん 質問事項が不十分でした。申し訳ございません。平均して1つの数字を出したいです。 質問も修正しておきます。
jbpb0

2022/09/12 09:31

質問内容とは直接の関係はありませんが、画像ファイルがグレースケールでも、cv2.imread()はカラーのデータとして読み込むので、下記のように変更すればグレースケールとして読み込めます target_img = cv2.imread(target_img_path) ↓ 変更 target_img = cv2.imread(target_img_path, 0) comparing_imgも同様です
jbpb0

2022/09/14 04:12 編集

> 黒いところが26度、灰色のところが25度、非常に分かりにくいですがその右の薄い灰色を24度 質問の画像を見ると、それ以外に白いところもあるので、それを23度として、画像を拡大してよく見るとグレーの諧調は四つではなくもっと多いので、全ての諧調を含めて23〜26度の四段階に分けるには、たとえば下記のようにしたらできます (四つに分ける条件は、画像を見て適当に決めました) target_img[target_img<=36] = 26 target_img[((target_img>=37) & (target_img<=139))] = 25 target_img[((target_img>=140) & (target_img<=224))] = 24 target_img[target_img>=225] = 23 質問の画像は質問内容を説明するための例で、実際はグレーの諧調は三つしかないのでしたら、それに合わせて条件を変えてください 二つの(温度)画像データをどちらも上記のようにして23〜26度の四段階にしてから、それらの差を計算すれば、全ての場所での温度差が計算できます これを、「温度差データ」と呼ぶことにします 別途、陸が「1」、海が「0」である画像データを用意します これを、「マスクデータ」と呼ぶことにします 「温度差データ」に「マスクデータ」を掛け算すれば、陸の温度差はそのままで、海の温度差は「0」になります これを、「陸温度差データ」と呼ぶことにします (陸温度差データの合計) / (マスクデータの合成) を計算すれば、陸の温度差の平均になると思います なお上記は、画像内の文字付近や、右下のアイコンや、県境の線等は考慮してません 本当に処理したい温度画像に、そういった温度ではない何かがあるなら、それらを考慮しないといけないかもしれません ただし、両方の画像で共通なら、差には残らないので、気にしなくてもいいかもしれません 【追記】 マスクデータの合成 ↓ 訂正 (書き間違い) マスクデータの合計
Vamosj1VIVA

2022/09/12 13:20

@jbpb0さん 1件目について追加の情報ありがとうございます。 2件目について ・取り敢えず温度差データをつくるまではしてみました(間違ってるでしょうが)。ただ >、陸が「1」、海が「0」である画像データを用意します これを、「マスクデータ」と呼ぶことにします の意味を無知ながら私は理解できませんでした。この1と0は何を意味するのでしょうか?2進数で表してAND計算から陸温度差データが出来るのは分かるのですが、その用意方法が分かりません。 ・申し訳ございませんが、合計や合成についても大変分かりやすいご説明で、理解する事は出来ましたが、そのコードの書き方もあまり分かりません。プログラムで計算式等を今まで書く機会が無かったので、調べてもおっしゃっていただいたコードを書ききれる自信がありません。大変恐縮ではございますが、その部分もご教授いただければ幸いです。 以上の事を考慮し、質問文を大幅に修正させていただきます。コードも無茶苦茶ですが書けるところまで書きました。
jbpb0

2022/09/12 21:57

comparing_imgもtarget_imgと同様に、cv2.imread()で読み込んで、23〜26度の四段階にします そうしないと、target_imgとの差を計算できません
jbpb0

2022/09/12 21:58

target_imgとcomparing_imgの差を計算する際に、cv2.absdiff()では差の絶対値になってしまい、後で差の平均が計算できなくなります 最終的に欲しい平均値は、差の絶対値の平均ではなく、マイナスを含む差の平均ですよね? img_diff = target_img.astype(int) - comparing_img.astype(int) みたいにすれば、マイナスを含む差が計算できます 参考 https://note.nkmk.me/python-opencv-numpy-image-difference/ の「差分画像を算出し保存」の「差分の絶対値」
fana

2022/09/13 01:05

absたるべきか否かは目的次第ではないでしょうか. 「予測の精度」を示したいなら差が+1でも-1でも「誤差1度」と扱うというのもあり得るかと. (各所ですっごい誤差があっても全部合計したらプラマイ相殺して丁度0になれば「完璧な予測精度!」ってわけじゃないハズ)
fana

2022/09/13 01:14

> コードの書き方 なんだろう,teratail で観察してきた感じ,python使ってる人って,なんかわからんけど「ちょろっと1行とか書けば画像全体に対して全部やってくれるような書き方」みたいなのしか受け付けない! 的な傾向が強い感じ. こんなの自前で2重ループでも書いて全画素走査したらダメな理由あるの? 画素値にアクセスする手段さえあれば全画素について引き算して…っていうのを書くだけちゃうんかと. (それだと「速度がどうの」とか言うのかもだけど,早かろうが遅かろうが所望の結果が得られないなら意味ないわけで,「処理効率MAXな書き方」の模索は後で好きなだけやるとして,最初は原理確認のためにさっさと自明なコード書いて動かせばよくね? みたく思う)
Vamosj1VIVA

2022/09/13 02:07 編集

@jbpb0さん 1件目について、凡ミスでした。申し訳ございません。 2件目について、後のfanaさんのお話とも被るのですが、一旦私が想定したマイナスを含む差を計算出来る様にプログラムを修正しました。質問文に掲載しているコードで、一先ず温度差データは取得出来るということでしょうか? @fanaさん 1件目について、当初はマイナスを含む差を想定していましたが、貴方のコメントから確かに精度の誤差を出すならその方が良いという事に気づけました。ありがとうございました。つきましては一旦はjbpb0さんのパターンで理想とする出力を出してから、そちらの誤差も出せる様に改良したいと思います。 2件目について、私は効率重視なコードを書く気はありませんし、その技術もありません。原理から理解して確実に動作するプログラムを書きたいと思います。貴方と同意見です。ただ情けない事に完全な独学で学んでいる為、自明なコードを書きたくても書けないという現実があります。それは過去に指摘されました。反論の余地はありません。
fana

2022/09/13 02:36

例えば1次元のデータ {10, 5, 3, 8, 9} と { 9, 5, 4, 10, 7 } について本件で言ってるようなことをやるとしたら, 各所の誤差 = { 10-9, 5-5, 3-4, 8-10, 9-7 } って話だよね(各要素の差を取ってるだけ). python知らない人からしたら,for か何かでループで書けばいいじゃん,って思うんだけど. (…ってだけの話)
jbpb0

2022/09/13 11:53

> 質問文に掲載しているコードで、一先ず温度差データは取得出来るということでしょうか? まずは自分で実行してみましょうよ それでエラーが出たら、どうしたらいいのか一旦は考えてみましょうよ 以下、当方で実行した結果です なお、温度画像ファイルは、質問の二枚の画像ファイルをダウンロードして使いました カッコの書き忘れが二ヶ所あってエラーになったので、それぞれ直しました 「mg_diff = cv2.diff(...」の行がエラーになったし、要らないので削除 (この行の意図不明) 次の「plt.imshow(img_diff)」もエラーになったし、要らないので削除 ダウンロードして使った質問の二枚の画像ファイルの解像度(縦横の画素数)が一致してなくて、温度差の計算がエラーになったので、温度差の計算の前に解像度を合わせました (本当の温度画像ファイルは全部同じ解像度なら、そういうことは要りませんけど) この状態でエラーは出なくなりましたが、温度差の計算が(インデントが無いので)forループの外なので、forループの一番最後の「comparing_img」だけしか温度差が計算されません forループの毎回で温度差を計算したいのなら、「img_diff = target_img.astype(...」からの三行もインデントを合わせてforループの中に入れる必要があります
jbpb0

2022/09/13 12:19

マスクデータ用の画像ファイルは、いろいろ作り方は考えられますが、たとえば https://www.gridscapes.net/AllRiversAllLakesTopography のような、海の色が陸の色と違っていて、文字が無い地図画像から加工するという手があります 海の色のところのデータを「0」に、それ以外の色のところのデータを「1」に置き換えてから、グレースケール画像に保存します ただし当然ですが、地図から、温度画像ファイルと同じ地点の範囲を切り出す必要があります また、温度画像ファイルと同じ解像度(縦横の画素数)で保存する方がいいでしょうね 以上は、こんな方法もあるという紹介で、積極的に勧めてるわけではありません 他にも、地図画像をペイントアプリで塗るとか、いろいろ方法はあるので、質問者さんご自身でいいと思う方法を選択してください
fana

2022/09/14 01:54

とりあえずここでは「入力は画像」っていう前提での話が繰り広げられていますが,SOの方に「そもそも温度データをそのまま扱ってればいいよね常考」みたいなコメントも来ていますね. どんな背景事情があるのかはわかりませんが,画像の元になった温度データが存在する(手に入る/利用可能である)のであれば,全くその通りだと思います. 何らかの予測手段があってその精度を語るという目的(なんだよね?)に対して,わざわざ何かしらの離散化/標本化 が成されてしまった結果のデータ(:画像)から出発する意味があるのか?(というか,それは妥当な方法なのかい?)っていう根本的な話は大丈夫なんですかね? 大丈夫じゃないなら,画像を入力とするということ自体を考え直す必要があるのかもしれない.(この場としては「それはそれとして,もしも画像が入力だったならば…」という話を続けることはできるのですが,あなたは「急を要する」とのことですので…)
Vamosj1VIVA

2022/09/14 02:54 編集

@fanaさん 多忙であった為、順に返信させていただきます。 1件目について、その通りです。しかし私はPython以外を扱った事は無いので、どうにかPythonでコードを書きたいと思っています。 2件目について、本来私が使っているものも画像になります。よって私は予測する前のデータも画像であり、数値データは一切ありません。そして実際に扱いたい画像も今回の気象庁のデータと似たものになります(ただ代わりのデータを示しているだけです)。SO側での回答者の趣旨は理解していなかったので、後ほど回答者に補足したいと思います。 後おっしゃる通り、非常に急いでいるのでfanaさんやjbpb0さん等が迅速に返信いただける事に感謝しております。今後ともよろしくお願いいたします。 @jbpb0さん 1件目について、自分で実行してそのエラーに対処中である旨を示すのを忘れており、申し訳ございません。現在エラーの対処をしているところです。修正箇所についても承知いたしましたので、修正加えたいと思います。 2件目について、私の方で別途プログラムを作成し、2値化画像を生成致しました。後ほど質問文に加えます(ただ海のところを0、それ以外を255にしただけでキレイにはなってませんが)。その後の処理について、不明な点があればご連絡しますので、何度も繰り返しすみませんがよろしくお願いいたします。
fana

2022/09/14 02:49 編集

(1) 返信速度とかに何か義務があったりはしないので,変にあやまる必要は皆無かと. (2) 画像が出発点である旨,把握. (3) python にも for くらいあると思うけど,それはそれとして,うまく進んでいるならそこの話は無視してくれてOK(元々,「何もコード書けなくて止まっているなら…」っていうような話なので) (4) 書いたコードの動作結果,ちゃんと見てますか? 実際に各所の温度が「あるべき値」として得られているのか? 等は確認すべし. 差分を取ったなら,差分値も同様に確認すべし(例えば結果がプラスもマイナスもあり得るなら,どっちもちゃんと取れているのかを見るとかはする). とにかく各処理ステップが問題ないのかどうかを必ず確認して固めていくべき. > 温度差データ取得までを書いたつもりです という言い方だと,読み手も「で,ちゃんと動くん?」ってなる. ちゃんと確認が取れているなら「温度差データの取得まではできた」と述べるのが良いかと.
Vamosj1VIVA

2022/09/14 02:53

(1)~(3)に関して承知いたしました。 (4)についてエラーの対応が完了していない為、完了次第述べます。現時点では「温度差データのコードは書いているが、エラーメッセージの為取得まで出来ていない」状態です。どうしても分からない場合は返信します。ただおっしゃる通り、確実に値が取られているか?という点の確認はしていきたいと肝に銘じておきます。いつもありがとうございます。
jbpb0

2022/09/14 03:12

> 海のところを0、それ以外を255にしただけでキレイにはなってませんが 質問の3枚目の画像は、拡大してよく見ると、「0」(真っ黒)と「255」(真っ白)ではないグレーもあります また、右下のアイコンのところ、左上と下の文字のところ、県境に余計なものがあります 本当のデータを処理する時に用意するマスクデータ用の画像ファイルは、そこらへんを全部ちゃんとしたものを用意するのですよね? (この質問にその画像を掲載する必要はありませんけど)
Vamosj1VIVA

2022/09/14 03:25 編集

グレーになる件は自分自身もよく分かりません。後でコードも載せますが、何故白と黒以外が出力されるのは不明です。現状軽い誤差として見ていますが、正式なデータだと考慮する必要があるかもしれません。 実際のデータはアイコンや文字は省きます。陸地と海の境目の境界線のみ残しますが、2値化で黒くする予定です。 あとこの後の処理なのですが、温度差データは数値(エラー対応が終わってないので出力は出来てませんが)、マスクデータは画像になると思いますが、これの積ってどの様なコードになりますか?画像同士や数同士の乗算はわかるのですが・・・。度々申し訳ございません。出力が数字になる事は予測出来るのですが・・・。
Vamosj1VIVA

2022/09/14 03:40

つまりマスクデータも読込した結果としては数値になるという事ですね。 後マスクデータの合成とは何を意味するのでしょうか?マスクデータと温度差データを乗算したものは陸温度差データですよね。話が理解できなくてすみません。
jbpb0

2022/09/14 03:40

> 正式なデータだと考慮する必要があるかもしれません。 海が「0」、陸が「255」の画像ファイルをpythonに読み込んでから255で割れば、海が「0.0」、陸が「1.0」のマスクデータとして使えますが、陸にグレーがあると255で割ったら0.0と1.0の間の値になり、それを温度差に掛け算すると、グレーだった地点の温度差が変わってしまいます(0.0にはならないけど小さくなる)
Vamosj1VIVA

2022/09/14 03:42

承知いたしました。後程2値化した際のコードも示します。
jbpb0

2022/09/14 03:42

> マスクデータの合成とは何を意味するのでしょうか? マスクデータの合成 ↓ 訂正 マスクデータの合計 書き間違いです ごめんなさい
Vamosj1VIVA

2022/09/14 03:44

いえいえ、長文を書いていただいているのでむしろ申し訳ない気持ちです。しかしマスクデータは1枚という認識なのですが、合計というのはどういう事なのでしょうか?
fana

2022/09/14 04:04

(マスク画像自体は「十分に黒い / 十分に白い」になってさえいれば,プログラムで読み込んでから二値化処理噛ませれば良いんじゃない? 閾値を 255/2 付近にでもして.)
jbpb0

2022/09/15 02:14 編集

> マスクデータは1枚という認識なのですが、合計というのはどういう事なのでしょうか? 2次元配列の値を全部足す、という意味です マスクデータの合計は、陸が何画素あるか、になります
Vamosj1VIVA

2022/09/14 04:08 編集

@fanaさん 承知いたしました。 @jbpb0さん >(陸温度差データの合計) / (マスクデータの合計) これにおいてマスクデータの合計は別に求める必要があり、別のプログラムが必要という事ですか?
fana

2022/09/14 04:10

CVの関数でいいなら,countNonZero() あたりを使えばいいんじゃない?
jbpb0

2022/09/15 02:15 編集

> マスクデータの合計は別に求める必要があり、別のプログラムが必要という事ですか? 「mask_img」が0, 1のマスクデータだとして、 mask_img.sum() で合計になります 陸温度差データも同様に、変数名の後ろに「.sum()」を付ければ合計になります
jbpb0

2022/09/14 04:24

質問の3枚目の画像のグレーは、県境とか陸と海の境とかの黒線が真っ黒になり切れてなくてグレーが混在してるので、グレーの地点も全部陸としていいようなので、画像の「0」(真っ黒)だけそのまま(海)にして、それ以外(1〜255)は全部陸(1)にしてしまう、のでもいいみたいです (アイコンや文字のところは別途何とかするとして)
fana

2022/09/14 04:41 編集

(sum なんていう便利なのがあるのなら他にも便利なのがあるのかな?と,素人がググってみた感じ,average なる加重平均を計算する手段があるっぽい? ← そしたらマスク範囲の平均値計算はこいつにマスクを重みとして渡せばいいだけか?) …と,あとは言語とライブラリに関する書き方の話になってきそうだから退散するにゃん. ノシ
Vamosj1VIVA

2022/09/14 04:37

@fanaさん わざわざありがとうございます。調べてみます。 @jbpb0さん 1件目について、承知いたしました。 2件目について、1以上はすべて255にする様にしたのですが、それでも見た感じ何も変わってなさそうです(一応質問文の2値化画像はやり直したやつに変えました・・・)。
jbpb0

2022/09/14 04:54

> average なる加重平均を計算する手段があるっぽい? ← そしたらマスク範囲の平均値計算はこいつにマスクを重みとして渡せばいいだけか?) 確かに! print(np.average(img_diff, weights=mask_img)) # 温度差の絶対値の平均にしたい場合 print(np.average(np.abs(img_diff), weights=mask_img))
jbpb0

2022/09/14 05:45

マスクデータ画像のグレーの暫定対策 mask_img = cv2.imread(mask_img_path,0) mask_img[mask_img > 0] = 1 # 0以外は1に 本番用のマスクデータ画像を作ったら、全てのグレーを陸扱いしてもいいのかは、その画像で確認してください
jbpb0

2022/09/14 05:48

マスクデータ画像を他の画像と同じ「IMG_DIR」に置くなら、forループの先頭のifの条件にその画像名も追加しないとダメですよ
Vamosj1VIVA

2022/09/14 23:48

1件目と3件目について、承知いたしました。取り敢えずコードを考えてみます。 2件目について、1にすると全て真っ黒の画像になってしまったので、255にすると以前と変わらない県境がそのまま残る画像になってしまいました(質問文の画像もそれに変更しています)。
jbpb0

2022/09/15 00:28 編集

上のコメントで > mask_img = cv2.imread(mask_img_path,0) mask_img[mask_img > 0] = 1 # 0以外は1に と書いた意図は、マクスデータ画像を作る時の話ではなくて、グレーを含む画像を読み込んでからマスクデータとして使う直前にそれをやって0, 1だけにする、という話です でも、画像を作るコードの、画像ファイルを保存する直前に mask_img[mask_img > 0] = 255 # 0以外は255に みたいなのを追加したら、0, 255だけになるはずですけど、 > 255にすると以前と変わらない県境がそのまま残る画像になってしまいました ですか > 1にすると全て真っ黒の画像になってしまった 1もほぼ黒なので、画像を見ても分かりませんよ マスクデータ画像は目視確認をしたいなら、0, 1ではなく0, 255で作って、その画像を読み込んでマスクデータとして使う前に mask_img[mask_img > 0] = 1 # 0以外は1に として0, 1にしたらいいです 【追記】 > 255にすると以前と変わらない県境がそのまま残る画像になってしまいました 質問の3枚目の画像を確認したら、グレーは無くなってました 県境の有無と、グレーの有無は、無関係です
Vamosj1VIVA

2022/09/15 00:32

はい、全ての意図を汲み取っていました。マスクデータを保存する前に0、255だけにして保存し、その後保存したマスクデータを読み出す際は0以外を1にする処理を行いました。書き方悪くてすみません。 グレー無くなってたんですね。確認が疎かでした。県境も邪魔ですが今回は無視するしか無いですね。
Vamosj1VIVA

2022/09/15 00:42

追加なのですが加重平均という私も知らなかったのですが、これを使うという事は温度差データとマスクデータを使って温度誤差を出すという手法になるのですか?そうすると陸温度差データ(温度差データとマスクデータの積)をわざわざ求める必要が無いということでしょうか?一応陸温度差データを求めるコードは下の様にしたのですが・・・。 img_multiply = np.multiply(img_diff,mask_img) print(np.multiply(img_diff,mask_img))
jbpb0

2022/09/15 01:04

> 陸温度差データ(温度差データとマスクデータの積)をわざわざ求める必要が無いということでしょうか? そうです 下記の結果は一致するはずなので、確認してみてください print((img_diff * mask_img).sum() / mask_img.sum()) print(np.average(img_diff, weights=mask_img)) # 温度差の絶対値の平均にしたい場合 print(np.abs(img_diff * mask_img).sum() / mask_img.sum()) print(np.average(np.abs(img_diff), weights=mask_img)) どちらを採用するのかは、お好きな方で
fana

2022/09/15 02:13 編集

> 加重平均 っていう話のせいで無意味に混乱させてしまったならSorry(と言うためだけに一瞬だけ復帰). だけど… 正直,そのくらいの算数の部分は自分で考えられないとマズい気もするよ. マスクについては( bool な意味のものとして用いるのではなく)マスク画像の画素値そのものを用いた計算をするのであれば,それは「マスク」と呼ぶよりも「重み画像」とでも呼ぶべき物になるから,「0と 0でない値」という2値なデータにさえなっていれば「0でない値」の方は何でもいいよ. (私は bool な側で考えちゃってたから↑の方では countNonZero() とか書いてたけど.現在,話は画素値そのものを乗じたり合計したりする形で話が進んでいると見える)
jbpb0

2022/09/15 02:33 編集

> 県境も邪魔ですが今回は無視するしか無いですね。 質問の1枚目の画像だと、海のほとんどは「168」なので、これから作るなら、たとえば mask_img[((mask_img != 167) & (mask_img != 168))] = 255 mask_img[((mask_img == 167) | (mask_img == 168))] = 0 のようにしたら、県境はだいぶ消えます 陸と海の境目のグレーの画素のほとんどが陸扱いになるので、陸が実際よりもちょっと太ってしまいますが (質問の3枚目の画像も、そこは同じ) 本当に処理したい温度画像の海が「168」かどうか不明なので、本番画像で上記でうまくいくかどうかは分かりません なので、これはご参考程度に
jbpb0

2022/09/15 02:36

> 「0と 0でない値」という2値なデータにさえなっていれば「0でない値」の方は何でもいいよ. 確かに!! 1.0じゃなくても、平均の計算で約分されて消えますね
Vamosj1VIVA

2022/09/15 03:20

@fanaさん いえ、とても貴重なお話ありがとうございます。やはりコードを書く者として今後計算等の原理も理解していかなくてはならないと思っているので、もっと今後勉強していきたいと思います。 @jbpb0さん 1件目について、一応どちらも出力させてみる事にします。 2件目について、おっしゃる通り実際に扱う図に県境は無いのですが、そうした図を扱う際に参考にさせていただきます。 温度差データを取得する際のエラーが改善できていない為、コードの確認はせずに一通り質問文に掲載しておきます。温度差データのエラーについては今日中に修正し、出力を出せる様にします。その他、何かありましたら又ご連絡します。
jbpb0

2022/09/15 03:31

comparing_img[comparing_img>=225] = 23 までと、 img_diff = target_img.astype(int) - comparing_img.astype(int) 以降が、インデントが違いますよ (スペースの数が)
Vamosj1VIVA

2022/09/15 14:13

承知いたしました。 以上全ての事を踏まえて動作させると、無事に出力まで辿り着ける事が出来ました!本当にありがとうございました。コード、及びその結果を質問文に掲載させていただきます。実際のデータを使っても検証しますので、ベストアンサー等はもうしばらくお待ちください。
Vamosj1VIVA

2022/09/16 09:23 編集

実際のデータで試してみたところ、温度誤差が8度という訳の分からない事になってしまいました。何故かというと定義では16〜20度までしか定義してないはずなのに、4度以上の誤差になる事は本来有り得ないからです。 確認なのですが、jbpb0さんが書いていただいた、4階調に分けた際の37以上139以下で25度等の37や139はグレースケールでの画素値の事ですよね?
jbpb0

2022/09/16 09:40 編集

そうです ただし、その数値は質問の画像から決めたものなので、本番の画像では画素値いくつが何度か、という関係はそれとは違うでしょうから、本番の画像で決め直してください でも、そこが違ってても、元のグレースケールの画素値が整数ならば、画素値がいくつであっても23, 24, 25, 26のどれかにしかならないのだから、引き算しても最大で±3にしかなりませんよね 「-240」になることはあり得ないと思うのですけど 引き算して「-240」になるのが画像の(というか、二次元配列の)どこかを探して、その場所の元のグレースケールの画素値がいくつで、23〜26に変換した(はずの)後の値がいくつかを、target_imgとcomparing_imgのそれぞれで確認してみてください なお、もしグレースケール画像の画素値が整数ではなくて不動小数点の場合は、23〜26に変換するところのコードをちょっと変える必要があります 【追記】 数値が変わってますが、やることは同じです まずは、8度差になる場所の、引き算直前のtarget_imgとcomparing_imgの値を調べる 少なくともどちらかは、16〜20ではない数値になってるはずですよね 次に、16〜20ではない数値になってる方の、その場所のグレースケール画像を読み込んだ時の画素値を調べる そして、グレースケール画素値→16〜20の変換の条件に間違いがないか、調べる 間違いがなければ、16〜20ではない数値にはならないはずですよね
Vamosj1VIVA

2022/09/16 11:55

・勿論、本番の画像では温度、画素値の関係は異なるので、全て対応させました(因みに本番の画像では23~26ではなく、16~20度に対応させました)。 ・誤差の範囲ですがおっしゃる通りで、質問文のものでも±3度に収まっていました。これを超えるのは明らかに可笑しいですよね。 ・画素値を全て16~20に対応させた直後の配列をprintで出力させましたが、target_imgとcomparing_imgのどちらも16~20に変換されていました。 ・画素値は整数です。 ・後、現在ではimggの引き算が最大値が222、最小値がー222になっています。どちらも16~20同士で引き算しているのに、何故±222なのか・・・。 ・最後ですが現状の温度差の平均は8度、絶対値の誤差が11度となっています。
jbpb0

2022/09/16 15:03

forループ内の img_diff = target_img.astype(int) - comparing_img.astype(int) のすぐ下に idx = np.unravel_index(np.argmax(img_diff), img_diff.shape) print(idx) を(インデントを合わせて)追加して、引き算後に最大値「222」になってる座標を確認してください 参考 https://note.nkmk.me/python-numpy-argmax-argmin/ の「二次元配列(多次元配列)の場合」の「全体の最大値のインデックス(座標)」 さらに、そのすぐ下に下記を(インデントを合わせて)追加して、その座標の引き算前後の値を確認してください print(target_img[idx]) print(target_img.astype(int)[idx]) print(comparing_img[idx]) print(comparing_img.astype(int)[idx]) print(img_diff[idx]) print(target_img.astype(int)[idx] - comparing_img.astype(int)[idx]) print((target_img.astype(int) - comparing_img.astype(int))[idx]) どれが想定外の値でしょうか?
Vamosj1VIVA

2022/09/16 15:20

すみません。ファイルとかコードとかを少しいじったら解決しました!実際に出力された誤差は2度でした(条件も細かくして13~20度としたので、imggの引き算も20-13=7より、ちゃんと±7になりました!これで本当に解決しました!明日以降、ベストアンサー等も含めて感謝の言葉述べさせてください!
jbpb0

2022/09/16 15:57

> mask_img = cv2.imread("/content/drive/MyDrive/mask.png",0) print(mask_img) #Noneが返ってきたらファイルが存在していないので、これで確かめる mask_img[mask_img > 0] = 1 # 0以外は1に は、forループの繰り返しの毎回で全く同じ処理しかやってないので、forループよりも前に出せますよ
Vamosj1VIVA

2022/09/17 00:54

確かにそうですね。forより前に出しても出力は変わりませんでした。これで全て解決です! 改めてですがここのコメントで多くのご助言いただいたjbpb0さん、fanaさん本当にありがとうございました。ここまで親身になって、未熟な私に厳しくも親切に教えていただき感謝申し上げます。私が勉強と経験不足なばかりに、かなりご負担とお時間があったと存じます。以下にメンションとして個別に御礼させてください。 @jbpb0さん ここまで詳しくコードの説明や効率化、原理についてご教示いただけたのはどのサイトでも始めてです。ベストアンサーとさせていただきたいのですが、回答ではなくコメントでのご教授だったので、今回はお許しください。 @fanaさん 何故こんな事もできないのか?と何度も思われたでしょうが、それでも様々な知識をいただきありがとうございました。おかげでコードの実用性も上がりました。貴重なお時間を頂きましてありがとうございました。ベストアンサーとさせていただきます。
fana

2022/09/17 02:10

> できないのか? 途中でちょろっと書いたけども,「できる/できない」という言葉を用いて同じことを言うならば, 【「できる/できない」という程度の影響が最も小さいであろうやり方で,とりあえずやってみてしまえばいいのに】と思った. 特に,本件は,「そもそも何を計算すればいいのか?」という状態から始まっており,途中から「平均」を求めることになったけども,それが本当に妥当なのか?ということが確定しているように思えない状況だったので,とにかくさっさと計算値を出してみて実際の値を見るなり(誰か判断できる者に示すなり?)する必要があるだろうと.そのような状況だとすれば,「平均値だと微妙とか足りないとかダメだよね」とかいうことになったならば,また別の指標値を計算する実装をするステップに戻る必要があるのだろうし. で,「自前で全画素走査するループを書く」形ってのが,おそらくは言語自体や使っているライブラリなどに関する学習コストを最も必要としない形であろう,と. ・自分が使う言語でループを書ける,という最低限の言語文法 ・画像から画素値を得る,というライブラリの最低限の使い方 ・(あとは「平均値の計算の仕方」という算数) だけがあれば書けるので.
fana

2022/09/17 02:26 編集

そもそもあなたが予測誤差を求めねばならない理由もこちらには不明なので,なんとも言えないのだけど,そこらへんの背景事情次第では > 「平均値だと微妙とか足りないとかダメだよね」とかいうことに なるんじゃないかなぁ,とか思う. (もちろん平均も1つの指標値ではあるだろうけど,それだけでは何かを分析するには不足すぎるのではあるまいか,と. 例えば, 数箇所だけ「ここは1000度です!」とかいうぶっ飛んだ予測を出してしまうけど他の箇所はすっごいOKな予測器 と 全体的に±1.5度程度の誤差がコンスタントに出ちゃう予測器 とがあったとき,平均値を見たら同じかもしれないよね.そしたら,この2つを比較して優劣を語る必要が生じたならば何か別の指標をひねり出すしかないよ.)
jbpb0

2022/09/21 03:13 編集

「2値化画像取得プログラム」ですが、「0」(真っ黒)以外は全て「255」(真っ白)にしていいのなら、 ret, thresh = cv2.threshold(img, 168, 255, cv2.THRESH_BINARY) ↓ 変更 ret, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY) とすれば、「0」(真っ黒)以外は全て「255」(真っ白)になるはずなので、次の行の「thresh[thresh > 0] = 255」は要らないと思うのですが また、「cv2.threshold()」の行のコメントに「1つめの数以上の画素値は2つ目の数の画素値にする」と書いてますが、上記の変更(次の行も無くして)をして実行したら分かると思いますが、「1つめの数以上の」ではなく、「1つめの数より大きい」とか「1つめの数を超える」とかです 上記変更後のコードのように「0」を指定してる場合、「0」は「255」にはならず「0」のままです 参考 https://pystyle.info/opencv-image-binarization/#outline__4_1 の「基本的な使い方」 ググると、「以上」って書いてる解説が結構多いですけど 【追記】 「cv2.threshold()」で「168」を指定してるのは、画像の海の画素値が「168」だからですね 上記のコード変更は、スルーしてください 失礼しました
Vamosj1VIVA

2022/09/23 05:24

承知いたしました。確かに以上と書いている文献が多いですよね。ありがとうございました。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

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

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。