web-dev-qa-db-ja.com

Opencv-filter2D()メソッドは実際にどのように機能しますか?

Filter2Dのソースコードを探しましたが見つかりませんでした。 Visual c ++もできませんでした。ここにfilter2Dアルゴリズムの専門家はいますか?私は知っています それがどのように機能するはずです しかしそれが実際にどのように機能するかはわかりません。物事をテストするために独自のfilter2d()関数を作成しましたが、結果はopencvs filter2D()とは大幅に異なります。これが私のコードです:

Mat myfilter2d(Mat input, Mat filter){

Mat dst = input.clone();
cout << " filter data successfully found.  Rows:" << filter.rows << " cols:" << filter.cols << " channels:" << filter.channels() << "\n";
cout << " input data successfully found.  Rows:" << input.rows << " cols:" << input.cols << " channels:" << input.channels() << "\n";

for (int i = 0-(filter.rows/2);i<input.rows-(filter.rows/2);i++){
    for (int j = 0-(filter.cols/2);j<input.cols-(filter.cols/2);j++){  //adding k and l to i and j will make up the difference and allow us to process the whole image
        float filtertotal = 0;
        for (int k = 0; k < filter.rows;k++){
            for (int l = 0; l < filter.rows;l++){
                if(i+k >= 0 && i+k < input.rows && j+l >= 0 && j+l < input.cols){  //don't try to process pixels off the endge of the map
                    float a = input.at<uchar>(i+k,j+l);
                    float b = filter.at<float>(k,l);
                    float product = a * b;
                    filtertotal += product;
                }
            }
        }
        //filter all proccessed for this pixel, write it to dst
        st.at<uchar>(i+(filter.rows/2),j+(filter.cols/2)) = filtertotal;

    }
}
return dst;
}

誰かが私の実装に何か問題があると思いますか? (遅いことに加えて)

これが私の実行です:

  cvtColor(src,src_grey,CV_BGR2GRAY);
  Mat dst = myfilter2d(src_grey,filter);
  imshow("myfilter2d",dst);
  filter2D(src_grey,dst2,-1,filter);
  imshow("filter2d",dst2);

これが私のカーネルです:

float megapixelarray[basesize][basesize] = {
            {1,1,-1,1,1},
            {1,1,-1,1,1},
            {1,1,1,1,1},
            {1,1,-1,1,1},
            {1,1,-1,1,1}
            };

そして ここに(実質的に異なる)結果があります:

考え、誰か?

編集:ブリアンの答えのおかげで私はこのコードを追加しました:

//normalize the kernel so its sum = 1
Scalar mysum = sum(dst);
dst = dst / mysum[0];   //make sure its not 0
dst = dst * -1;  //show negetive

そしてfilter2dはよりよく働きました。特定のフィルターは完全に一致し、Sobelのような他のフィルターは 惨めに失敗します。

私は実際のアルゴリズムに近づいていますが、まだそこにはありません。他に何かアイデアがありますか?

13
john ktejik

問題はおそらくスケールの問題だと思います。入力画像が8ビット画像の場合、ほとんどの場合、畳み込みによって最大値255を超える値が生成されます。

実装では、ラップアラウンド値を取得しているように見えますが、ほとんどのOpenCV関数は、最大(または最小)値に制限することでオーバーフローを処理します。これが、OpenCVの関数の出力のほとんどが白である理由と、出力で同心円状の形状が得られる理由を説明しています。

これを説明するには、すべての値をフィルターの合計で割ってmegapixelarrayフィルターを正規化します(つまり、フィルター値の合計が1であることを確認します)。

たとえば、このフィルターの代わりに(合計= 10):

1 1 1
1 2 1
1 1 1

このフィルターを試してください(合計= 1):

0.1 0.1 0.1
0.1 0.2 0.1
0.1 0.1 0.1
11
Brian L

Filter2Dを手動で作成するための私の解決策は次のとおりです。

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

using namespace cv;
using namespace std;

int main(int argc, const char * argv[]) {    
    Mat img;
    Mat img_conv;
    Mat my_kernel;
    Mat my_conv;

    // Controlling if the image is loaded correctly
    img = imread("my_image.jpg",CV_LOAD_IMAGE_COLOR);
    if(! img.data )
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }
    imshow("original image", img);
    img.convertTo(img, CV_64FC3);

    int kernel_size;   // permitted sizes: 3, 5, 7, 9 etc
    cout << "Select the size of kernel (it should be an odd number from 3 onwards): \n" << endl;
    cin >> kernel_size;

    // Defining the kernel here
    int selection;
    cout << "Select the type of kernel:\n" << "1. Identity Operator \n2. Mean Filter \n3. Spatial shift \n4. Sharpening\n-> ";
    cin >> selection;
    switch (selection){
        case 1:
            my_kernel = (Mat_<double>(kernel_size,kernel_size) << 0, 0, 0, 0, 1, 0, 0, 0, 0);
            break;
        case 2:
            my_kernel = (Mat_<double>(kernel_size,kernel_size) << 1, 1, 1, 1, 1, 1, 1, 1, 1) / ( kernel_size * kernel_size);
            break;
        case 3:
            my_kernel = (Mat_<double>(kernel_size,kernel_size) << 0, 0, 0, 0, 0, 1, 0, 0, 0);
            break;
        case 4:
            my_kernel = (Mat_<double>(kernel_size,kernel_size) << -1, -1, -1, -1, 17, -1, -1, -1, -1) / ( kernel_size * kernel_size);
            break;
        default:
            cerr << "Invalid selection";
            return 1;
            break;
    }
    cout << "my kernel:\n "<<my_kernel << endl;

    // Adding the countour of nulls around the original image, to avoid border problems during convolution
    img_conv = Mat::Mat(img.rows + my_kernel.rows - 1, img.cols + my_kernel.cols - 1, CV_64FC3, CV_RGB(0,0,0));

    for (int x=0; x<img.rows; x++) {
        for (int y=0; y<img.cols; y++) {
                img_conv.at<Vec3d>(x+1,y+1)[0] = img.at<Vec3d>(x,y)[0];
                img_conv.at<Vec3d>(x+1,y+1)[1] = img.at<Vec3d>(x,y)[1];
                img_conv.at<Vec3d>(x+1,y+1)[2] = img.at<Vec3d>(x,y)[2];
        }
    }

    //Performing the convolution
    my_conv = Mat::Mat(img.rows, img.cols, CV_64FC3, CV_RGB(0,0,0));
    for (int x=(my_kernel.rows-1)/2; x<img_conv.rows-((my_kernel.rows-1)/2); x++) {
        for (int y=(my_kernel.cols-1)/2; y<img_conv.cols-((my_kernel.cols-1)/2); y++) {
            double comp_1=0;
            double comp_2=0;
            double comp_3=0;
                for (int u=-(my_kernel.rows-1)/2; u<=(my_kernel.rows-1)/2; u++) {
                    for (int v=-(my_kernel.cols-1)/2; v<=(my_kernel.cols-1)/2; v++) {
                        comp_1 = comp_1 + ( img_conv.at<Vec3d>(x+u,y+v)[0] * my_kernel.at<double>(u + ((my_kernel.rows-1)/2) ,v + ((my_kernel.cols-1)/2)));
                        comp_2 = comp_2 + ( img_conv.at<Vec3d>(x+u,y+v)[1] * my_kernel.at<double>(u + ((my_kernel.rows-1)/2),v + ((my_kernel.cols-1)/2)));
                        comp_3 = comp_3 + ( img_conv.at<Vec3d>(x+u,y+v)[2] * my_kernel.at<double>(u +  ((my_kernel.rows-1)/2),v + ((my_kernel.cols-1)/2)));
                    }
                }
            my_conv.at<Vec3d>(x-((my_kernel.rows-1)/2),y-(my_kernel.cols-1)/2)[0] = comp_1;
            my_conv.at<Vec3d>(x-((my_kernel.rows-1)/2),y-(my_kernel.cols-1)/2)[1] = comp_2;
            my_conv.at<Vec3d>(x-((my_kernel.rows-1)/2),y-(my_kernel.cols-1)/2)[2] = comp_3;
        }
    }
    my_conv.convertTo(my_conv, CV_8UC3);
    imshow("convolution - manual", my_conv);

    // Performing the filtering using the opencv funtions
    Mat dst;
    filter2D(img, dst, -1 , my_kernel, Point( -1, -1 ), 0, BORDER_DEFAULT );
    dst.convertTo(dst, CV_8UC3);
    imshow("convlution - opencv", dst);


    waitKey();
    return 0;
}
0
Umar Spa