我正在尝试使用卷积进行边缘检测。我认为我需要在卷积后对图像进行标准化。
我正在使用此处指定的卷积矩阵: https://en.wikipedia.org/wiki/Kernel_(image_processing)#Convolution
附件是一些r代码,以及源和输出图像......
require(jpeg)
myjpg <- readJPEG("mtg.jpg")
grayImg <- myjpg[,,1]+myjpg[,,2]+myjpg[,,3] # reduce to gray
grayImg <- grayImg/max(grayImg) # normalize
dim(grayImg)
convolve <- function(img, f){
newimg <- img
radius <- as.integer(nrow(f)/2)+1
print(radius)
for(i in c(1:nrow(img))){
for(j in c(1:ncol(img))){
f_sub <- f[c(max(1,radius-i+1):min(nrow(f),nrow(img)-i+radius)),c(max(1,radius-j+1):min(ncol(f),ncol(img)-j+radius))]
img_sub <- img[c(max(1,i-radius+1):min(nrow(img),i+radius-1)),c(max(1,j-radius+1):min(ncol(img),j+radius-1))]
wavg <- sum(as.vector(f_sub)*as.vector(img_sub))# / sum(as.vector(f_sub)) # todo, not sure about this division
newimg[i,j] <- wavg
}
}
return(newimg)
}
edgeFilter <- matrix(c(-1,-1,-1,-1,8,-1,-1,-1,-1), ncol = 3)
outimg <- convolve(grayImg,edgeFilter)
outimg <- outimg - min(outimg)
outimg <- outimg/max(outimg)
plot(c(0,1),c(0,1),t='n')
rasterImage(outimg, 0,0,1,1)
处理前的灰色图像:
处理后的灰色图像:
我很困惑,因为在我看到的例子中,卷积图像是黑白的。在这里,我的卷积需要归一化,而且,它不是纯黑色和白色。
答案 0 :(得分:6)
您的可视化非常正常。发生的事情是您正在重新映射像素值,以便将最低强度设置为0并将最高强度设置为1.所有其他值将线性重新映射以符合[0,1]
范围。您可能只看到黑色和白色的原因是剪裁。发布这些结果的用户可能截断了动态范围,其中任何小于0的值都设置为0,任何大于1的值(或者您正在查看的数据类型的最大值是)设置为1。
您正在计算边缘检测,其中内核/掩码具有负系数,因此完全有可能在结果中获得负值和正值。通过这种方式重新调整图像,您将看到0的值被映射为灰色(大约0.5左右),因为负的最小强度被拉到0,这自然意味着您的0值被拉达到一些非零数字。同样,那些非常大的值也被标准化为1。
但是,在执行规范化时,标准做法是规范化内核。之所以这样,是因为通过这样做,您可以确保每个像素的输出值永远不会超出数据类型的动态范围。通过规范化内核,您可以确保所有系数在[0,1]
之间加权,并且内核的总和为1.通过这样做,您可以确保不必检查输出并剪切值必要时。这也确保您不需要在每个像素处除以卷积码中的权重之和,因为内核规范化步骤已经处理了规范化。你只需要规范化一次。但是,当你在内核中有负系数时,这是一个棘手的事情。如果存在负系数,则很少进行标准化....至少我在实践中看到的情况。
现在,回到&#34;黑白&#34;东西,如果你使用另一个过滤器...说...一个普通的过滤器,你肯定会得到一个&#34;黑色和白色&#34;图片,因为没有任何值为负的....即使你通过min-max方法将输出规范化为[0,1]
。请记住,这将执行对比度拉伸,如果您的强度集中在[0,1]
范围的一小部分,则输出将拉伸,以使最低强度降至0并且最大强度被映射到1.
我已修改您的代码来执行此操作。请记住,如果没有轴线,我无法找到原始图像,因此我拍摄了快照并将其保存为PNG。因此,我使用png
包而不是jpeg
包:
require(png) # Change
myjpg <- readPNG("mtg.png") # Change
grayImg <- myjpg[,,1]+myjpg[,,2]+myjpg[,,3] # reduce to gray
grayImg <- grayImg/max(grayImg) # normalize
dim(grayImg)
convolve <- function(img, f){
newimg <- img
radius <- as.integer(nrow(f)/2)+1
print(radius)
for(i in c(1:nrow(img))){
for(j in c(1:ncol(img))){
f_sub <- f[c(max(1,radius-i+1):min(nrow(f),nrow(img)-i+radius)),c(max(1,radius-j+1):min(ncol(f),ncol(img)-j+radius))]
img_sub <- img[c(max(1,i-radius+1):min(nrow(img),i+radius-1)),c(max(1,j-radius+1):min(ncol(img),j+radius-1))]
wavg <- sum(as.vector(f_sub)*as.vector(img_sub))# / sum(as.vector(f_sub)) # todo, not sure about this division
newimg[i,j] <- wavg
}
}
return(newimg)
}
#edgeFilter <- matrix(c(-1,-1,-1,-1,8,-1,-1,-1,-1), ncol = 3)
averageFilter <- matrix(c(1,1,1,1,1,1,1,1,1), ncol=3) / 9# Change
#outimg <- convolve(grayImg,edgeFilter) # Change
outimg <- convolve(grayImg,averageFilter)
outimg <- outimg - min(outimg)
outimg <- outimg/max(outimg)
plot(c(0,1),c(0,1),t='n')
rasterImage(outimg, 0,0,1,1)
这是我得到的:
将其与原始图像进行比较:
如果你更仔细地盯着它,你会发现两者之间存在一些模糊。如果你增加平均滤镜尺寸,你会看到更多的模糊...说... 7 x 7:
averageFilter <- matrix(rep(1,49), ncol=7) / 49
这样做,这是我们得到的图像:
正如我们所料......更加模糊。但是,重点在于,当您决定通过min-max方式对图像进行标准化时,数据的动态范围将决定图像的可视化方式。如果存在负值,则期望大约为0的值将被推送到某个非零值...通常为灰色。如果指定具有负系数的内核,则会发生这种情况。如果你有一个具有严格正系数的内核,你就不会看到任何负面的值,并且可视化就像你期望的那样。
答案 1 :(得分:1)
我认为你看到的例子没有对图像进行标准化,因为负值会被剪裁,只能看到正值,并且由于灰度值不按比例缩放,正值显示为最高值。图像,当您正在标准化比例,因此没有剪切和灰度值的钳位发生,所有都取决于可视化。