拉普拉斯滤波器 opencv c++
Laplacian Filter opencv c++
我在学习 OpenCV 中的过滤器,但我对拉普拉斯过滤器有点困惑。我的结果与 OpenCV 库中的拉普拉斯滤波器有很大不同。
首先,我对图像使用高斯滤波器:
Mat filtroGauss(Mat src){
Mat gauss = src.clone();
Mat temp(src.rows+2,src.cols+2,DataType<uchar>::type);
int y,x;
for (y=0; y<src.rows; y++){
for (x=0; x<src.cols; x++) temp.at<uchar>(y+1,x+1) = src.at<uchar>(y,x);
}
int mask[lenMask*lenMask];
mask[0] = mask[2] = mask[6] = mask[8] = 1;
mask[1] = mask[3] = mask[5] = mask[7] = 2;
mask[4] = 4;
int denominatore = 0;
for (int i=0; i<lenMask*lenMask; i++) denominatore += mask[i];
int value[lenMask*lenMask];
for(y=0; y<src.rows; y++){
for (x=0; x<src.cols; x++){
value[0] = temp.at<uchar>(y-1,x-1)*mask[0];
value[1] = temp.at<uchar>(y-1,x)*mask[1];
value[2] = temp.at<uchar>(y-1,x+1)*mask[2];
value[3] = temp.at<uchar>(y,x-1)*mask[3];
value[4] = temp.at<uchar>(y,x)*mask[4];
value[5] = temp.at<uchar>(y,x+1)*mask[5];
value[6] = temp.at<uchar>(y+1,x-1)*mask[6];
value[7] = temp.at<uchar>(y+1,x)*mask[7];
value[8] = temp.at<uchar>(y+1,x+1)*mask[8];
int avg = 0;
for(int i=0; i<lenMask*lenMask; i++)avg+=value[i];
avg = avg/denominatore;
gauss.at<uchar>(y,x) = avg;
}
}
return gauss;
}
然后我用拉普拉斯函数:
L(y,x) = f(y-1,x) + f(y+1,x) + f(y,x-1) + f(y,x+1) + 4*f(y,x)
Mat filtroLaplace(Mat src){
Mat output = src.clone();
Mat temp = src.clone();
int y,x;
for (y =1; y<src.rows-1; y++){
for(x =1; x<src.cols-1; x++){
output.at<uchar>(y,x) = temp.at<uchar>(y-1,x) + temp.at<uchar>(y+1,x) + temp.at<uchar>(y,x-1) + temp.at<uchar>(y,x+1) -4*( temp.at<uchar>(y,x));
}
}
return output;
}
这是我的代码的最终结果:
OpenCV 结果:
让我们稍微重写一下函数,这样更容易讨论:
cv::Mat filtroLaplace(cv::Mat src)
{
cv::Mat output = src.clone();
for (int y = 1; y < src.rows - 1; y++) {
for (int x = 1; x < src.cols - 1; x++) {
int sum = src.at<uchar>(y - 1, x)
+ src.at<uchar>(y + 1, x)
+ src.at<uchar>(y, x - 1)
+ src.at<uchar>(y, x + 1)
- 4 * src.at<uchar>(y, x);
output.at<uchar>(y, x) = sum;
}
}
return output;
}
问题的根源是 sum
。让我们通过两个极端来检查它在该算法范围内的范围:
- 黑色像素,周围有4个白色。这意味着
255 + 255 + 255 + 255 - 4 * 0 = 1020
.
- 白色像素,周围有4个黑色。这意味着
0 + 0 + 0 + 0 - 4 * 255 = -1020
.
当您执行 output.at<uchar>(y, x) = sum;
时,会隐式地将 int
转换回 unsigned char
-- 高阶位会被截断并且值会溢出。
处理这种情况的正确方法(OpenCV 采用的方法)是在实际投射之前执行饱和。本质上
if (sum < 0) {
sum = 0;
} else if (sum > 255) {
sum = 255;
}
OpenCV 提供函数 cv::saturate_cast<T>
来做到这一点。
还有一个问题是您没有处理输入图像的边缘 rows/columns——您只是将它们保留为原始值。既然你没有问这个问题,我就把解决这个问题作为 reader.
的练习
代码:
cv::Mat filtroLaplace(cv::Mat src)
{
cv::Mat output = src.clone();
for (int y = 1; y < src.rows - 1; y++) {
for (int x = 1; x < src.cols - 1; x++) {
int sum = src.at<uchar>(y - 1, x)
+ src.at<uchar>(y + 1, x)
+ src.at<uchar>(y, x - 1)
+ src.at<uchar>(y, x + 1)
- 4 * src.at<uchar>(y, x);
output.at<uchar>(y, x) = cv::saturate_cast<uchar>(sum);
}
}
return output;
}
示例输入:
更正 filtroLaplace
的输出:
cv::Laplacian
的输出:
我在学习 OpenCV 中的过滤器,但我对拉普拉斯过滤器有点困惑。我的结果与 OpenCV 库中的拉普拉斯滤波器有很大不同。
首先,我对图像使用高斯滤波器:
Mat filtroGauss(Mat src){
Mat gauss = src.clone();
Mat temp(src.rows+2,src.cols+2,DataType<uchar>::type);
int y,x;
for (y=0; y<src.rows; y++){
for (x=0; x<src.cols; x++) temp.at<uchar>(y+1,x+1) = src.at<uchar>(y,x);
}
int mask[lenMask*lenMask];
mask[0] = mask[2] = mask[6] = mask[8] = 1;
mask[1] = mask[3] = mask[5] = mask[7] = 2;
mask[4] = 4;
int denominatore = 0;
for (int i=0; i<lenMask*lenMask; i++) denominatore += mask[i];
int value[lenMask*lenMask];
for(y=0; y<src.rows; y++){
for (x=0; x<src.cols; x++){
value[0] = temp.at<uchar>(y-1,x-1)*mask[0];
value[1] = temp.at<uchar>(y-1,x)*mask[1];
value[2] = temp.at<uchar>(y-1,x+1)*mask[2];
value[3] = temp.at<uchar>(y,x-1)*mask[3];
value[4] = temp.at<uchar>(y,x)*mask[4];
value[5] = temp.at<uchar>(y,x+1)*mask[5];
value[6] = temp.at<uchar>(y+1,x-1)*mask[6];
value[7] = temp.at<uchar>(y+1,x)*mask[7];
value[8] = temp.at<uchar>(y+1,x+1)*mask[8];
int avg = 0;
for(int i=0; i<lenMask*lenMask; i++)avg+=value[i];
avg = avg/denominatore;
gauss.at<uchar>(y,x) = avg;
}
}
return gauss;
}
然后我用拉普拉斯函数:
L(y,x) = f(y-1,x) + f(y+1,x) + f(y,x-1) + f(y,x+1) + 4*f(y,x)
Mat filtroLaplace(Mat src){
Mat output = src.clone();
Mat temp = src.clone();
int y,x;
for (y =1; y<src.rows-1; y++){
for(x =1; x<src.cols-1; x++){
output.at<uchar>(y,x) = temp.at<uchar>(y-1,x) + temp.at<uchar>(y+1,x) + temp.at<uchar>(y,x-1) + temp.at<uchar>(y,x+1) -4*( temp.at<uchar>(y,x));
}
}
return output;
}
这是我的代码的最终结果:
OpenCV 结果:
让我们稍微重写一下函数,这样更容易讨论:
cv::Mat filtroLaplace(cv::Mat src)
{
cv::Mat output = src.clone();
for (int y = 1; y < src.rows - 1; y++) {
for (int x = 1; x < src.cols - 1; x++) {
int sum = src.at<uchar>(y - 1, x)
+ src.at<uchar>(y + 1, x)
+ src.at<uchar>(y, x - 1)
+ src.at<uchar>(y, x + 1)
- 4 * src.at<uchar>(y, x);
output.at<uchar>(y, x) = sum;
}
}
return output;
}
问题的根源是 sum
。让我们通过两个极端来检查它在该算法范围内的范围:
- 黑色像素,周围有4个白色。这意味着
255 + 255 + 255 + 255 - 4 * 0 = 1020
. - 白色像素,周围有4个黑色。这意味着
0 + 0 + 0 + 0 - 4 * 255 = -1020
.
当您执行 output.at<uchar>(y, x) = sum;
时,会隐式地将 int
转换回 unsigned char
-- 高阶位会被截断并且值会溢出。
处理这种情况的正确方法(OpenCV 采用的方法)是在实际投射之前执行饱和。本质上
if (sum < 0) {
sum = 0;
} else if (sum > 255) {
sum = 255;
}
OpenCV 提供函数 cv::saturate_cast<T>
来做到这一点。
还有一个问题是您没有处理输入图像的边缘 rows/columns——您只是将它们保留为原始值。既然你没有问这个问题,我就把解决这个问题作为 reader.
的练习代码:
cv::Mat filtroLaplace(cv::Mat src)
{
cv::Mat output = src.clone();
for (int y = 1; y < src.rows - 1; y++) {
for (int x = 1; x < src.cols - 1; x++) {
int sum = src.at<uchar>(y - 1, x)
+ src.at<uchar>(y + 1, x)
+ src.at<uchar>(y, x - 1)
+ src.at<uchar>(y, x + 1)
- 4 * src.at<uchar>(y, x);
output.at<uchar>(y, x) = cv::saturate_cast<uchar>(sum);
}
}
return output;
}
示例输入:
更正 filtroLaplace
的输出:
cv::Laplacian
的输出: