C++ filter2D实现中的差异

C++ filter2D实现中的差异,c++,opencv,image-processing,computer-vision,convolution,C++,Opencv,Image Processing,Computer Vision,Convolution,我试图在OpenCV中实现卷积2d(filter2D),并产生了以下代码 Mat卷积2d(Mat-image,双**内核,int-W){ Mat filtered_image=image.clone(); //查找内核的中心位置(内核大小的一半) int kCenterX=W/2; int kCenterY=W/2; int xx=0; int-yy=0; cout您的代码有两个问题: 在向输出图像添加值之前,您不会将其设置为零。因此,您计算的是“输入+过滤输入”,而不仅仅是“过滤输入” 假设k

我试图在OpenCV中实现
卷积2d
filter2D
),并产生了以下代码

Mat卷积2d(Mat-image,双**内核,int-W){
Mat filtered_image=image.clone();
//查找内核的中心位置(内核大小的一半)
int kCenterX=W/2;
int kCenterY=W/2;
int xx=0;
int-yy=0;

cout您的代码有两个问题:

  • 在向输出图像添加值之前,您不会将其设置为零。因此,您计算的是“输入+过滤输入”,而不仅仅是“过滤输入”

  • 假设
    kernel
    的值很小,“input pixel*kernel value”可能会产生一个小数字,当写入
    uchar
    时,这个数字会向下舍入。将内核的每个值相加,结果会太低

  • 我建议您这样做:

    double res = 0;
    for(int x = 0; x < W; ++x){
       int xx = W - 1 - x;
       for(int y = 0; y < W; ++y){
          int yy = W - 1 - y;
          int ii = i + (x - kCenterX);
          int jj = j + (y - kCenterY);
          if( ii >= 0 && ii < image.rows && jj >= 0 && jj < image.cols) {
             res += image.at<uchar>(Point(jj, ii)) * kernel[xx][yy];
          }
       }
    }
    filtered_image.at<uchar>(Point(j, i)) = res;
    
    double res=0;
    对于(int x=0;x=0&&ii=0&&jj
    这同时解决了这两个问题。而且,这应该更快一些,因为访问输出图像会有一点开销


    对于更快的速度,考虑到越界检查(在内部循环中<代码>如果< /代码>)减慢您的代码,并且对于大多数像素(几乎没有像素在图像边缘附近)是完全不必要的。相反,您可以将循环拆分为<代码> [ 0,KcTyx] ,<代码> [KCyxx,Simult.LoxKCcTxx ]。

    [image.rows kCenterX,image.rows]
    。中间的循环通常是最大的,不需要检查越界读取。

    您的代码有两个问题:

  • 在向输出图像添加值之前,您不会将其设置为零。因此,您计算的是“输入+过滤输入”,而不仅仅是“过滤输入”

  • 假设
    kernel
    的值很小,“input pixel*kernel value”可能会产生一个小数字,当写入
    uchar
    时,这个数字会向下舍入。将内核的每个值相加,结果会太低

  • 我建议您这样做:

    double res = 0;
    for(int x = 0; x < W; ++x){
       int xx = W - 1 - x;
       for(int y = 0; y < W; ++y){
          int yy = W - 1 - y;
          int ii = i + (x - kCenterX);
          int jj = j + (y - kCenterY);
          if( ii >= 0 && ii < image.rows && jj >= 0 && jj < image.cols) {
             res += image.at<uchar>(Point(jj, ii)) * kernel[xx][yy];
          }
       }
    }
    filtered_image.at<uchar>(Point(j, i)) = res;
    
    double res=0;
    对于(int x=0;x=0&&ii=0&&jj
    这同时解决了这两个问题。而且,这应该更快一些,因为访问输出图像会有一点开销


    对于更快的速度,考虑到越界检查(在内部循环中<代码>如果< /代码>)减慢您的代码,并且对于大多数像素(几乎没有像素在图像边缘附近)是完全不必要的。相反,您可以将循环拆分为<代码> [ 0,KcTyx] ,<代码> [KCyxx,Simult.LoxKCcTxx ]。

    [image.rows kCenterX,image.rows]
    。中间循环通常是最大的,不需要检查越界读取。

    并使用cv::saturate\u cast正确分配给uchar,例如:

    filtered_image.at<uchar>(Point(j, i)) = cv::saturate_cast<uchar>(res);
    
    filtered_image.at(点(j,i))=cv::saturate_cast(res);
    
    并使用cv::saturate\u cast正确分配给uchar,例如:

    filtered_image.at<uchar>(Point(j, i)) = cv::saturate_cast<uchar>(res);
    
    filtered_image.at(点(j,i))=cv::saturate_cast(res);
    
    非常感谢您提供的描述性但简洁的答案!第一个问题是一个很好的答案。我也没有意识到可能存在的小值问题。我在完成研究生课程后才开始自己实现CV算法,这是一个相当快的节奏!非常感谢您提供的描述性但简洁的答案!我遇到的第一个问题是这是一个很好的发现。我也没有意识到可能存在的小值问题。我只是在完成研究生课程后才开始自己实现CV算法,这是一个非常快的节奏!