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

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

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

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

フィルタ

フィルタとは、特定の条件に合わせてデータへのアクセスをブロックするプログラムやルーチンを指します。

C++

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

Q&A

解決済

3回答

4472閲覧

OpenCVで平滑化フィルタを作りたい

pootare

総合スコア16

OpenCV

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

フィルタ

フィルタとは、特定の条件に合わせてデータへのアクセスをブロックするプログラムやルーチンを指します。

C++

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

0グッド

0クリップ

投稿2020/07/20 15:27

編集2020/07/20 15:32

前提・実現したいこと

OpenCVで線形フィルタを作ろうとしたところ結果画像が黒塗りになりました.

該当のソースコード

c++

1#include <iostream> 2#include <opencv2/opencv.hpp> 3 4 5using namespace std; 6using namespace cv; 7 8int main() 9{ 10 //画像の読み込み 11 Mat src = imread("../img/lena.jpg",0); 12 if(src.empty()) 13 { 14 cout << "img not found" << endl; 15 return -1; 16 } 17 18 //線形フィルタ 19 double filter[][3] = 20 { 21 {1/9,1/9,1/9}, 22 {1/9,1/9,1/9}, 23 {1/9,1/9,1/9} 24 }; 25 26 //入力画像と同じサイズの画像を0で初期化 27 Mat dst = Mat::zeros(src.rows, src.cols, CV_8U); 28 29 for(int j = 1; j < src.rows - 1; j++) 30 { 31 for(int i = 1; i < src.cols - 1; i++) 32 { 33 int tmp = 0; //テンプレート初期化 34 for(int jj = -1; jj < 1; jj++) 35 { 36 for(int ii = -1; ii < 1; ii++) 37 { 38 tmp += src.at<uchar>(j + jj,i + ii) * filter[jj + 1][ii + 1]; 39 } 40 } 41 if(tmp < 0) tmp = -tmp; //絶対値 42 if(tmp > 255) tmp = 255; //255は超えない 43 dst.at<uchar>(j, i) = tmp; 44 } 45 } 46 47 namedWindow("original",WINDOW_AUTOSIZE); 48 namedWindow("filter",WINDOW_AUTOSIZE); 49 imshow("original",src); 50 imshow("filter",dst); 51 waitKey(0); 52 53 return 0; 54 55}

参考にしたサイト

OpenCVで線形フィルタ処理と代表的なフィルタの種類11個

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

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

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

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

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

guest

回答3

0

ベストアンサー

tmpはintではない方が良いと思う.

//ここは他回答で指摘済み double filter[][3] = { {1.0/9, 1.0/9, 1.0/9}, {1.0/9, 1.0/9, 1.0/9}, {1.0/9, 1.0/9, 1.0/9}, }; for(int j = 1; j < src.rows - 1; j++) { for(int i = 1; i < src.cols - 1; i++) { double tmp = 0; //intではなくdoubleに for(int jj = -1; jj <= 1; jj++) //条件を <= に (他回答で指摘済み) { for(int ii = -1; ii <= 1; ii++) //条件を <= に (他回答で指摘済み) { tmp += src.at<uchar>(j + jj,i + ii) * filter[jj + 1][ii + 1]; } } tmp = cvRound( fabs(tmp) ); //絶対値と丸め dst.at<uchar>(j, i) = ( tmp<255 ? (uchar)tmp : uchar(255) ); //255は超えない } }

あと,この処理だと,外周が処理されない問題もある(結果画像の外周に1pixel幅の黒枠ができることになるはず).これに関しては,

  • iとjのループ範囲を全域にして,
  • j+jjやi+iiが画像範囲外になる場合を適切にハンドリングする(例えば,最も近い「範囲内」な座標の画素値を参照するようにする)

あるいは,
あらかじめ「外周を膨らませた」画像を作って(copyMakeBorder()あたりを使うとよい),それを処理対象にする.

投稿2020/07/21 04:40

編集2020/07/21 04:47
fana

総合スコア11729

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

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

fana

2020/07/21 05:02

参考までに:外周の話も含めて畳み込みをしてくれる関数として,filter2D()というのがあります.
pootare

2020/07/21 07:04

こちらの方法でできました.ありがとうございました.
yohhoy

2020/07/21 07:40

FYI: 最後の値域[0, 255]に丸める処理には cv::saturate_cast という関数テンプレートも提供されます。 fanaさんコメントにもある通り filter2D() を使ってしまうのがOpenCV的ですし、安全かつ高速化と思います。
guest

0

C/C++(その他整数/浮動小数点型のある多くのプログラム言語)において、整数同士の演算は整数で閉じていて(結果も整数で得られる)、1/9の演算は0になります。計算した後結果を格納する型を浮動小数点型にしたところですでに時遅し...

1.0/9などとして、計算に浮動小数点型を参加させてください。

投稿2020/07/20 21:41

thkana

総合スコア7667

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

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

pootare

2020/07/21 04:17

"1.0/9"に変更し実行したところ黒塗りからは脱却できました! でも結果画像は全体の明度が下がっただけで肝心の平滑化はできてないと思われます..
guest

0

内側の二重ループ(ii,jj)が -1~0 の2つしか回っていませんが、それで正しい動作ですか?
平均して画素ひとつあたり 4/9 になるので半分くらい暗くなります。

(参考サイトも同様になっています)

真っ黒ということであれば、また別の原因が考えられますが。

投稿2020/07/20 16:33

Kaleidoscope

総合スコア257

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

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

pootare

2020/07/21 04:27

黒塗りは浮動小数点型にすることで解決しました. 初心者なのでコード内の動きは詳しく分からないです.すいません. 参考サイトが間違っている可能性があるのでしょうか...
fana

2020/07/21 04:55

どこぞの「参考サイト」のコードはちゃんとその意味を把握して使いましょう. (コードを無条件に信用してそのまま使うのではなく)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問