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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

Python

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

Q&A

解決済

1回答

5931閲覧

Python3 画像の白い部分を黒く塗りつぶしたい

SuzuAya

総合スコア71

Python 3.x

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

Python

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

0グッド

0クリップ

投稿2019/06/03 12:26

前提・実現したいこと

自作のデータセット(白黒画像25000枚)の中に、画像の端が見切れて白くなってしまっているものが複数枚あるため、その部分を黒く塗りつぶしたいと考えております。
以下のサイトを参考に、画像の白の領域を切り取って、黒で補完できれば良いのではと考えたのですが、以下のようなエラーが発生し、また、画像には何の変化もありませんでした。

お手数をおかけしますが、コードをどのように修正すればうまくいくかご教示いただけないでしょうか。
どうぞよろしくお願い致します。
http://sh0122.hatenadiary.jp/entry/2017/10/17/220447

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

<ipython-input-16-1e94062ab931> in <module>() 25 26 # 白の領域をカット ---> 27 masked_img = cv2.bitwise_and(img, mask_white) 28 29 # 切り取った部分を黒で補完 error: OpenCV(3.4.3) /io/opencv/modules/core/src/arithm.cpp:225: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function 'binary_op'

該当のソースコード

Python

1import cv2, matplotlib 2import numpy as np 3import matplotlib.pyplot as plt 4 5white_min = np.array([255, 255, 255], np.uint8)# ここがよくわかりません 6white_max = np.array([255, 255, 255], np.uint8)# ここがよくわかりません 7 8img = cv2.imread('NORMAL_resize_100_1_0506/NORMAL-9615869-4_resized.jpeg') 9img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 10plt.imshow(cv2.cvtColor(img_hsv, cv2.COLOR_HSV2RGB)) 11 12# 白の領域のマスクを取得 13mask_white = cv2.inRange(img, white_min, white_max) 14 15# 白の領域をカット 16masked_img = cv2.bitwise_and(img, mask_white) 17 18# 切り取った部分を黒で補完 19masked_replace_black = cv2.addWeighted(img, 1, cv2.cvtColor(mask_white, cv2.COLOR_GRAY2RGB), 1, 0) 20 21plt.imshow(cv2.cvtColor(masked_replace_black, cv2.COLOR_BGR2RGB)) 22 23plt.show()

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

google colabを使っています。

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

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

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

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

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

guest

回答1

0

ベストアンサー

The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function 'binary_op'

bitwise_and に渡した第1引数と第2引数がおかしいというエラーです。
cv2.bitwise_and(img, mask_white) において、img, mask_white の型及び形状は一致していますか?

python

1# これが成り立つことが前提 2img.shape == mask_white.shape and img.dtype == mask_white.dtype

カラー画像のある色を置換したい場合

inRange() は画像の色がある範囲内かどうかで2値化する関数なので、白 (255, 255, 255) を黒 (0, 0, 0) にしたいだけであれば、以下のコードでよいです。

イメージ説明

python

1import cv2 2 3img = cv2.imread("test.png") 4 5# 白 (255, 255, 255) のピクセルを取得する。 6white_pixels = (img == (255, 255, 255)).all(axis=-1) 7# 白のピクセルを黒 (0, 0, 0) にする。 8img[white_pixels] = (0, 0, 0) 9cv2.imwrite("output.png", img)

イメージ説明


不明な点等あればコメントしてください。

追記

ほんの少し白い部分が残ってしまったものの、

厳密に白 (255, 255, 255) でなく、白っぽい色は全部塗りつぶしたいということであれば、inRange() で色の範囲を指定してください。

周辺の色の情報を取得し、それと同じ色で画像の穴あき部分を塗りつぶす、ということができると以前何かのサイトで見かけた気がするのですが、どうしてもうまく検索できません…。

少し複雑になりますが、以下の手順でできます。

1. inRange() で白っぽい色かどうかで2値化する。

python

1white = cv2.inRange(img, (250, 250, 250), (255, 255, 255))

(250, 250, 250) <= (b, g, r) <= (255, 255, 255) の画素は255、そうでない画素は0の2値画像を作成される。

解説: OpenCV - inRange による範囲指定で2値化する方法について

イメージ説明

2. 白っぽい色に隣接する画素を取得する。

先程作成した2値画像を膨張処理し、膨張後 - 膨張前と差分をとることで、白っぽい色に隣接する画素を取得できる。
]

python

1# 膨張処理を行う。 2kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) 3dilated = cv2.dilate(white, kernel) 4 5# 膨張後 - 膨張前 = 白に隣接するピクセル 6adjacent = cv2.subtract(dilated, white)

解説: OpenCV - モルフォロジー演算について

イメージ説明

3. 隣接する画素から適当に1つ色を取得し、その色で白っぽい色の画素を塗りつぶす。

python

1# 白に隣接するピクセルの色を取得する。 2adjacent_colors = img[np.where(adjacent == 255)] 3fill_color = adjacent_colors[0] # 隣接するピクセルは沢山あるので、適当に1つピックアップ 4print(fill_color) 5 6# その色で塗りつぶす。 7img[white == 255] = fill_color # 白のピクセルを塗りつぶす。

サンプルコード

以下がコード全体

イメージ説明

python

1import cv2 2 3# 画像を読み込む。 4img = cv2.imread('test.png') 5 6# 白かどうかで2値化する。 7white = cv2.inRange(img, (250, 250, 250), (255, 255, 255)) 8 9# 膨張処理を行う。 10kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) 11dilated = cv2.dilate(white, kernel) 12 13# 膨張後 - 膨張前 = 白に隣接するピクセル 14adjacent = cv2.subtract(dilated, white) 15 16# 白に隣接するピクセルの色を取得する。 17adjacent_colors = img[np.where(adjacent == 255)] 18fill_color = adjacent_colors[0] # 隣接するピクセルは沢山あるので、適当に1つピックアップ 19print(fill_color) 20 21# その色で塗りつぶす。 22img[white == 255] = fill_color # 白のピクセルを塗りつぶす。 23 24# 画像を書き込む。 25cv2.imwrite('result.png', img)

イメージ説明

投稿2019/06/03 16:26

編集2019/06/04 06:09
tiitoi

総合スコア21956

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

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

SuzuAya

2019/06/04 02:17

ご丁寧にありがとうございます。提案していただいた方法でやったところ、ほんの少し白い部分が残ってしまったものの、黒に置き換えることができました!!本当にありがとうございました。 ちなみに、もしご存知でしたら教えていただきたいのですが、私が使っている白黒画像の背景は、正確には真っ黒ではないため(少しグレーがかった黒)、白い部分を黒く塗りつぶす処理をすると、それはそれで周りと少し色が異なってしまいます。 周辺の色の情報を取得し、それと同じ色で画像の穴あき部分を塗りつぶす、ということができると以前何かのサイトで見かけた気がするのですが、どうしてもうまく検索できません…。 そういったやり方についてもしご存知でしたら、教えていただけないでしょうか。 ご存知なければ、このままこちらの質問はtiitoiさんのご回答をベストアンサーに選び、クローズさせていただきます。お手数をお掛けしますがご確認の程よろしくお願いいたします。
tiitoi

2019/06/04 05:32

追記しました。 白色の画素取得 → 白色の画素に隣接する画素を取得 → 白色の画素を隣接する画素の色で塗りつぶす という流れで実現できます。
SuzuAya

2019/06/04 06:01

早速ありがとうございます。binaryについて定義されていないとエラーが出てしまったので、お手数ですがその部分についても追記していただけますと大変助かります。
tiitoi

2019/06/04 06:10

コードが一部間違っていたので修正しました。 一番下の「サンプルコード」以下がコード全体になります。 処理で不明な点があれば、コメントしてください。
SuzuAya

2019/06/04 06:34

ありがとうございます!無事動きました。白黒画像なので、埋めたくない白い部分も少し黒くなってしまったり、調整が難しいものだと実感いたしました。教えていただいたコードを基に、色々と調整をしていきたいと思います。たくさんご丁寧に教えてくださり、本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問