C++ filter2D实现中的差异
我试图在OpenCV中实现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
卷积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算法,这是一个非常快的节奏!