-
Notifications
You must be signed in to change notification settings - Fork 1.7k
P.250 的图 12.5 和 P.252 代码中的 Sobel 算子和 Prewitt 算子的Gx和Gy矩阵写反了. #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
你好,我明白你的意思,我写的时候也考虑了一些时间要写成什么 样。书里的确有些事情没有交代,我这里再具体说一下。 实际上卷积操作有一个翻转核的操作,我在书里写到过: 这意味着,你看到的卷积核需要翻转一下后再和原图像像素相乘相加。但我的代码实现为了简单和明了并没有进行这一步。 而边缘检测里面的Gx和Gy从直观意义上讲其实是为了分别检测水平方向和垂直方向上的边缘线,也就是说是检测横线和纵线。你所看到的wiki上的Sobel算子之所以是和书里面反的,是因为它的卷积操作是严格按照定义来,即翻转后再权重相加,这样一来,其实和书里面的本质是一样的:书里直接把核翻转过来而在进行“卷积”操作的时候就不会再翻转核了。得到的效果就是,Gx会检测出来水平线: 而Gy会检测出来垂直线: 不知道你是否看明白了。总结来说就是,标准的卷积操作定义是:
书里面由于没有进行第一步操作,所以为了达到和标准卷积操作一样的效果就提前在定义卷积核操作的时候把核翻转了,造成和wiki里面的定义不同,但它们的效果其实是一样的。如果按你说的核来进行同样的计算,那么Gx将会检测的是垂直线,这是不对的。 我的确应该在书里更明确地解释一下。感谢反馈 :) |
谢谢你的详细解释. 不过对于卷积核的翻转, 感觉你的理解有误, 我了解到的卷积核的翻转是沿对角线翻转, 也就是翻转 比如我们以 wiki 中列出的
沿对角线翻转后会变成这样:
相当于在 x 轴向上改变了一下时序. 如果按照你所描述的翻转, 那是 也就是说 wiki 中提到的 所以我有些奇怪为什么你上面的例子中的两张图在用了错误的矩阵后居然能输出正确的结果.... |
你的对角线翻转不对哦,我研一上图像处理课的时候也困惑了很久,不明白为什么要这样多此一举所以印象非常深刻。 这个翻转类似于矩阵转置,横行会变成纵列,纵列会变成横行。你那个不是沿着对角线翻转,而是沿着中心垂直对称轴翻转,正确翻转可参考矩阵转置。 -1 0 1
-2 0 2
-1 0 1 翻转过后是 -1 -2 -1
0 0 0
1 2 1 |
这里不能跟转置矩阵搞混淆, 沿对角线翻转要做两次, 第一次是沿左下角到右上角的对角线, 第二次是沿左上角到右下角的对角线. 具体来说是这样: 原矩阵
先沿左下角到右上角的对角线翻转, 结果为:
再沿左上角到右下角的对角线翻转, 最终结果为:
而且看看在 wiki 中对翻转的描述:
也是把卷积核的行列同时翻转, 我们可以先翻转行:
再翻转列:
最终结果一样. wiki 上贴出的计算示意图也表示是这种翻转: 这里是用矩阵的对应元素相乘再相加, 要跟矩阵相乘区分开. 我写过一个用 着色器代码如下:
|
我明白你的 意思了。我又查了些资料,我的理解的确是有问题的…… Gx并不是检测水平方向的边缘线,而是水平方向上的梯度变化,结果是检测出来的是垂直方向上的边缘线,所以应该是 -1 0 1
-2 0 2
-1 0 1 感谢指正 :) 至于你说计算法线的时候的问题,你是说按书里的做法,xy值就反了是吧。这个问题是另外一个问题了,就是说从高度图生成法线的时候,xy分量分别指的是什么。我也做了实验,靠三种方法生成法线:
float height = tex2D(_MainTex, i.uv);
edgeX = ddy(height);
edgeY = ddx(height);
fixed3 norm = fixed3(edgeX, edgeY, 1.0); 结果证明这三个得到的结果是类似的,也就是说法线输出的x分量对应了y方向的梯度变化,y分量对应了x方向上的梯度变化,是反的。书上的Gx和Gy的确写反了,但算法线的时候应该是刚好对才对。。。 你可以贴上你的灰度图和法线生成工具,我再测一下。 |
是我没说清楚, 我举那个生成法线图的例子是想说明: 如果把 以你上面的三个图来说, 第三张图是错误的, 因为一般 (x,y,z) 对应于法线图的 (r,g,b) , 也就是说 x 对应 红色, y 对应绿色, z 对应蓝色, 所以生成的法线图底色是蓝色, 左右的凹凸是紫色, 上下的凹凸是蓝绿色. 虽然第三张图跟前两张图看起来很类似, 但是在用它做法线贴图(或者叫法线映射)时会产生错误的立体效果. 我使用的原图是这个: 然后用代码提取每个像素的灰度值, 用灰度值来模拟高度值. 图像处理软件用的是 CrazyBump. BTW, 我是看了第四章的电子版后觉得其中对几种空间的变换解释得很清楚才买的书, 主要是想参考学习一下你的各种 |
明白啦!我又试了下,PS里之所以是那样是因为xy取反了,Invert回来就一样了。 嗯呢,的确是我的问题,感谢!!! 总结一下,Gx和Gy分别是检测x方向和y方向的梯度值,所以书里那样写是有错误的。我会更新到勘误列表中。 |
已更新,填补了知识漏洞… 感谢支持呀~ |
感觉经过这么一番交流后我对图像卷积的理解也加深了. :) |
我来补个问题,为什么要用1减去水平方向和竖直方向的梯度绝对值呢? |
没什么特别意义,只是因为混合因子edge在lerp里面的位置:
也就是说,如果是纯边界的地方,edge是0。而梯度可能为负也可能为正,绝对值表示了它跟邻域之间值的差距大小,所以绝对值越大表示差异越大,越是边界,那么1-abs就是我们需要的edge值。 |
所以书里的结果虽然对,但严格来说还要再进行一步kernel翻转? 谢谢! |
@mingingzi 这个就是卷积核的定义问题了,有很多资料可以参考,比如: |
P.250 的图 12.5 和 P.252 代码中的 Sobel 算子和 Prewitt 算子的Gx和Gy矩阵写反了.
Sobel 算子的 Gx 是用来计算 x 轴向(横向)的梯度, Gy 是用来计算 y 轴向(纵向)的梯度, 因此, Gx 是用像素点右侧相邻位置(右上,右中,右下)的像素点的亮度值(或高度值/灰度值), 分别乘以权重 1,2,1 后求和, 减去像素点左侧相邻位置(左上,左中,左下)的对应数值, 所以, Gx 矩阵应该是:
Gy 类似, 应为:
因为你的示例代码最终使用的是
1 - abs(edgeX)- abs(edgeY)
, 所以就算把梯度矩阵写反了也不影响, 如果你单独使用它们就会发现问题了, 比如用它们来生成法线贴图.wiki上相关的条目:
Sobel算子
Prewitt算子
The text was updated successfully, but these errors were encountered: