filter2D实现中的差异
Differences in filter2D implementation
我试图实现convolute2D
(OpenCV中的filter2D
),并产生了以下代码。
Mat convolute2D(Mat image, double** kernel, int W){
Mat filtered_image = image.clone();
// find center position of kernel (half of kernel size)
int kCenterX = W / 2;
int kCenterY = W / 2;
int xx = 0;
int yy = 0;
cout << endl << "Performing convolution .." << endl;
cout << "Image Size : " << image.rows << ", " << image.cols <<endl;
for (int i = 0; i < image.rows; ++i){
for (int j = 0; j < image.cols; ++j){
for(int x = 0; x < W; ++x){
xx = W - 1 - x;
for(int y = 0; y < W; ++y){
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) {
filtered_image.at<uchar>(Point(j, i)) += image.at<uchar>(Point(jj, ii)) * kernel[xx][yy];
}
}
}
}
}
return filtered_image;
}
假设我们总是有一个平方核。但我的结果与filter2D
有很大不同。是因为可能溢出还是我的实现有问题?
感谢
您的代码有两个问题:
-
在添加值之前,您不会将输出图像设置为零。因此,您计算的是"输入+过滤输入",而不仅仅是"过滤输入"。
-
假设
kernel
的值很小,"输入像素*内核值"可能会产生一个小数字,当写入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;
这同时解决了这两个问题。此外,这应该更快一点,因为访问输出图像需要一些开销。
要想获得更快的速度,请考虑检查越界读取(内部循环中的if
)会显著降低代码的速度,并且对于大多数像素来说是完全不必要的(因为图像边缘附近的像素很少)。相反,您可以将循环拆分为[0,kCenterX]
、[kCenterX,image.rows-kCenterX]
和[image.rows-kCenterX,image.rows]
。中间循环通常是迄今为止最大的,不需要检查越界读取。
使用cv::saturate_cast对uchar进行正确赋值,例如:
filtered_image.at<uchar>(Point(j, i)) = cv::saturate_cast<uchar>(res);
相关文章:
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- filter2D实现中的差异