OpenCVを使った画像のノイズ除去方法

このQ&Aのポイント
  • OpenCVを使用して画像のノイズ除去を行いたい
  • 現在はプログラムがうまく動作せず困っている
  • Labeling.hを使用したプログラムも検討しているが、理解ができていない
回答を見る
  • ベストアンサー

OpenCVを使って画像のノイズ除去を考えています

OpenCVを使って画像のノイズ除去を考えています。 ですが、プログラムで上手く動いてくれないところがあり、分からなくて困っています。 もしわかる方がいらっしゃれば是非教えてください。 OpenCV2.4.6,VisualC++2010を用いています。 OpenCVを使わないLabeling.hなどを使った似たようなプログラムを教えてくださっても構いません。 ただ、Labeling.h自体がよくわからなく、Labeling.hを使って書いたプログラムが動かない状態であり、OpenCVの方がまだわかるので今回はOpenCVで質問しました。 プログラム(OpenCVを使った)の詳しい説明です。 入力画像の黒い点すべてがノイズだとします。またノイズのサイズは500以下だとします。 またサイズは特に指定はありません。拡張子は24bitのbmpを使っています。 画像の左側が入力画像とした時、画像の右側のように出力されます。(画像では分かりやすいように画像の切れ目を青の枠で囲っています。) 出力画像のふち?の部分が1ピクセルの範囲だけノイズ除去されずに残ってしまいます。(画像では分かりずらいですが赤の矢印の先の部分です。) 画像の下側のように赤のふち?1ピクセルの範囲はノイズ除去されません。 原因を考えているのですが、自分では分からなく困っています。 もしわかる方がいらっしゃれば是非教えてください。 私自身、プログラムは大学の授業レベル、OpenCVは使い始めて数ヶ月なので詳しくないです。 よろしくお願いします。 プログラムの内容は以下のようになっています。 〇〇〇は入力画像のファイル指定先 ●●●は出力画像のファイル指定先 ノイズのサイズは500以下とします。 自分は輪郭追跡のcvPointの部分が怪しいと考えてます。 今書いてるプログラムから一部抜き出してきたのでもしかしたら余計な処理が入っているかもしれません。 一応コピペでライブラリの設定、入力・出力画像のファイル指定をしていただくと動くと思います。 #include "stdafx.h" #include <stdio.h> #include "opencv/cv.h" #include "opencv/highgui.h" int _tmain(int argc, _TCHAR* argv[]) { IplImage *Proc;//処理画像 int i; char input_fname[256]; //元画像読み込み先 char output_fname[256]; //処理後画像出力先 //輪郭情報 CvMemStorage* Storage;//メモリストレージ CvSeq* Contours=0;//輪郭データ int Count=0;//輪郭の数 double Area=0;//面積 Storage=cvCreateMemStorage(0);//メモリストレージを確保 sprintf(input_fname, "〇〇〇"); sprintf(output_fname, "●●●"); IplImage *Input = cvLoadImage( input_fname, CV_LOAD_IMAGE_GRAYSCALE); if( Input == NULL ){ printf("ファイルが読み込めません。\n"); cvWaitKey(0); // キー入力待機 return -1; } // (1)二値化(大津の手法を利用) cvThreshold (Input, Input, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);//大津の二値化を用いて色を反転させる Proc = cvCreateImage(cvGetSize(Input), Input->depth, 1);//処理画像 cvCopy(Input,Proc,NULL); //輪郭を取得 Count = cvFindContours(Proc,Storage,&Contours,sizeof(CvContour),CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0)); //輪郭情報の取得 for(i=1;i<=Count;i++){ Area=abs(cvContourArea(Contours));//面積 if(Area<500){//面積が500以下の場合、黒で塗りつぶす cvDrawContours( Input, Contours, CV_RGB(0,0,0),CV_RGB(0,0,0), 0, CV_FILLED);} Contours=Contours->h_next;//次の輪郭へ } cvThreshold (Input, Input, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU);//大津の二値化を用いて色を反転させる cvSaveImage(output_fname,Input);//矩形描画した画像を保存 //画像情報解放 cvReleaseImage(&Input); cvReleaseImage(&Proc); }

質問者が選んだベストアンサー

  • ベストアンサー
noname#208507
noname#208507
回答No.1

OpenCVの輪郭線抽出は、入力画像の端の1ピクセルは必ず黒(0)として扱われるようですね。 塗りつぶしを下のように置き換え、 cvDrawContours( Input, Contours, CV_RGB(100,100,100),CV_RGB(0,0,0), 0, 1); 最後の二値化をコメントアウトして出力画像を見ると分かります。 画像の端の1ピクセルを残して、輪郭線(100)が引かれます。 少しでも高速化するために、画像端の例外処理を省略しているのでしょう。 入力画像より縦横に2ピクセル大きい画像を作り、入力画像の内容を縦横に1ピクセル内側にコピーして、入力画像の代わりに用いれば期待する結果が得られるのではないでしょうか。

nanonanoda
質問者

お礼

長々と質問してしまったのですが、cvMergeを使って8bitから24bitへ変換することが出来るようになりました。 ulisrtさんのおかげでノイズ除去が出来るようになったので、助かっています。 数週間悩んで解決できず質問させていただいたので、もっと早くに質問しておけばよかったです f(^^;

nanonanoda
質問者

補足

ulisrtさんの提案してくださった方法でOpenCVを使ったノイズ除去が出来るようになりました。 ありがとうございます。 また、余分に2ピクセル大きい画像を作ってノイズ除去した後に、余分に大きくした2ピクセル分をなくし、元の画像サイズにすることが出来たのですが、出力画像が8bitのbmp画像になってしまいます。 プログラム中の処理画像Procが1チャンネル8bitなので、処理後画像が8bitになってしまうのはわかるのですが・・・ 入力画像自体は白黒画像(24bitのbmp形式)なので、出力画像も24bitのbmp形式で出力させたいです。(ほかのプログラムで24bitのbmp形式で処理させているので・・・) ちなみに処理画像Procを3チャンネル24bitでさせようと思ったのですが、cvFindContoursで8bitの画像しか処理できないようでエラーが出てしまいます。 なので以前は、最初に入力画像をコピーした出力画像(24bitのbmp形式)を用意して、ラべリングの輪郭情報取得などは入力画像を使ってさせ、ラべリングの結果(ノイズ除去の結果)を出力画像(24bitのbmp形式)に反映させて24bitのbmp形式で画像を出力させていました。 この方法を使えばたぶん24bitのbmp形式で画像を出力させることはできそうなのですが、画像を用意したりなど二度手間のように感じます・・・ 8bitの画像を24bitの画像に変換させる方法はご存じでしょうか?(この処理はOpenCVを使っても使わなくても構いません。) もし何かいい方法をご存じであればぜひ教えてください。 よろしくお願いします。

関連するQ&A

  • OpenCVのcvFindContours

    添付画像(2値)の一番外側の輪郭線を抽出するコードを書きたいのですが, contoursがNULLになってしまい、うまく行きません。 サンプルで添付した画像(小さくてすみません)に、問題があるのでしょうか。 いろいろと調べましたが原因がわからず困っています。 どこを修正するべきか ぜひ教えてください。 よろしくお願い致します。 void test(char myPath){ int i; Iplimage *kuro; CvSeq *contours = NULL; kuro = cvLoadImage(myPath, CV_LOAD_IMAGE_ANYCOLOR);  //2値画像 cvThreshold(kuro, kuro, 100, 255, CV_THRESH_BINARY); // 以下の contours がNULLになってしまいます。 cvFindContours(kuro, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); cvDrawContours(img, contours, CV_RGB(255, 0, 0), CV_RGB(0, 255, 0), 1, 2, CV_AA, cvPoint(0, 0)); }

  • OpenCV輪郭抽出→座標取得でのバグ(C++)

    プログラミング初心者の者です。 今OpenCVを色々勉強してるのですが、全く行き詰ってしまいました。 サンプルを打ち込んだりして、輪郭抽出、表示まではできましたが、それに加えて座標の取得、表示の部分を書いてみたんですが、バグが一向に取れません。 OpenCV2.4.1 Visual Studio2010ExpressC++でやっています。 0x00411845 でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00000004 を読み込み中にアクセス違反が発生しました。 という内容が表示されます。 以下のようなコードを書きました。 おかしいところもたくさんあると思いますが、何卒ご教示頂ければと思います。 using namespace cv; using namespace std; int i; IplImage *g_image = NULL; IplImage *g_gray = NULL; IplImage *src_img = NULL; IplImage *tmp_img = NULL; int g_thresh = 100;//閾値 CvMemStorage *g_storage = NULL;//データ格納用低レベル構造体 CvFileStorage *fs;//ファイルストレッジ CvTreeNodeIterator it;//イテレータ CvPoint *point,*tmp; void on_trackbar(int){ if( g_storage == NULL ){ g_gray = cvCreateImage( cvGetSize( g_image ), 8, 1 ); g_storage = cvCreateMemStorage(0); } else { cvClearMemStorage( g_storage ); } CvSeq* contours = 0; cvCvtColor( g_image, g_gray, CV_BGR2GRAY ); cvThreshold( g_gray, g_gray, g_thresh, 255, CV_THRESH_BINARY ); cvFindContours( g_gray, g_storage, &contours,sizeof(CvContour ),CV_RETR_TREE,CV_CHAIN_APPROX_NONE); //輪郭抽出 (入力画像、保存先、一番外の輪郭、サイズ、  ) 抽出モード cvZero( g_gray ); if( contours ){ cvDrawContours( g_gray, contours, cvScalarAll(255), cvScalarAll(255), 100 ); } cvInitTreeNodeIterator (&it, contours,1); fs=cvOpenFileStorage("Contours.xml",NULL,CV_STORAGE_WRITE); //輪郭線上を走査 while((contours=(CvSeq*)cvNextTreeNode(&it))!=NULL){ cvClearMemStorage( g_storage ); cvStartWriteStruct(fs,"Contours",CV_NODE_SEQ); for (i=0;i<contours->total;i++){ point=CV_GET_SEQ_ELEM(CvPoint,contours,i); cvLine(g_gray,*tmp,*point,CV_RGB(0,0,255),2); cvStartWriteStruct(fs,NULL,CV_NODE_MAP); cvWriteInt(fs,"x",point->x); cvWriteInt(fs,"y",point->y); //座標取得 cvEndWriteStruct(fs); tmp=point; } cvEndWriteStruct(fs); cvReleaseFileStorage(&fs); } cvShowImage( "Contours", g_gray ); } int _tmain(int argc, _TCHAR* argv[]){ g_image = cvLoadImage( "C:\\OpenCV2.4.1\\opencv\\samples\\c\\lena.jpg" ); //入力画像       cvNamedWindow( "Contours", 1 ); cvCreateTrackbar( "Threshold", "Contours", &g_thresh, 255, on_trackbar ); on_trackbar(0); cvWaitKey(); return 0; }

  • OpenCV 2値化について

    いつもお世話になっております。 画像の2値化(黒は全てゼロ、白は全て255)をした画像bw_imgを用意して 左上端から11×11サイズのROIに切り取って決まった処理をかけていこうとしていますが、 2値化した画像をROIで保持させることができず、困っています。 int main() { //画像の2値化処理用変数 IplImage *src_img = 0, *dst_img = 0, *bw_img = 0; IplImage *src_img_gray = 0; IplImage *tmp_img, *out_img, *lap_img; CvMemStorage *storage = cvCreateMemStorage(0); CvSeq *contours = 0; // (1)画像を読み込み、グレースケール化(src_img_gray)、二値化(tmp_img) src_img = cvLoadImage("C:\\Users...\\サンプル画像\\sample.jpg", CV_LOAD_IMAGE_COLOR); tmp_img = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1); src_img_gray = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1);//もとはIPL_DEPTH_8U cvCvtColor(src_img, src_img_gray, CV_BGR2GRAY); cvAdaptiveThreshold(src_img_gray, tmp_img, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, 8); //11×11 走査用変数 dst_img = cvCreateImage(cvGetSize(tmp_img), IPL_DEPTH_8U, 1); bw_img = cvCreateImage(cvGetSize(tmp_img), IPL_DEPTH_8U, 1); out_img = cvCreateImage(cvGetSize(tmp_img), IPL_DEPTH_8U, 1); cvThreshold(tmp_img, bw_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); for (x = 0; x < bw_img->width; x++){ // x 座標を 1ピクセルずつ進める for (y = 0; y < bw_img->height; y++){ // y 座標を 1ピクセルずつ進める //(1) 11×11ピクセルに切り取って2値化する。 cvCopy(bw_img, dst_img); lap_img = cvCreateImage(cvSize(11, 11), IPL_DEPTH_8U, 1); CvMat *sub = cvCreateMatHeader(11, 11, CV_8UC1); cvGetSubRect(bw_img, sub, cvRect(y, x, 11, 11)); //コピー画像から11×11切り取り。 cvThreshold(sub, lap_img, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); //2値化、結果はlap_img. uchar iro = lap_img->imageData[lap_img->widthStep * (y + 6) + (x + 6)]; if (iro ==0){ →ここでどうみても黒なのにiroに「238」「71」などの値が入っています。 roiで切り取ったlap_imgが2値になっていません。 何が問題で2値化できていないのでしょうか。 どうすると2値化した画像(lap_img)を決まったサイズのウィンドウで扱えるでしょうか。 もしおわかりでしたらヒントでも結構ですのでぜひ教えてください。 よろしくお願いします。

  • OpenCVについて

    OpenCVについて OpenCVをインストールしたのですが、設定もちゃんとしたと思います。 インクルードファイルには C:\Program Files\OpenCV\cv\include C:\Program Files\OpenCV\cxcore\include C:\Program Files\OpenCV\cvaux\include C:\Program Files\OpenCV\otherlibs\highgui ライブラリファイルには C:\Program Files\OpenCV\bin C:\Program Files\OpenCV\lib を入れています。 したのですが、 fatal error C1083: include ファイルを開けません。'cxcore.h': No such file or directoryというエラーが出て実行できません。 どうしたら実行できるんでしょうか?

  • C++でOpenCV コンパイルでエラー

    超初心者です。 Visual C++2010 ExpressでOpenCVを使おうとしています。 このページを参考にしています。 http://gihyo.jp/dev/feature/01/opencv/0002?page=2 プログラムは以下の通り。 #include <C:\Program Files (x86)\opencv\build\include\opencv\cv.h> #include <C:\Program Files (x86)\opencv\build\include\opencv\highgui.h> int main(int argc, char* argv[]) { IplImage* img; // 画像ファイルポインタの宣言 char imgfile[] = "lena.jpg"; // 読み込み画像ファイル名 // 画像の読み込み img = cvLoadImage(imgfile, CV_LOAD_IMAGE_COLOR); // 画像の表示 cvNamedWindow ("lena", CV_WINDOW_AUTOSIZE); cvShowImage ("lena", img); cvWaitKey (0); cvDestroyWindow("lena"); // 画像の解放 cvReleaseImage(&img); return 0; } コンパイルすると、以下のエラーメッセージが出ます。 1>------ ビルド開始: プロジェクト: try, 構成: Debug Win32 ------ 1> try.cpp 1>c:\program files (x86)\opencv\build\include\opencv\cv.h(63): fatal error C1083: include ファイルを開けません。'opencv2/core/core_c.h': No such file or directory ========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ========== どのようにすれば通るのでしょうか? 教えてください。よろしくお願いします。

  • opencvのシーケンスについて。

    opencvのシーケンスについて。 opencvのシーケンスとは。 opencvを使っていると、よくシーケンスという言葉に遭遇します。本やネットで調べましたが、どんなものなのかがよく分かりません。 メモリストレージ・オブジェクト等と一緒に出てくるのですが、これらもなかなか理解しがたいです… 例えばCvFindCountorという画像内のn個の辺を持つ輪郭を調べるという関数がありますが、これに関する情報が引数として渡したシーケンスに保存されているようだ。というのは何となく感じとったのですが、この中の座標等を引き出すにはどうしたらいいのでしょうか。 どなたか分かりやすくご教授頂けないでしょうか。 また、分かりやすいサイトや本もご存知であれば教えて下さい。

  • OpenCVで画像を読み込みたい

    OpenCVを勉強しようと思い先日始めました。 http://chihara.naist.jp/opencv/?FrontPage 上記のサイトに掲載されている通りにVC++ 2008 EEで ・環境変数PATH ・インクルードファイル ・ライブラリファイル ・リンカ の設定をしました。 これでいざプログラムをコンパイルして実行すると何故か画像が読み込んでくれません。 これらの設定以外の他にするべきことがあるのでしょうか? いきなり出鼻を挫かれたので困っています。よろしくお願いします。 OS:XP SP2 開発環境:VC++ 2008 EE 実行したプログラム ---------------------------------------------------------------- #include "cv.h" #include "highgui.h" int main( int argc, char** argv ) { IplImage* img; char* filename = "abc.bmp"; if( argc == 2 && (img = cvLoadImage( filename, 1)) != 0 ) { cvNamedWindow( "Image view", 1 ); cvShowImage( "Image view", img ); cvWaitKey(0); // イベント処理を含む場合には,これが重要. cvDestroyWindow( "Image view" ); cvReleaseImage( &img ); return 0; } return -1; } ----------------------------------------------------------------

  • 【OpenCV】BGRからHSVへの画像変換

    OpenCVを使って任意の画像データをBGR表色系からHSV表色系に変換するプログラムです。 コンパイルして実行してみたところ、添付画像のように元画像とは色味が異なった画像が出力されてしまいます。 他の画像ファイルを使ってみましたが結果は同じでした。 HSVへの変換がうまくいってないのでしょうが、調べても原因は分かりませんでした。 どなたか分かる方がいらっしゃいましたらご指摘お願いします。 以下にコードを載せます。 #include <cv.h> #include <highgui.h> int main (int argc, char **argv){ IplImage *src_img=0; // 入力画像 IplImage *hsv_img=0; // hsvに変換された画像 // (1)画像を読み込む src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); // (2)読み込んだ画像をhsvに変換する hsv_img = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 3); cvCvtColor (src_img, hsv_img, CV_BGR2HSV); // (3)画像を表示,キーが押されたときに終了 cvNamedWindow ("Source_Image", CV_WINDOW_AUTOSIZE); cvNamedWindow ("HSV_Image", CV_WINDOW_AUTOSIZE); cvShowImage ("Source_Image", src_img); cvShowImage ("HSV_Image", hsv_img); cvWaitKey (0); // (4)メモリ解放 cvDestroyWindow ("Source_Image"); cvDestroyWindow ("HSV_Image"); cvReleaseImage (&src_img); cvReleaseImage (&hsv_img); return 0; } OS:Windows7 OpenCVのバージョン:2.1 添付画像で用いた画像の形式:png

  • ある2値化画像に対して,一定の連結より小さければ,

    ある2値化画像に対して,一定の連結より小さければ, その部分を削除し,ある画像に出力するというものを作りたいです. VC++でOpenCVを使っています. ラベリングをしようと思い,井村さんのラベリングクラス http://oshiro.bpe.es.osaka-u.ac.jp/people/staff/imura/products/labeling を見つけました. labeling.Exec(dst_buf, dst_buf, 1920, 1080, true, 10); の関数を使い,2番目のdst_bu2の部分が出力バッファというのも わかるのですが,それを画像に出力する方法がわかりません. よろしくおねがいします.

  • openCVでのデバックエラー

    画像や動画の研究で、aviファイルから色の抽出などを行うためにIntelのopenCVを使用と考えています。 しかし、自作プログラムやopenCVに付属されているサンプルプログラムさえもデバックが失敗してしまい実行することができません。 OSはWindows Professional version2002のVisualC++ 2005で動かしています。 openCVは「OpenCV_b5a」を使用しています。 インストール時にVC++のインクルードファイルに C:\Program files\OpenCV\cv\include C:\Program Files\OpenCV\cvaux\include C:\Program Files\OpenCV\cxcore\include C:\Program Files\OpenCV\otherlibs\highgui ライブラリファイルに C:\Program files\OpenCV\lib を追加させました。 新しくプロジェクトを作成するたびに、リンカの入力に "cv.lib" "cxcore.lib" "cvaux.lib" "highgui.lib" "ipl.lib" を追加させプログラムを作っています。 しかし、デバックをするとすべてのプログラムにおいて、 'AAA.exe': 'C:\WINDOWS\system32\ntdll.dll' を読み込みました。シンボルが読み込まれていません。 'AAA.exe': 'C:\WINDOWS\system32\kernel32.dll' を読み込みました。シンボルが読み込まれていません。 ・・・・・・ と、シンボルが読み込まれていませんとエラーが沢山表示され、 プログラム '[2508] AAA.exe: ネイティブ' はコード -1 (0xffffffff) で終了しました。 と、失敗して困っています。 初心者ですが、この原因が分かる方いましたらどうぞご教授ください。

専門家に質問してみよう