- PR -

画像処理 ぼかしとシャープ化

1
投稿者投稿内容
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-04-09 12:35
画像にぼかしをかけたりシャープ化をするプログラムを作りたいと思っています。ぼかしはネットで調べてできたのですが、このプログラムを流用してシャープ化させようとしてもうまくいきませんでした。
ぼかしのマスクは以下のソースのmaskで定義されていて、それぞれのピクセルを9分の1にするようにしています。(実際には掛け算で求めたいので値は0.1を使用していて厳密には9分の1ではありませんが)
このマスクをシャープ化用に
コード:

private float[] mask = { 0.0f, -1.0f, 0.0f,
-1.0f, 5.0f, -1.0f,
0.0f, -1.0f, 0.0f};


として実行してみたのですが、砂嵐のような画像になってしまいました。画像処理の理論はまだ知らないことが多くて、単に流用しただけではだめなのか分からないのですが、どなたか分かる方いらっしゃいますか?

コード:

import java.awt.*;
import java.applet.Applet;
import java.awt.image.*;

public class A2 extends Applet {
private String imageFile = "image.jpg";
private Image originalImage;
private Image filteredImage;
private MediaTracker tracker;
private float[] mask = { 0.1f, 0.1f, 0.1f,
0.1f, 0.1f, 0.1f,
0.1f, 0.1f, 0.1f};
public void init() {
tracker = new MediaTracker(this);
originalImage = getImage(getDocumentBase(), imageFile);
tracker.addImage(originalImage, 1);
try {
tracker.waitForID(1);
}
catch(InterruptedException e) { }

// フィルタをかける
filteredImage = filterImage(originalImage);
}
public void paint(Graphics g) {
g.drawImage(filteredImage, 0, 0, this);
}
public Image filterImage(Image im) {
int width = im.getWidth(this);
int height = im.getHeight(this);
int[] pixels = new int[width * height];
int scan = width;
int offset = 0;
// PixelGrabberを生成
PixelGrabber pg = new PixelGrabber(im,0,0,width,height,pixels,0,scan);
try {
pg.grabPixels();
}catch(InterruptedException e){ }
//配列内のpixelを順番に処理
for(int i=0; i < width*height ; i++) {
try {
//着目ピクセルの上下左右のRED(RGB)を論理積で取り出し
int r = ApplyFilter(pixels, width, i, 'r');
//着目ピクセルの上下左右のGREEN(RGB)を論理積で取り出し
int g = ApplyFilter(pixels, width, i, 'g');
//着目ピクセルの上下左右のBLUE(RGB)を論理積で取り出し
int b = ApplyFilter(pixels, width, i, 'b');
//RGBの平均値を論理和で求めて着目ピクセルを置き換える
pixels[i] = 0xff000000 | r | g | b ;
}
catch(Exception ex){ }
}
//操作完了した配列から画像を再生成する
//引数(幅、高さ、配列、配列の開始位置、横幅)
MemoryImageSource mis =
new MemoryImageSource(width,height,pixels,offset,scan);
Toolkit tk = Toolkit.getDefaultToolkit();
//戻された画像を呼び元に戻す
return tk.createImage(mis);
}
public int ApplyFilter(int[] pixels, int width, int i, char rgb) {
float c, n, ne, e, se, s, sw, w, nw;
int hex = 0;
int result = 0;

switch(rgb) {
case 'r':
hex = 0x00ff0000;
break;
case 'g':
hex = 0x0000ff00;
break;
case 'b':
hex = 0x000000ff;
break;
}
// 現在のピクセルとその周り8方向のピクセルを得る
c = pixels[i] & hex;
n = pixels[i-width] & hex;
ne = pixels[i-width+1] & hex;
e = pixels[i+1] & hex;
se = pixels[i+width+1] & hex;
s = pixels[i+width] & hex;
sw = pixels[i+width-1] & hex;
w = pixels[i-1] & hex;
nw = pixels[i-width-1] & hex;

  // マスクをかける
nw = mask[0] * nw;
n = mask[1] * n;
ne = mask[2] * ne;
w = mask[3] * w;
c = mask[4] * c;
e = mask[5] * e;
sw = mask[6] * sw;
s = mask[7] * s;
se = mask[8] * se;

return (int)(c + n + ne + e + se + s + sw + w + nw) & hex;
}
}



[ メッセージ編集済み 編集者: fuzuki 編集日時 2004-04-09 12:36 ]

[ メッセージ編集済み 編集者: fuzuki 編集日時 2004-04-09 12:37 ]
omatsu
常連さん
会議室デビュー日: 2002/08/29
投稿数: 20
投稿日時: 2004-04-09 13:22
画像処理については、何にも詳しくありませんが、砂嵐になる理由はわかります。

コード:
private float[] mask = { 0.1f, 0.1f, 0.1f,
                         0.1f,  0.1f, 0.1f,
                         0.1f, 0.1f, 0.1f};


であれば、各ピクセルの明度が、0〜255 の時、結果もその範囲に収まりますが、
コード:
private float[] mask = { 0.0f, -1.0f, 0.0f,
                        -1.0f,  5.0f, -1.0f,
                         0.0f, -1.0f, 0.0f};


の場合、そうはいかず、-1020〜1275 の範囲になってしまい、結果は、その値の下位8ビットなんで、見た目、訳がわからない画像になってしまうはず。

ゼロ未満、255より大、を、ゼロ、255 にクリップするようにすればいいんですかね?
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-04-09 14:32
早速のご返事ありがとうございます。

確かにこのフィルターをかけるとレンジが0以下になったり255以上になったりしますね。どこかに載っていたそのマスクの値を見てそれを信じてそのまま使ってしまったので全く気付きませんでした。ただ、0以下を0にして255以上を255にするように処理してみたのですが、今後は真っ青の画像になってしまって。どうも分かりません・・・
一郎
ぬし
会議室デビュー日: 2002/10/11
投稿数: 1081
投稿日時: 2004-04-09 15:16
Javaは良く分かりませんが、RとGのデータにもそのまま「0〜255以内かどうか」という判定をしているわけではありませんよね。
Rは5,6バイト目、Gは3,4バイト目を使っているみたいですから・・・

あと、範囲を外れていた場合RやGの値も0(つまり0x00000000)や255(つまり0x000000ff)の値に変更しているわけではありませんよね。
Rは5,6バイ(以下略
キルシェ
常連さん
会議室デビュー日: 2004/03/25
投稿数: 26
投稿日時: 2004-04-09 15:44
言葉でうまく説明できませんがご容赦を。

一旦、処理前の画像のデータ、処理後の画像のデータ、さらにRGBのそれぞれで
変数を分けて計算すれば、そのままのフィルタ式でもうまく行きそうな気がします。
最大で5バイトの値になる計算を1バイトで済まそうとしているのが、うまくいかない
原因じゃないかと思います。
いっきゅう
大ベテラン
会議室デビュー日: 2004/04/04
投稿数: 153
お住まい・勤務地: 兵庫
投稿日時: 2004-04-09 17:24
JAVA2Dを使って下記のような感じはどうでしょう?

参考 :http://java.sun.com/j2se/1.4/ja/docs/ja/guide/2d/spec/j2d-image.fm8.html#63208

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

import java.awt.*;
import java.applet.Applet;
import java.awt.image.*;
import javax.imageio.*;
import java.net.URL;

public class A2 extends Applet {
private String imageFile = "tetst.png";
BufferedImage srcimg;
BufferedImage bimg;
BufferedImage bimg2;

public void init() {
try {
int width, height;
srcimg = ImageIO.read(new URL(getDocumentBase() + "/" + imageFile));
width = srcimg.getWidth();
height = srcimg.getHeight();

bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
bimg2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics2D gg = bimg.createGraphics();
gg.drawImage(srcimg, 0, 0, this);
float weight = 1.0f / 9.0f;
System.out.println(weight);
float[] blur = {weight,weight,weight,weight,weight,weight,weight,weight,weight};
float[] sharp = {0.0f,-1.0f,0.0f,-1.0f,5.0f,-1.0f,0.f,-1.0f,0.0f};

Kernel myKernel = new Kernel(3, 3, sharp);

ConvolveOp blurOp = new ConvolveOp(myKernel);
ConvolveOp sharpOp = new ConvolveOp(myKernel, ConvolveOp.EDGE_NO_OP, null);

//blurOp.filter(bimg, bimg2); // ぼかし
sharpOp.filter(bimg, bimg2); // シャープ

}
catch (Exception e) {
e.printStackTrace();
}
}

public void paint(Graphics g) {
g.drawImage(bimg2, 0, 0, this);
}
}
ぽんす
ぬし
会議室デビュー日: 2003/05/21
投稿数: 1023
投稿日時: 2004-04-09 20:54
画像処理は専門じゃないし、Javaは更に分からなかったりしますが...

0 -1 0
-1 5 -1
0 -1 0

ということは...

0 -0.2 0
-0.2 1.8 -0.2
0 -0.2 0

だと、周囲4ピクセルを含む5ピクセルの平均との差を
問題のピクセルに足したことになるわけで、
その5倍ですかあ。なんか相当強そうな気がするですが、
このくらいはふつうなんですかねえ。

[ メッセージ編集済み 編集者: ぽんす 編集日時 2004-04-09 21:23 ]
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-04-10 00:40
どうも最初の方法ではうまく行かず、他の方法を探していたところ、いっきゅうさんと同じページを見つけ、これでうまくいきました。
最初の方法のほうが自分にとっては分かりやすかったのですが、どうしてだめなのか分からず少し残念です。もう少し画像の処理について勉強しないとだめですね。

みなさん、ありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)