web-dev-qa-db-ja.com

Java画像をぼかす

画像をぼかそうとしています

   int radius = 11;
    int size = radius * 2 + 1;
    float weight = 1.0f / (size * size);
    float[] data = new float[size * size];

    for (int i = 0; i < data.length; i++) {
        data[i] = weight;
    }

    Kernel kernel = new Kernel(size, size, data);
    ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.Edge_NO_OP, null);
    //tbi is BufferedImage
    BufferedImage i = op.filter(tbi, null);

画像はぼやけますが、画像のすべての部分がぼやけるわけではありません。

enter image description here

完全な画像がぼやけるように欠けているところ。パスなし。

10
Prashant Thorat

標準のJava ConvolveOpには、Edge_ZERO_FILLEdge_NO_OPの2つのオプションしかありません。必要なのは、同等のJAIのオプションです( ConvolveDescriptor )、これはEdge_REFLECT(または繰り返しパターンが必要な場合はEdge_WRAP)です。

JAIを使用したくない場合は、画像をより大きな画像にコピーし、エッジをストレッチまたはラップし、畳み込み演算を適用してからエッジを切り取る(「」で説明されている手法と同様)ことにより、これを自分で実装できます。 記事 の「エッジでの作業」セクションは@halexによってコメントセクションに投稿されていますが、その記事によると、エッジを透明のままにすることもできます)。

簡単にするために、 私の実装はConvolveWithEdgeOp と呼ばれ、上記を実行します(BSDライセンス)。

コードは元々持っていたものと似ています:

// ...kernel setup as before...
Kernel kernel = new Kernel(size, size, data);
BufferedImageOp op = new ConvolveWithEdgeOp(kernel, ConvolveOp.Edge_REFLECT, null);

BufferedImage blurred = op.filter(original, null);

フィルタは他のBufferedImageOpと同じように機能し、BufferedImageでも機能するはずです。

8
haraldK

これは、次の行でConvolveOp.Edge_NO_OPを使用しているためです。

ConvolveOp op = new ConvolveOp(kernel, ConvolveOp.Edge_NO_OP, null);

APIドキュメント の説明:

ソース画像の端にあるピクセルは、変更せずに宛先の対応するピクセルにコピーされます。

Edge_ZERO_FILLを試してください-それはあなたに黒い境界線を与えるでしょう。

ぼかした後、エッジを切り落とすこともできます。

エッジを実行できない理由は、アルゴリズムの動作に関係しています。

2
Jesper

1ピクセルをぼかすことはできません。これは当たり前のように聞こえますが、考えてみると、最小値は何ですか?ピクセルをぼかすには、隣接するピクセルが必要です。

ここでの問題は、エッジとコーナーで、ピクセルの隣接ピクセルが少なすぎることです。ブラーアルゴリズムのピクセル数が少なすぎて使用できません。ぼかす画像の「外側」にピクセルがないため、そのままにしておきます。

解決策は、画像をなんらかの方法で拡張するか(より大きなソース画像を利用できますか?)、完了したらぼやけていないビットを切り取る方法です。どちらも本質的に同じです。

0
Tomas

Opencvライブラリを使用して、完全な画像をぼかすことができます。

0
Aniket Patil

ConvolveOpクラスがそれをカットしなかったときにドキュメントのぼかし機能を探していたときにこれを一度見つけました(あなたが遭遇している理由のために)。それは最も自然なぼかしimhoであるガウスぼかしを行います...うまくいけば、それはあなたを助けるでしょう。私はこのウェブページからそれを取得しました: Java画像処理 ...

/*
** Copyright 2005 Huxtable.com. All rights reserved.
*/

package com.jhlabs.image;

import Java.awt.image.*;

/**
 * A filter which applies Gaussian blur to an image. This is a subclass of ConvolveFilter
 * which simply creates a kernel with a Gaussian distribution for blurring.
 * @author Jerry Huxtable
 */
public class GaussianFilter extends ConvolveFilter {

    static final long serialVersionUID = 5377089073023183684L;

    protected float radius;
    protected Kernel kernel;

    /**
     * Construct a Gaussian filter
     */
    public GaussianFilter() {
        this(2);
    }

    /**
     * Construct a Gaussian filter
     * @param radius blur radius in pixels
     */
    public GaussianFilter(float radius) {
        setRadius(radius);
    }

    /**
     * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
     * @param radius the radius of the blur in pixels.
     */
    public void setRadius(float radius) {
        this.radius = radius;
        kernel = makeKernel(radius);
    }

    /**
     * Get the radius of the kernel.
     * @return the radius
     */
    public float getRadius() {
        return radius;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();

        if ( dst == null )
            dst = createCompatibleDestImage( src, null );

        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        src.getRGB( 0, 0, width, height, inPixels, 0, width );

        convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, CLAMP_EDGES);
        convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, CLAMP_EDGES);

        dst.setRGB( 0, 0, width, height, inPixels, 0, width );
        return dst;
    }

    public static void convolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) {
        float[] matrix = kernel.getKernelData( null );
        int cols = kernel.getWidth();
        int cols2 = cols/2;

        for (int y = 0; y < height; y++) {
            int index = y;
            int ioffset = y*width;
            for (int x = 0; x < width; x++) {
                float r = 0, g = 0, b = 0, a = 0;
                int moffset = cols2;
                for (int col = -cols2; col <= cols2; col++) {
                    float f = matrix[moffset+col];

                    if (f != 0) {
                        int ix = x+col;
                        if ( ix < 0 ) {
                            if ( edgeAction == CLAMP_EDGES )
                                ix = 0;
                            else if ( edgeAction == WRAP_EDGES )
                                ix = (x+width) % width;
                        } else if ( ix >= width) {
                            if ( edgeAction == CLAMP_EDGES )
                                ix = width-1;
                            else if ( edgeAction == WRAP_EDGES )
                                ix = (x+width) % width;
                        }
                        int rgb = inPixels[ioffset+ix];
                        a += f * ((rgb >> 24) & 0xff);
                        r += f * ((rgb >> 16) & 0xff);
                        g += f * ((rgb >> 8) & 0xff);
                        b += f * (rgb & 0xff);
                    }
                }
                int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff;
                int ir = PixelUtils.clamp((int)(r+0.5));
                int ig = PixelUtils.clamp((int)(g+0.5));
                int ib = PixelUtils.clamp((int)(b+0.5));
                outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
                index += height;
            }
        }
    }

    /**
     * Make a Gaussian blur kernel.
     */
    public static Kernel makeKernel(float radius) {
        int r = (int)Math.ceil(radius);
        int rows = r*2+1;
        float[] matrix = new float[rows];
        float sigma = radius/3;
        float sigma22 = 2*sigma*sigma;
        float sigmaPi2 = 2*ImageMath.PI*sigma;
        float sqrtSigmaPi2 = (float)Math.sqrt(sigmaPi2);
        float radius2 = radius*radius;
        float total = 0;
        int index = 0;
        for (int row = -r; row <= r; row++) {
            float distance = row*row;
            if (distance > radius2)
                matrix[index] = 0;
            else
                matrix[index] = (float)Math.exp(-(distance)/sigma22) / sqrtSigmaPi2;
            total += matrix[index];
            index++;
        }
        for (int i = 0; i < rows; i++)
            matrix[i] /= total;

        return new Kernel(rows, 1, matrix);
    }

    public String toString() {
        return "Blur/Gaussian Blur...";
    }
}
0
Rabbit Guy

アプリケーションで画像を頻繁に処理する場合は、ImageJ APIの使用を検討することをお勧めします。これは、ぼかしを含む非常に多くの画像処理タスクの機能を備えています。

彼らのガウスぼかしフィルターは、次の仮定を行うことにより、画像の端までぼやけます

{...}画像外のピクセルの値が最も近いエッジピクセルに等しいと想定します{...}

ImageJ APIを使用するようにコードを変更したくない場合でも、上記の仮定が問題の解決に役立つ場合があります。

詳細については、APIドキュメントのGaussianBlurフィルターを確認してください: http://rsb.info.nih.gov/ij/developer/api/ij/plugin/filter/GaussianBlur.html

0
critichu