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

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

新規登録して質問してみよう
ただいま回答率
85.35%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

1020閲覧

画像の各画素に対して任意の計算を行い、その結果をグレースケール画像として取得したい。

hikarota

総合スコア15

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2021/12/19 07:02

編集2021/12/19 12:01

前提・実現したいこと

画像の各画素に対して任意の計算を行い、その結果をグレースケール画像として取得したいです。

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

単純に以下のようにfor文で値を取得して計算していけば良いと思っていたのですが、各画素にアクセスするのは推奨されないと知りました。

python3

1img = cv2.imread("hoge.png") 2for x in range(640): 3 for y in range(480): 4 value = img[x,y] 5 value[0] = value[0] + 100 # 例えば 6 img[x,y] = value 7

そこで、どのような実装をするとよいのでしょうか?

追加

上記では

python3

1 value[0] = value[0] + 100 # 例えば

と記載してしまいましたが、正確には、

python3

1 value[0] = a(定数) * value[0] + b(定数) 2 if value[0] > c(定数): 3 value[0] = d(定数) - value[0]

という計算を行いたいです。情報が不足しておりすみません。
fourteenlength様やukyoda様にコメント頂いた方法で1行目の処理は実現可能と理解しましたが、
2行目のif等を各画素に対して行うにはどのような方法がありますでしょうか。
よろしくお願いします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikadzuchi

2021/12/19 09:50

「推奨されない」とはどこで得た情報ですか? ふつう何かを推奨しないときは代替の方法を示すものですが、そこには何か書かれてはいませんでしたか?
guest

回答3

0

ベストアンサー

行列の値を一括して操作するのであればNumpyがおすすめです。
OpenCVで扱う画像はグレースケール画像であればそのままNumpyの2次元行列として扱えます。
この辺が参考になると思います。リンク先のabが、ここでの質問においてはそのまま画像一枚や加算値として扱える感じです。

もう少し凝った計算であればガンマ補正cv2.addあたりで調べると使えそうな内容が出てくると思います。

どうしてもForを使ってNumpyの計算を早くしたいのであれば、Pythonの裏側で最適化を図るNumbaを検討ください。

追補1
OpenCVのグレースケールで表示させる場合、uint8の縛りがあります。計算した値を最後に0-255でスケールさせるか、計算結果が0-255からはみ出ないようにnp.clip()のような関数を使って無理やりはみ出た部分を切り落とす必要があります。
Matplottlibであればもう少し柔軟に対応できますが、表示までのラグやなんやらを考えるとちょっとうっとおしいですよね…。値が255を超えるようであれば、初めからuint8にすると桁落ちしてしまうので、uint16uint32にしたり、多少誤差も許されるのであればfloat16なんかでもいいと思います。なんにせよ負の数になりえるか、正の数だけでよいか、最大値がいくらか、で適当にtypecastを帳尻合わせしてください。

追補2

fourteenlength様やukyoda様にコメント頂いた方法で1行目の処理は実現可能と理解しましたが、

2行目のif等を各画素に対して行うにはどのような方法がありますでしょうか。
よろしくお願いします。

np.where()を使うと条件一致した値だけ処理できます。forのネストをぶん回す代わりに、まずval=ax+bのような計算をしてしまって、その後にvalが指定値より大きいところをnp.whereで抽出したらいいですね。リンク先の**「条件を満たす要素を処理」**のところがまんまこのやりたいことになると思います。

投稿2021/12/19 09:13

編集2021/12/19 14:38
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hikarota

2021/12/19 14:50 編集

ありがとうございます。 色々な関数があるのですね。勉強になりました。 教えて頂いた方法でやってみようとおもいます!
guest

0

単純に、「グレースケールに変換したい」という要件を満たしたいのであれば、cv2.cvtColorを使えばいいと思います。

一方で、ライブラリの関数ではなく、実際に計算してグレースケールを出したいのであれば、下記の通り書けばfor分使わずにグレースケールの画像を得ることができると思います。

python

1img_float32 = img.astype(np.float32) # 丸めが発生しないように、uint8からfloat32に変換した画像を作る 2gray_float32 = 0.2126 * img_float32[:, :, 2] + 0.7152 * img_float32[:, :, 1] + 0.0722 * img_float32[:, :, 0] 3gray = gray_float32.astype(np.uint8) # 最後にuint8型にする

投稿2021/12/19 09:02

ukyoda

総合スコア386

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

以下は Python ではなく、ImageMagick – Convert, Edit, or Compose Digital Images というツールを使う場合のお話なので参考程度にお読み下さい。

ImageMagick でも画素(正確にはカラーチャネル)に対する計算を行う事ができます。画素(カラーチャネル)の値は [0.0, 1.0] の範囲で正規化されていて、計算結果が範囲外になる場合は近い方の境界値になります。

例として a, b, c, d を以下の様に設定して変換してみます。

bash

1$ convert -version 2Version: ImageMagick 6.9.11-60 Q16 x86_64 2021-01-25 https://imagemagick.org 3 4$ a=1.2 b=0.1 c=0.8 d=1.6 5$ convert lena.png -fx $" 6 pixel = u * $a + $b; 7 pixel > $c ? $d - pixel : pixel 8 " lena_transform.png

左側が元画像、右側が変換後の画像です。
convert

投稿2021/12/19 15:07

melian

総合スコア20655

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問