- 締切済み
Sobelフィルタがうまく作れません…
プログラミング初心者で、プログラミングが苦手な者です。 エクリプスというソフトを使ってJavaでsobelフィルタの画像処理を作っているのですが どうしても出来ない部分があります。 下記のコードで作っているのですがうまく動作が出来ないようです。 import org.eclipse.swt.graphics.*; // フィルタクラス public class ImgFil{ // Sobelフィルタ public static Image filso(Image image) { int[] iDx = {- 1, 0, -1, -1, 0, 1, -1, 0, 1 }; int[] iDy = { -1, -1, -1, 0, 0, 0, 1, 1, 1 }; int[] iW1 = { -1, 0, 1, -2, 0, 2, -1, 0, 1 }; int[] iW2 = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; ImageData imd = image.getImageData(); // 画像データ ImageData imd2 =image.getImageData(); // 変換後データを格納するImageData // 画像の幅、高さ int wid = imd.width; int hgt = imd.height; // 空間フィルタは周りの画素を使うため、 // はみでないように(1~wid-1)と(1~hgt-1)でループ for (int y = 1; y < hgt-1; y++) { for (int x = 1; x < wid-1; x++) { for(int i = 0; i < 9; i++) { // 中心座標の色 int iC0 = imd.getPixel(x, y); int iR0 = PixelColor.getR(iC0); int iG0 = PixelColor.getG(iC0); int iB0 = PixelColor.getB(iC0); // 右どなりの色 int iCr = imd.getPixel(x+1, y); int iRr = PixelColor.getR(iCr); int iGr = PixelColor.getG(iCr); int iBr = PixelColor.getB(iCr); // 下どなりの色 int iCu = imd.getPixel(x, y+1); int iRu = PixelColor.getR(iCu); int iGu = PixelColor.getG(iCu); int iBu = PixelColor.getB(iCu); // 合計値を加算していく変数 int iRsum1 = 0; int iGsum1 = 0; int iBsum1 = 0; int iRsum2 = 0; int iGsum2 = 0; int iBsum2 = 0; // RGBに分解して取得 int iR = PixelColor.getR(iC); int iG = PixelColor.getG(iC); int iB = PixelColor.getB(iC); // 累積加算1 int iRsum + = iR * iW1[i]; int iGsum + = iG * iW1[i]; int iBsum + = iB * iW1[i]; // 累積加算2 int iRsum + = iR * iW2[i]; int iGsum + = iG * iW2[i]; int iBsum + = iB * iW2[i]; } // エッジ強度を計算 // Math.abs(...)は絶対値を求める関数 int iRd = Math.abs(iRr-iRO) + Math.abs(iRu-iR0); int iGd = Math.abs(iGr-iG0) + Math.abs(iGu-iG0); int iBd = Math.abs(iBr-iB0) + Math.abs(iBu-iB0); int iRd2 = Math.abs(iRr-iR0) + Math.abs(iRu-iR0); int iGd2 = Math.abs(iGr-iG0) + Math.abs(iGu-iG0); int iBd2 = Math.abs(iBr-iB0) + Math.abs(iBu-iB0); // 合計値を個数で割る int iPRd = iRd+iRd2 ; int iPGd = iRd+iRd2 ; int iPBd = iRd+iRd2 ; // 上限値のチェック // (255を超すとエラーになるので255に揃える) if (iPRd > 255){ iRd = 255; } if (iPGd > 255){ iPGd = 255; } if (iPBd > 255){ iPBd = 255; } // 下限値のチェック // (255を超すとエラーになるので255に揃える) if (iPRd < 0){ iPRd = 0; } if (iPGd < 0){ iPGd = 0; } if (iPBd < 0){ iPBd = 0; } // カラー値の作成 int iCd = PixelColor.setRGB(iRd, iGd, iBd); // カラー値をimd2(変換後データ)に設定 imd2.setPixel(x, y, iCd); } } // 変換後データimd2を使って、新しいImageを作成 Image newImage = new Image(null, imd2); // 新しいImageを返す return newImage; } } エクリプスで見るとRGBに分解して取得、累積加算、 エッジ強度の計算のところのコードに 赤波線のエラー表示が出ていたので その部分の処理がうまく出来ていないのではと思います。 sobelプログラムを動作させるためのファイルは全部で4つで 一つは画像を呼び出すボタンファイル。 二つ目に画像処理を起動するファイル。 三つ目に画像表示用のファイル。 RGBの値を取得するファイル。 で構成されています。 今回問題があって質問したいのは 二つ目の画像処理を起動するファイルのコードです。 自分でもインターネット等で似たような構成のソースコードを 参考にしてやってみたのですが良く分かりませんでした。 プログラミングが苦手なので 出来る限り分かりやすく解答していただけれると助かります。
- みんなの回答 (2)
- 専門家の回答
みんなの回答
・配列 iDx と iDy はたぶん座標(x,y)からみた中心画素とその周囲8画素の相対座標ですね。 ・iRsum1 から iBsum2 までの変数へ0を代入している部分は、変数iのループの中ではなく、ループの直前に書きましょう。iのループが終わった後で、これらの合計値を使うので。 ・下記の部分は、配列 iDx と iDy があるので必要ないです。代わりに iDx と iDy を使って、中心画素と周囲8画素の色を取得しましょう。 // 中心座標の色 ...(略)... // 右どなりの色 ...(略)... // 下どなりの色 ...(略)... ・「累積加算1」「累積加算2」のところは必要な処理ですが、コンパイルエラーになりますよね? ・エッジ強度ですが、Sobelフィルタなら√(sum1の自乗 + sum2の二乗)ではないでしょうか。また、後述のようにエッジ強度とその最大値・最小値を記録しておいた方がよいでしょう。エッジ強度については、あらかじめ画像と同じサイズの配列を用意しておいて。 ・256階調の画像で出力するなら、エッジ強度を単純に0未満と256以上を切り捨てない方がよいでしょう。画像によりますが、エッジ強度の値のスケールが256階調からかけ離れる可能性があります。その対処には二回目のx,yループが必要です。一回目のx,yループで調べたエッジ強度の最小値・最大値を使って、エッジ強度×(255.0 / (最大値 - 最小値)) - 最小値、のようにエッジ強度を255階調に調整します。(もしエッジ強度本来の値が必要なら、別な出力方法を考えましょう)
- kmee
- ベストアンサー率55% (1857/3366)
Sobelフィルターって単純に3x3にフィルタを適用するだけですが。 > // 右どなりの色 > // 下どなりの色 ってどっからでてきました? -1 -2 -1 0 0 0 1 2 1 というフィルタを I(x-1,y-1) I(x,y-1) I(x+1,y-1) I(x-1,y) I(x,y) I(x+1,y) I(x-1,y+1) I(x,y+1) I(x+1,y+1) という画像の「I(x,y)」に適用したら、どんな計算になるか、式を書いてみましょう。 このプログラムに、この式を計算しているところが見当りません。 > for(int i = 0; i < 9; i++) { のループで計算するつもりなのでしょうが、I(x,y)しか出てきません。他のI(x-1,y-1)等を得るにはどうすればいいか考えましょう。 > int[] iDx = {- 1, 0, -1, -1, 0, 1, -1, 0, 1 }; > int[] iDy = { -1, -1, -1, 0, 0, 0, 1, 1, 1 }; と、なんか使ってない配列がありますね