🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

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

Q&A

解決済

2回答

4118閲覧

Python:画素の置き換えの処理の違いについて

grandchild

総合スコア10

Python

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

0グッド

0クリップ

投稿2021/01/17 02:22

編集2021/01/17 03:07
import numpy as np import cv2 import scipy.stats as sstats import matplotlib.pyplot as plt def func1(luv): l, u, v = cv2.split(luv.astype(int)) mode_l = sstats.mode(l[l.nonzero()])[0][0] mode_u = sstats.mode(u[l.nonzero()])[0][0] mode_v = sstats.mode(v[l.nonzero()])[0][0] luv[(mode_u - u)**2 + (mode_v - v)**2 < 3000., :] = [0, 0, 0] return luv def func2(luv): l, u, v = cv2.split(luv) mode_l = sstats.mode(l[l.nonzero()])[0][0] mode_u = sstats.mode(u[l.nonzero()])[0][0] mode_v = sstats.mode(v[l.nonzero()])[0][0] mode = np.array([mode_l, mode_u, mode_v], dtype=int) a = (mode - luv)**2 b = a[:, :, 1] + a[:, :, 2] c = (b >= 3000).astype(int) cs = np.stack([c] * 3, axis=2) luv = luv * cs return luv bgr = cv2.imread('bara.jpg') luv = cv2.cvtColor(bgr, cv2.COLOR_BGR2Luv) luvs = func1(luv) result_s = cv2.cvtColor(luvs, cv2.COLOR_Luv2BGR) cv2.imwrite("result_s.jpg",result_s) rgb = result_s[:, :, [2, 1, 0]] plt.imshow(rgb) plt.show() luvk = func2(luv) result_k = cv2.cvtColor(luvk, cv2.COLOR_Luv2BGR) cv2.imwrite("result_k.jpg",result_k) rgb = result_k[:, :, [2, 1, 0]] plt.imshow(rgb) plt.show() ```黒(輝度Lが0)以外の背景色に近い色(最頻値からの色の距離が小さいもの)を黒く塗るプログラムを作成しました。RGBについては、昨日質問させていただいて、お二人のご助言により計算速度を向上できました。今度はCIELuv空間で試みたところ、一つの方法(result_s.jpg)ではうまくいくのですが、もう一つの方法ではエラーが出てうまくいきません。result_k.jpgがきちんと出力できるよう、ご教示いただけないでしょうか? 入力画像と、成功した結果result_s.jpgはそれぞれ下画像のとおりです。 ![入力画像はこれです。](90dc77d46b83fe5fb464cca373ffd2d8.jpeg) ![result_s.jpgはこれです。](46fc7a95adb46a1e4beedad029df935c.jpeg) エラーメッセージはこれです。 Traceback (most recent call last): File "kirisaki3.py", line 38, in <module> result_k = cv2.cvtColor(luvk, cv2.COLOR_Luv2BGR) cv2.error: OpenCV(4.2.0) /io/opencv/modules/imgproc/src/color.simd_helpers.hpp:94: error: (-2:Unspecified error) in function 'cv::impl::{anonymous}::CvtHelper<VScn, VDcn, VDepth, sizePolicy>::CvtHelper(cv::InputArray, cv::OutputArray, int) [with VScn = cv::impl::{anonymous}::Set<3>; VDcn = cv::impl::{anonymous}::Set<3, 4>; VDepth = cv::impl::{anonymous}::Set<0, 5>; cv::impl::{anonymous}::SizePolicy sizePolicy = (cv::impl::<unnamed>::SizePolicy)2u; cv::InputArray = const cv::_InputArray&; cv::OutputArray = const cv::_OutputArray&]' > Unsupported depth of input image: > 'VDepth::contains(depth)' > where > 'depth' is 4 (CV_32S)

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

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

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

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

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

y_waiwai

2021/01/17 03:01

このままではコードが読めないので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
grandchild

2021/01/17 03:08

昨日初めて投稿した状態でコードの貼り付け方も知りませんでした。ご指摘ありがとうございました。
guest

回答2

0

昨日のご質問に回答した(func1 を提案した)者です。
エラーの解消については既に回答がついているので、こちらは「func1 と func2 の順番を入れ替えるとうまく動作した」ということの解釈となります。
実際にはコメント相当なのですが、コメント欄が柔軟ではないので回答欄を利用しております
(なのでこのコメントをベストアンサーにしないでください。)
あらかじめご了承ください。

昨日のご質問(https://teratail.com/questions/316337)で私が提案した処理方法 func1 は、入力 luv に対して 破壊的な操作を行っています
したがって、ご質問者様のコメントにある
「b>=3000だと結果は真っ黒画像となり、同じ処理をしているつもりが、異なる結果となりました。それを解決しようとFunc1とFunc2の順番を変えてみたところ、3000でも同じ結果となりました。」
というのは、次のように解釈できます:

  1. func1 を適用した時点で luv 自体の値が処理後のものに変わっている。
  2. func1 で値が変わってしまった luvfunc2 に入力したので func2 の結果は期待されるものとは異なってしまった。
  3. func2func1 の順番を入れ替えた場合、func2 の入力 luv は正しい値を持つため正しい結果が出力される。
  4. また、func2 は入力 luv を破壊しないため、その後に func1luv を入れても正しい結果が得られた。

次に、
「b>=3000ではなく、b>=0でうまくいった」
理由も func1 が破壊的な操作を行っていることに起因します。
func1 によって既に処理が行われているので b >= 0 でないと同様の結果が得られなかったということになります。
実際には、func2 を単体で使う分には b >= 3000 で問題ありません

<以下、詳しい理由と func1 の改善案です>
先述の通り、func1 は入力 luv に対して 破壊的な操作を行っています
(つまり入力値をその後の処理で使用しないことを想定しています。)
どういうことかというと、func1 の中で入力 luv を直接変更しているのです。
従って、func1 は処理後の luv を返していますが、実際には入力値の luv と同じオブジェクトを返しています。
以下のように id 関数によって luv オブジェクトの ID を確認すれば、入力 luv と戻り値 luvs の ID が一致していることが分かります:

Python

1def func1(luv): 2 l, u, v = cv2.split(luv.astype(int)) 3 mode_l = sstats.mode(l[l.nonzero()])[0][0] 4 mode_u = sstats.mode(u[l.nonzero()])[0][0] 5 mode_v = sstats.mode(v[l.nonzero()])[0][0] 6 7 print("id of luv before processing:", id(luv)) 8 luv[(mode_u - u)**2 + (mode_v - v)**2 < 3000., :] = [0, 0, 0] 9 print("id of luv after processing:", id(luv)) 10 return luv 11 12bgr = cv2.imread('bara.jpeg') 13luv = cv2.cvtColor(bgr, cv2.COLOR_BGR2Luv) 14 15print("id of luv before calling func1:", id(luv)) 16luvs = func1(luv) 17print("id of luvs:", id(luvs))
# 出力結果の例: id of luv before calling func1: 2085935722128 <- 入力値 `luv` の ID。 id of luv before processing: 2085935722128 id of luv after processing: 2085935722128 id of luvs: 2085935722128 <- 入力値 `luv` と同じ ID。

一方で func2 では入力 luv に対して 非破壊的な操作を行っています
(つまり入力値をその後の処理で使用できるようになっています。)
これは func2 の中で入力 luv に対して cs を掛けることで、その後に得られる luv は別のオブジェクトになっているからです。
このことも、入力 luv と処理後の luv および戻り値 luvk の ID が異なっていることから分かります:

Python

1def func2(luv): 2 l, u, v = cv2.split(luv) 3 mode_l = sstats.mode(l[l.nonzero()])[0][0] 4 mode_u = sstats.mode(u[l.nonzero()])[0][0] 5 mode_v = sstats.mode(v[l.nonzero()])[0][0] 6 mode = np.array([mode_l, mode_u, mode_v], dtype=int) 7 a = (mode - luv)**2 8 b = a[:, :, 1] + a[:, :, 2] 9 c = (b >= 3000).astype(np.uint8) 10 cs = np.stack([c] * 3, axis=2) 11 print("id of luv before processing:", id(luv)) 12 luv = luv * cs 13 print("id of luv after processing:", id(luv)) 14 return luv 15 16bgr = cv2.imread('bara.jpeg') 17luv = cv2.cvtColor(bgr, cv2.COLOR_BGR2Luv) 18 19print("id of luv before calling func2:", id(luv)) 20luvk = func2(luv) 21print("id of luvk:", id(luvk))
# 出力結果の例: id of luv before calling func2: 2085935721168 <- 入力値 `luv` の ID。 id of luv before processing: 2085935721168 id of luv after processing: 2085935854576 <- 入力値 `luv` と異なる ID。 id of luvk: 2085935854576 <- 入力値 `luv` と異なる ID(処理後の `luv` と同じ)。

func1 を非破壊的にしたい場合は、例えば次のように修正していただければいいと思います:

Python

1def func1_rev(luv): 2 luv = luv.copy() # <- ココを追加。copy() によって別のオブジェクトを作る 3 l, u, v = cv2.split(luv.astype(int)) 4 mode_l = sstats.mode(l[l.nonzero()])[0][0] 5 mode_u = sstats.mode(u[l.nonzero()])[0][0] 6 mode_v = sstats.mode(v[l.nonzero()])[0][0] 7 8 print("id of luv before processing:", id(luv)) 9 luv[(mode_u - u)**2 + (mode_v - v)**2 < 3000., :] = [0, 0, 0] 10 print("id of luv after processing:", id(luv)) 11 return luv

最後に、なぜ func1 が入力 luv を破壊したのかということですが、これは Python における参照渡しと値渡しという話題に関連します。
今回の件に関して言えば、func1 も func2 も numpy.ndarray の参照が渡されているため、その値を関数内で変更すると参照先の値も変わるのです。
詳しくは『Python 参照渡し 値渡し』などのキーワードで調べれいただければと存じます。

以上、長文失礼しました。

投稿2021/01/17 08:39

編集2021/01/17 09:31
Surpris

総合スコア106

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

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

grandchild

2021/01/17 09:02

その後に使用することを想定していなかったこと、理解いたしました。また、その修正方法までご教示いただきありがとうございました。順番を入れ替えたことでうまくいったように見えたので、上書きかな?とは何となく思ってはいたものの、何も追求せずに、別の勉強をしておりました。実際には私の何となくの想定は間違っており、ご指摘いただいたことで真実が分かったような気がします。そのようにidを調べる方法も知りませんでしたし、参照渡し、値渡しという言葉についても勉強になりました(しばらくそれをキーワードで検索して勉強してみたいと思います)。ありがとうございました。
guest

0

ベストアンサー

エラーの中身は
Unsupported depth of input image: 'VDepth::contains(depth)' where 'depth' is 4 (CV_32S)
であっていますか?
これはCV_32S(32ビット整数)をサポートしていないよ、というエラーです。
発生源は、result_k = cv2.cvtColor(luvk, cv2.COLOR_Luv2BGR)で、もう少し追うとc = (b >= 3000).astype(int)に行き着くはずです。

ここをc = (b >= 0).astype(np.uint8)に差し替えてください。うまくいくはずです。

投稿2021/01/17 05:10

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

grandchild

2021/01/17 05:36

fourteenlengthさん、貴重なご助言をありがとうございます。 コードは無事にエラーなく動きました。また結果も同じとなりました。大変、勉強になりました。 b>=3000ではなく、B>=0である理由が分からず、b>=3000だと結果は真っ黒画像となり、同じ処理をしているつもりが、異なる結果となりました。それを解決しようとFunc1とFunc2の順番を変えてみたところ、3000でも同じ結果となりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問