我正在尝试实现拉普拉斯滤镜以锐化图像。 但是结果有点灰色,我不知道我的代码出了什么问题。
到目前为止,这是我的工作
img = imread("moon.png", 0);
Mat convoSharp() {
//creating new image
Mat res = img.clone();
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
res.at<uchar>(y, x) = 0.0;
}
}
//variable declaration
//change -5 to -4 for original result.
int filter[3][3] = { {0,1,0},{1,-4,1},{0,1,0} };
//int filter[3][3] = { {-1,-2,-1},{0,0,0},{1,2,1} };
int height = img.rows;
int width = img.cols;
int **temp = new int*[height];
for (int i = 0; i < height; i++) {
temp[i] = new int[width];
}
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
temp[i][j] = 0;
}
}
int filterHeight = 3;
int filterWidth = 3;
int newImageHeight = height - filterHeight + 1;
int newImageWidth = width - filterWidth + 1;
int i, j, h, w;
//convolution
for (i = 0; i < newImageHeight; i++) {
for (j = 0; j < newImageWidth; j++) {
for (h = i; h < i + filterHeight; h++) {
for (w = j; w < j + filterWidth; w++) {
temp[i][j] += filter[h - i][w - j] * (int)img.at<uchar>(h, w);
}
}
}
}
//find max and min
int max = 0;
int min = 100;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (temp[i][j] > max) {
max = temp[i][j];
}
if (temp[i][j] < min) {
min = temp[i][j];
}
}
}
//clamp 0 - 255
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
res.at<uchar>(i, j) = 0 + (temp[i][j] - min)*(255 - 0) / (max - min);
}
}
//empty the temp array
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
temp[i][j] = 0;
}
}
//img - res and store it in temp array
for (int y = 0; y < res.rows; y++) {
for (int x = 0; x < res.cols; x++) {
//int a = (int)img.at<uchar>(y, x) - (int)res.at<uchar>(y, x);
//cout << a << endl;
temp[y][x] = (int)img.at<uchar>(y, x) - (int)res.at<uchar>(y, x);
}
}
//find the new max and min
max = 0;
min = 100;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (temp[i][j] > max) {
max = temp[i][j];
}
if (temp[i][j] < min) {
min = temp[i][j];
}
}
}
//clamp it back to 0-255
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
res.at<uchar>(i, j) = 0 + (temp[i][j] - min)*(255 - 0) / (max - min);
temp[i][j] = (int)res.at<uchar>(i, j);
}
}
return res;
}
这是结果
正如您在上面的代码中看到的那样,我已经将像素值标准化为0-255。我仍然不知道这里出了什么问题。这里有人可以解释为什么吗?
答案 0 :(得分:0)
问题是您正在夹紧并重新缩放图像。看一下月亮的左下边界:在非常暗的像素旁边有非常亮的像素,然后在明亮的像素旁边还有一些灰色像素。您的锐化滤镜将真正刺破该明亮的边框并增加最大值。同样,黑色像素将进一步减少。
然后确定最小和最大并重新缩放整个图像。这必然意味着当以以前的灰度显示时,整个图像将失去对比度,因为您的滤镜输出的像素值大于255而小于0。
在输出图像中仔细查看月亮的边界:
有一个黑色的光环(新的0)和一个明亮而锋利的边缘(新的255)。 (浏览器图像的缩放使此屏幕截图变得不那么清晰,请查看原始输出)。缩放后,其他所有内容均被压缩,因此以前的黑色(0)现在变为深灰色。 >
答案 1 :(得分:0)
灰色是因为as Max suggested in his answer,您正在缩放到0-255的范围,而不是钳位(如代码中的注释所建议的那样)。
但是,这并不是代码中的所有问题。 Laplace运算符的输出包含负值。您可以将它们很好地存储在int
中。但是随后您可以缩放并复制到char
。不要那样做!
您需要将Laplace的结果原样添加到图像中。这样,图像中的某些像素会变暗,而某些会变亮。这就是导致边缘显得更清晰的原因。
仅跳过代码中的某些循环,并保留执行temp = img - temp
的循环。这样一来,您可以自由缩放或限制到输出范围,然后投射到char
。
要进行钳位,只需将任何像素值设置为0到0以下,以及将任何像素值设置为255到255以上。不要像这样做那样计算最小/最大和缩放,因为这样会降低对比度并在图像上产生灰色阴影。
您最近的问题非常相似(尽管代码中的问题有所不同),请再次阅读my answer there,它提出了一种进一步简化代码以使img-Laplace
成为单个卷积的方法。 / p>