2012-12-20 118 views
11

我沒有找到Filter2D的源代碼,但找不到它。 Visual C++也不是。 這裏有filter2D算法的專家嗎?我知道how it's supposed to work,但不知道它是如何工作的。我做了我自己的filter2d()函數來測試,結果與opencvs filter2D()有很大的不同。這裏是我的代碼:Opencv - 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} 
      }; 

而且here are the (substantially different) results:

思想,任何人嗎?

編輯:感謝Brians答案我添加了這個代碼:

//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,fail miserably.

我正在接近實際的算法,但還沒有。任何人有任何想法?

+0

+1好問的問題!你展示了你的實現,上下文以及結果。 –

+0

我最近一直在玩相同的概念,比較opencv實現與自定義的實現。看來,至少在內核總和爲0的情況下,filter2d可能仍然會對其進行縮放,以使max(abs(kernel))爲1. – Bovaz

回答

9

我認爲這個問題可能是規模的問題:如果你的輸入圖像是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 
+0

您是對的。 C++正在將我的花車變成Uchars,顯然是通過截斷。所以每當數字超過255時,它就會跳回到零,從而產生很酷的同心效應。 –

+0

C++中的無符號整型實際上工作模2^N。溢出是明確定義的,但並非總是意圖。此外,「封頂」操作通常被稱爲「飽和」。 – MSalters

-1

這裏是我的手動創建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; 
}