3

私はガウス フィルターを書いています。私の目標は、Photoshop のガウスぼかしフィルターを可能な限り一致させることです。初めての画像加工です。私が持っているいくつかの問題/質問は...

私のフィルターで画像をさらにぼかすと画像が暗くなりますが、Photoshop の画像は明るく見えます。

私が使用している偏差値 (私のコードでは「シグマ」) は r/3 で、ガウス曲線は行列内で約 0.0001 に近づいています...この値を決定するより良い方法はありますか?

Photoshop (またはほとんどの人) は、このタイプのぼかしの画像境界をどのように処理しますか?

int matrixDimension = (radius*2)+1;
float sigma = radius/3;
float twoSigmaSquared = 2*pow(sigma, 2);
float oneOverSquareRootOfTwoPiSigmaSquared = 1/(sqrt(M_PI*twoSigmaSquared));

float kernel[matrixDimension];

int index = 0;
for (int offset = -radius; offset <= radius; offset++) {

    float xSquared = pow(offset, 2);
    float exponent = -(xSquared/twoSigmaSquared);
    float eToThePower = pow(M_E, exponent);
    float multFactor = oneOverSquareRootOfTwoPiSigmaSquared*eToThePower;

    kernel[index] = multFactor;

    index++;
}

//Normalize the kernel such that all its values will add to 1
float sum = 0;
for (int i = 0; i < matrixDimension; i++) {
    sum += kernel[i];
}
for (int i = 0; i < matrixDimension; i++) {
    kernel[i] = kernel[i]/sum;
}

//Blur horizontally
for (int row = 0; row < imageHeight; row++) {
    for (int column = 0; column < imageWidth; column++) {

        int currentPixel = (row*imageWidth)+column;

        int sum1 = 0;
        int sum2 = 0;
        int sum3 = 0;
        int sum4 = 0;

        int index = 0;
        for (int offset = -radius; offset <= radius; offset++) {
            if (!(column+offset < 0) && !(column+offset > imageWidth-1)) {

                int firstByteOfPixelWereLookingAtInSrcData = (currentPixel+offset)*4;

                int in1 = srcData[firstByteOfPixelWereLookingAtInSrcData];
                int in2 = srcData[firstByteOfPixelWereLookingAtInSrcData+1];
                int in3 = srcData[firstByteOfPixelWereLookingAtInSrcData+2];
                int in4 = srcData[firstByteOfPixelWereLookingAtInSrcData+3];

                sum1 += (int)(in1 * kernel[index]);
                sum2 += (int)(in2 * kernel[index]);
                sum3 += (int)(in3 * kernel[index]);
                sum4 += (int)(in4 * kernel[index]);
            }

            index++;
        }

        int currentPixelInData = currentPixel*4;

        destData[currentPixelInData] = sum1;
        destData[currentPixelInData+1] = sum2;
        destData[currentPixelInData+2] = sum3;
        destData[currentPixelInData+3] = sum4;

    }
}

//Blur vertically
for (int row = 0; row < imageHeight; row++) {
    for (int column = 0; column < imageWidth; column++) {

        int currentPixel = (row*imageWidth)+column;

        int sum1 = 0;
        int sum2 = 0;
        int sum3 = 0;
        int sum4 = 0;

        int index = 0;
        for (int offset = -radius; offset <= radius; offset++) {
            if (!(row+offset < 0) && !(row+offset > imageHeight-1)) {

                int firstByteOfPixelWereLookingAtInSrcData = (currentPixel+(offset*imageWidth))*4;

                int in1 = destData[firstByteOfPixelWereLookingAtInSrcData];
                int in2 = destData[firstByteOfPixelWereLookingAtInSrcData+1];
                int in3 = destData[firstByteOfPixelWereLookingAtInSrcData+2];
                int in4 = destData[firstByteOfPixelWereLookingAtInSrcData+3];

                sum1 += (int)(in1 * kernel[index]);
                sum2 += (int)(in2 * kernel[index]);
                sum3 += (int)(in3 * kernel[index]);
                sum4 += (int)(in4 * kernel[index]);
            }

            index++;
        }

        int currentPixelInData = currentPixel*4;

        finalData[currentPixelInData] = sum1;
        finalData[currentPixelInData+1] = sum2;
        finalData[currentPixelInData+2] = sum3;
        finalData[currentPixelInData+3] = sum4;

    }
}
4

2 に答える 2

8

フィルターをリバース エンジニアリングするには、そのインパルス応答を見つける必要があります。32 などの非常に暗い値の背景に、223 などのほぼ白のピクセルを配置します。0 と 255 は使用しないでください。一部のフィルターは、開始値を超える値を作成しようとするためです。この画像に対してフィルターを実行し、出力値を取得して 0.0 から 1.0 に引き伸ばします(value-32)/(223-32)。これで、フィルターをエミュレートするために必要な正確な重みが得られました。

画像のエッジを処理する方法はたくさんあります。フィルターの重みを取得して合計し、結果をその合計で割ることをお勧めします。エッジを超えようとしている場合は、ピクセル値とそのピクセルのフィルター ウェイトの両方に 0.0 を使用します。

于 2011-03-05T03:45:56.687 に答える
1

境界条件は、何をしているのか、どのような種類のデータを扱っているのかに正確に依存する場合がありますが、一般的な目的の画像操作では、境界の値を画像の端を超えて拡張するのが最善だと思います。もちろん文字通りではありませんが、フィルターが画像の境界線の外側にあるピクセルを読み取ろうとすると、画像の端にある最も近いピクセルの値に置き換えられます。これは、行を 0 と高さの間に、列を 0 と幅の間にクランプすることと同じです。

于 2011-03-05T02:44:06.920 に答える