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

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

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

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

1595閲覧

OpenCV340でのクロージングについて

daisuke.senga

総合スコア8

OpenCV

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/10/11 08:58

編集2018/10/18 00:34

次のようなプログラムで単純なドットを描画し、クロージングをかけてみました

Mat mat = Mat::zeros(3, 9, CV_8U); mat.at<unsigned char>(1, 2) = 255; mat.at<unsigned char>(1, 6) = 255; imwrite("c:\temp\mat1.bmp", mat); morphologyEx(mat, mat, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(5, 1))); imwrite("c:\temp\mat2.bmp", mat);

元画像 mat1.bmpはこんな感じ

■■■■■■■■■
■■ ■■■ ■■
■■■■■■■■■

結果画像 mat2.bmpはこんな感じ

■■■■■■■■■

■■■■■■■■■

期待している画像はこんな感じ

■■■■■■■■■
■■     ■■  
■■■■■■■■■

morphologyExの最後の引数をいろいろ変えましたが、期待通りになりませんでした
画像の端までつながってしまいます
こういうものなのでしょうか?

どうぞよろしくお願いします

回答していただいた後に、次のプログラムを試したところ、期待通りの結果になりませんでした

Mat mat = Mat::zeros(3, 9, CV_8U); Mat mat2 = Mat::zeros(3, 9, CV_8U); mat.at<unsigned char>(1, 2) = 255; mat.at<unsigned char>(1, 6) = 255; imwrite("c:\temp\mat1.bmp", mat); morphologyEx(mat, mat2, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(9, 1)), Point(-1, -1), 1, BORDER_CONSTANT, 0); imwrite("c:\temp\mat2.bmp", mat2);

画像を添付しようとしたのですが、うまくいきません

よろしくおねがいします。

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

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

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

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

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

guest

回答2

0

MORPH_CLOSEは、DILATEとERODEをセットでやってくれるのですが

期待しているであろう動作
①画像をひろげて、指定値でパディング
②Dilateする
③Erodeする
④画像サイズを戻して返す

実際の動作
①画像をひろげて、指定値でパディング
②Dilateする
③画像サイズを戻す
④画像をひろげて、指定値でパディング
⑤Erodeする
⑥画像サイズを戻して返す

となります。
#OpenCVのソースのmorph.cppあたりをみるとでてくるかと

なので、daisuke.sengaさんの指定しているSize(9, 1)で横方向にDILATEしてびょいーんと伸ばしたが、そのうち、元の画像サイズを超えた部分は一旦消され、それからSize(9,1)でERODEされるため中央に1点だけになっているようです。

以下の内容ではいかかでしょうか?

cv::Mat mat = cv::Mat::zeros(3, 9, CV_8U); cv::Mat mat2; mat.at<unsigned char>(1, 2) = 255; mat.at<unsigned char>(1, 6) = 255; cv::imwrite("e:\mat1.bmp", mat); cv::Mat temp; cv::copyMakeBorder(mat, temp, 9, 9, 9, 9, cv::BORDER_CONSTANT, cv::Scalar(0)); // (9,1)フィルターでClosing cv::morphologyEx(temp, temp, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(9, 1))); cv::Mat(temp, cv::Rect(cv::Point(9, 9), mat.size())).copyTo(mat2); cv::imwrite("e:\mat2.bmp", mat2);

//広げる量は、9÷2以上あればいいはずだけどとりあえず9に

投稿2018/10/18 12:24

yominet

総合スコア187

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

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

daisuke.senga

2018/10/22 02:35 編集

分かりやすい解説ありがとうございます ③画像サイズを戻す ④画像をひろげて、指定値でパディング が無ければ期待通りの結果になりそうですね せっかく教えていただいたのですが、RLEを使用したバージョンに切り替え中です そちらでは数値的に処理しますので、画像の端の影響は無く、期待通りの結果になりました
guest

0

ベストアンサー

CLOSE 演算は、dilate → erode を順番に行う処理なので、dilate、erode を単体で呼び出して調整してみてはどうでしょうか。

kernel 引数で各走査点での処理する画素を定義しているので、ここを以下のようにカーネルを自分で定義することで、特定の方向だけ収縮したり、膨張したりもできます。

python

1kernel = np.array([ 2 [0, 0, 0], 3 [1, 1, 1], 4 [0, 0, 0] 5]) 6 7kernel = np.array([ 8 [0, 1, 0], 9 [0, 1, 0], 10 [0, 1, 0] 11])

参考リンク

追記

python

1import matplotlib.pyplot as plt 2import numpy as np 3 4# 入力画像を作成する。 5src = np.zeros((3, 9), dtype=np.uint8) 6src[1, 2] = 255 7src[1, 6] = 255 8plt.imshow(src, cmap='gray') 9plt.show() 10 11kernel = np.array([[1, 1, 1]]) 12dst = cv2.morphologyEx(src, cv2.MORPH_DILATE, kernel, 13 borderType=cv2.BORDER_CONSTANT, borderValue=0) 14plt.imshow(dst, cmap='gray') 15plt.show() 16 17# 縁を除く ROI を作成して、dilate する。 18dst = src.copy() 19dst[1:-1, 1:-1] = cv2.morphologyEx(dst[1:-1, 1:-1], cv2.MORPH_DILATE, kernel, iterations=2, 20 borderType=cv2.BORDER_CONSTANT, borderValue=0) 21plt.imshow(dst, cmap='gray') 22plt.show()

イメージ説明
入力画像

イメージ説明
入力画像に対して dilate を1回した結果

イメージ説明
入力画像の外周のピクセルを除いて dilate を2回した結果

投稿2018/10/11 09:10

編集2018/10/18 02:37
tiitoi

総合スコア21956

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

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

daisuke.senga

2018/10/12 01:15

回答ありがとうございます morphologyEx(mat, mat, MORPH_DILATE, getStructuringElement(MORPH_RECT, Size(5, 1))); morphologyEx(mat, mat, MORPH_ERODE, getStructuringElement(MORPH_RECT, Size(5, 1))); とやってみましたが、同じでした カーネルの件もご教授いただけましたが、上記理由から良い結果にはならなさそうです 処理したい画像の上下左右に輝度値0の領域を1ドットつけたしてからCLOSEし、そのあとに上下左右取り除くような仕組みが必要かもしれません 処理時間がかかりますねー
daisuke.senga

2018/10/12 01:29

あ、1ドットではだめでした、Size(5, 1)の場合は6ドット必要ですね(^_^;) この方法は現実的ではありませんね
daisuke.senga

2018/10/12 02:29 編集

CLOSINGの前に mat = mat(Rect(1, 1, 7, 1)); としたら期待通りになりましたが、OPENINGでこのROIを使用すると 画面の端のノイズが除去できなくなってしまいますね 仕様と言われれば仕方ないですが、OpenCVは一般的なモルフォロジ処理ではないような?
tiitoi

2018/10/12 03:14

roi は shallow コピーなので、作成元の行列とデータを共有しており、一方の変更はもう一方にも反映されます。 mat = mat(Rect(1, 1, 7, 1)); とすると、元の行列を参照できなくなってしまうので、別の変数に入れましょう。 > 仕様と言われれば仕方ないですが、OpenCVは一般的なモルフォロジ処理ではないような? 一般的なモルフォロジ処理とはどのようなものを想像されていますか? リファレンスの erode() dilate() の欄を見ると、ちゃんと数式で処理が定義されています。 https://docs.opencv.org/3.4.1/d4/d86/group__imgproc__filter.html#ga4ff0f3318642c4f469d0e11f242f3b6c > カーネルの件もご教授いただけましたが、上記理由から良い結果にはならなさそうです getStructuringElement() はカーネル用の行列を作る便利関数なので、別にカーネルを cv::Mat で自分で作ってもいいわけです。カーネルがどのように使われるのか、リファレンスの数式と合わせて確認してみてください。 http://pynote.hatenablog.com/entry/opencv-morpology#%E6%BC%94%E7%AE%97%E3%81%AE%E7%A8%AE%E9%A1%9E
daisuke.senga

2018/10/12 04:38 編集

回答ありがとうございます 「画像の境界を処理するときに折り返した値を使用する」 という仕様で、こうなっているようですね ■■■■■■■■■    ■■■ ■■ ■■■■■■■■■ を5x1でERODEすると ■■■■■■■■■  ■■■■■■■■ ■■■■■■■■■ なるんですよね 端のゴミはとれません 折り返さずに「0」で処理できれば以下のようになりそうですが... ■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■
daisuke.senga

2018/10/12 05:15

borderValue=0 で解決しました! 長々とありがとうございました
daisuke.senga

2018/10/17 08:51

すいません、また不可解なことになってしまいました ■■■■■■■■■ ■■ ■■■ ■■ ■■■■■■■■■ を、教えていただいたように morphologyEx(mat, mat, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(9, 1)), Point(-1, -1), 1, BORDER_CONSTANT, 0); とすると ■■■■■■■■■ ■■■■ ■■■■ ■■■■■■■■■ となります なかなか思い通りにいきません
tiitoi

2018/10/17 09:48

試されている画像を質問欄を編集して、添付していただくことはできますか?
daisuke.senga

2018/10/18 01:08

はい、編集しました 画像作成もコードで行っています よろしくお願いします
tiitoi

2018/10/18 02:40 編集

モルフォロジー演算はそもそも前景 (白いピクセル) を収縮または膨張させる目的で行う処理なので、処理されたくない部分はそもそもモルフォロジー演算の対象から外しておけばいいのではないでしょうか? 具体的には、入力画像から外側の縁を除くような ROI を作成して、その ROI に対してモルフォロジー演算を行えばよいのではないでしょうか? 回答にサンプルを追記しました。
daisuke.senga

2018/10/22 02:35 編集

現在、RLEを使用したバージョンに切り替え中です そちらでは数値的に処理しますので、画像の端の影響は無く、期待通りの結果になりました いろいろとありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問