16

誰かがこれほどばかげたことを以前に試みたことがあることを期待して、私はこれをそこに捨てています. 私の目標は、入力画像を取り込み、各ピクセルの周囲の小さなウィンドウの標準偏差に基づいてセグメント化することです。基本的に、これは数学的にガウスまたはボックス フィルターに似ている必要があります。つまり、コンパイル時 (または実行時) にユーザーが指定した各ピクセルのウィンドウ サイズに適用され、宛先配列には各ピクセルの SD 情報が含まれます。オリジナルと同じサイズの画像で。

アイデアは、HSV 空間の画像でこれを行うことです。これにより、均一な色の領域 (つまり、Hue 平面と Sat 平面に小さなローカル SD を持つ領域) を簡単に見つけて、より詳細な処理のために画像からそれらを抽出できます。

質問は、これまでにこのようなカスタム フィルターを作成したことがある人はいますか? ガウスやブラーに使用されるような単純なボックス タイプのフィルター カーネルで SD を実行する方法がわからないので、FilterEngine コンストラクトを使用する必要があると推測しています。また、これを C++ で行っていることを忘れていました。

あなたのアドバイスと熟考は大歓迎です。

4

2 に答える 2

46

ウィキペディアには、標準偏差フィルターに使用できる標準偏差の優れた説明があります。

基本的には、ボックス フィルターで画像をぼかし、ボックス フィルターで画像の 2 乗をぼかし、その差の平方根を取ります。

更新:これは、おそらくウィキペディアの方程式でよりよく示されます... ここに画像の説明を入力

blurOpenCV関数は、関心のある近傍の期待値(つまり、E[X] 別名標本平均) を表すものと考えることができます。この場合のランダム サンプル X は、ローカル近傍のイメージ ピクセルによって表されます。sqrt(blur(img^2) - blur(img)^2)したがって、上記の同等性を使用すると、OpenCVのようなものになります。このようにすると、局所平均と標準偏差を計算できます。

また、数学的な証明に興味がある場合に備えて。この等価性は、分散の計算式として知られています。

OpenCVでこれを行う方法は次のとおりです。

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;

Mat mat2gray(const Mat& src)
{
    Mat dst;
    normalize(src, dst, 0.0, 1.0, NORM_MINMAX);
    return dst;
}

int main()
{
    Mat image = imread("coke-can.jpg", 0);

    Mat image32f;
    image.convertTo(image32f, CV_32F);

    Mat mu;
    blur(image32f, mu, Size(3, 3));

    Mat mu2;
    blur(image32f.mul(image32f), mu2, Size(3, 3));

    Mat sigma;
    cv::sqrt(mu2 - mu.mul(mu), sigma);

    imshow("coke", mat2gray(image32f));
    imshow("mu", mat2gray(mu));
    imshow("sigma",mat2gray(sigma));
    waitKey();
    return 0;
}

これにより、次の画像が生成されます。

オリジナル

ここに画像の説明を入力

平均

ここに画像の説明を入力

標準偏差

ここに画像の説明を入力

それが役立つことを願っています!

于 2012-07-12T20:16:04.343 に答える
0

これをより一般的な方法で使用したい場合、これは nan 値を生成できます

ゼロに近い値は、「負」になることがあります。

Mat sigma;
cv::sqrt(mu2 - mu.mul(mu), sigma);

正しい方法は

Mat sigma;
cv::sqrt(cv::abs(mu2 - mu.mul(mu)), sigma);
于 2020-12-10T20:38:45.030 に答える