扩张期间不需要的噪声元素
Unwanted Noise element during dilation
我正在对二值米粒图片应用膨胀操作。当使用的结构元素大小为 9x9 时,噪声粒子会变大,这是合乎逻辑的。但是当我使用大小为 15x15 的结构元素时,我会得到与原始噪声粒子相邻的新噪声粒子。这很令人困惑,因为我不知道为什么会这样。结构元素是一个全为 1 的 nxn 矩阵。已附上图片以供参考。
参考图片:
膨胀图像(9x9 SE):
膨胀图像(15x15 SE):
请帮忙!!
代码:
void DilateBinary(Mat Image, Mat& op, double* SE, int m){
op=Image.clone();
double pixelvalue;
int limit=(m-1)/2;
for(int y = limit; y < (Image.rows - limit); y++)
{
for(int x = limit; x < (Image.cols - limit); x++)
{
double max=0.0;
//printf("Input pixel: %u \n",Image.at<unsigned char>(y,x));
for(int j = -limit; j <=limit ; j++)
{
for(int i = -limit; i <=limit ; i++)
{
if(*(SE + (j+1)*m + (i+1) ) > 0)
{
pixelvalue = (*(SE + (j+1)*m + ((2*limit)-(i+1)) )) * (Image.at<unsigned char>(y+j,x+i));
//printf("%f",pixelvalue);
if (pixelvalue>127)
max=255.0;
}
}
}
op.at<uchar>(y,x) = max;
//printf("Output pixel: %u \n",op.at<unsigned char>(y,x));
//printf("Modified pixel= %f %d\n",pixelvalue,cvRound(pixelvalue));
}
}
注意:SE 是指向我正在使用的 mask/SE 的指针。 & m 对于 9x9 SE 为 9,对于 15x15 SE 为 15......
罪魁祸首是你在第二个嵌套 for
循环块中的 if
语句:
for(int j = -limit; j <=limit ; j++) {
for(int i = -limit; i <=limit ; i++) {
if(*(SE + (j+1)*m + (i+1) ) > 0) {
pixelvalue = (*(SE + (j+1)*m + ((2*limit)-(i+1)) )) (Image.at<unsigned char>(y+j,x+i));
if (pixelvalue>127)
max=255.0;
}
}
}
您索引到结构元素的方式假设它是一个 3 x 3 掩码,因为您期望 i
和 j
从 -1
悬停到 1
。 Mark Ransom 的评估是正确的,因为您将拥有负值的指数。尝试设置m = 15
,这是你的问题所在。这意味着 limit = 7
然后从这个循环的开头开始查看您正在访问的行和列,因为您正在尝试访问具有行优先线性索引的掩码。
如果limit = 7
,这意味着在开头,j = -7, i = -7
等等(j+1)*m = (-7+1)*15 = -90
。还有(2*limit) - (i+1) = (2*7) - (-7+1) = 20
。这最终意味着您正在尝试访问 SE - 90 + 20 = SE - 70
的内存位置,因此您实际上是在评估距离结构元素原点 70 个字节(假设 unsigned char
)的内存位置,而不是顶部结构元素的左角...所以你确定你写的代码正确吗?我很惊讶你还没有遇到任何分段错误。您可能幸运地使用 9 x 9
因为行偏移量为负,但列偏移量将为正并且它们的大小可能相等,因此您可能幸运地访问了所有结构元素,但是这对于更大的掩码尺寸肯定不会如此。
为了确保覆盖所有的mask系数,需要将偏移量改为+limit
,而不是+1
。我也不明白 if
语句中的 2*limit
。您可以直接访问 mask 元素。因此,您需要这样做:
for(int j = -limit; j <=limit ; j++) {
for(int i = -limit; i <=limit ; i++) {
if(*(SE + (j+limit)*m + (i+limit) ) > 0) {
pixelvalue = (*(SE + (j+limit)*m + (i+limit) )) * (Image.at<unsigned char>(y+j,x+i));
if (pixelvalue>127)
max=255.0;
}
}
}
但是,如果我能提出一些建议,因为您正在进行形态二元膨胀,您只需检查结构元素中是否有任何像素接触到白色像素。因为这是一个方形结构元素,所以这会更容易。本质上,在 m x m
像素邻域中,如果任何像素不为零,则将输出设置为 255 并跳出循环。对您的代码进行的小优化可能是:
for(int j = -limit; j <=limit ; j++) {
for(int i = -limit; i <=limit ; i++) {
pixelValue = (*(SE + (j+limit)*m + (i+limit) )); // Get structuring element value
pixelValue *= (Image.at<unsigned char>(y+j,x+i)); // Obtain corresponding intensity
if (pixelValue != 0) { // If non-zero, set output to max and break
max = 255.0;
i = limit + 1; j = limit + 1; // break out of loop
}
}
}
当你有完全黑暗的区域时,这显然不会节省任何东西,但当涉及到完全白色的区域时,双重嵌套 for
循环 运行 通过结构元素只会迭代一次。它可能会节省一些时钟周期,但请始终记住,蛮力形态学本身已经具有可怕的计算复杂性。
我正在对二值米粒图片应用膨胀操作。当使用的结构元素大小为 9x9 时,噪声粒子会变大,这是合乎逻辑的。但是当我使用大小为 15x15 的结构元素时,我会得到与原始噪声粒子相邻的新噪声粒子。这很令人困惑,因为我不知道为什么会这样。结构元素是一个全为 1 的 nxn 矩阵。已附上图片以供参考。
参考图片:
膨胀图像(9x9 SE):
膨胀图像(15x15 SE):
代码:
void DilateBinary(Mat Image, Mat& op, double* SE, int m){
op=Image.clone();
double pixelvalue;
int limit=(m-1)/2;
for(int y = limit; y < (Image.rows - limit); y++)
{
for(int x = limit; x < (Image.cols - limit); x++)
{
double max=0.0;
//printf("Input pixel: %u \n",Image.at<unsigned char>(y,x));
for(int j = -limit; j <=limit ; j++)
{
for(int i = -limit; i <=limit ; i++)
{
if(*(SE + (j+1)*m + (i+1) ) > 0)
{
pixelvalue = (*(SE + (j+1)*m + ((2*limit)-(i+1)) )) * (Image.at<unsigned char>(y+j,x+i));
//printf("%f",pixelvalue);
if (pixelvalue>127)
max=255.0;
}
}
}
op.at<uchar>(y,x) = max;
//printf("Output pixel: %u \n",op.at<unsigned char>(y,x));
//printf("Modified pixel= %f %d\n",pixelvalue,cvRound(pixelvalue));
}
}
注意:SE 是指向我正在使用的 mask/SE 的指针。 & m 对于 9x9 SE 为 9,对于 15x15 SE 为 15......
罪魁祸首是你在第二个嵌套 for
循环块中的 if
语句:
for(int j = -limit; j <=limit ; j++) {
for(int i = -limit; i <=limit ; i++) {
if(*(SE + (j+1)*m + (i+1) ) > 0) {
pixelvalue = (*(SE + (j+1)*m + ((2*limit)-(i+1)) )) (Image.at<unsigned char>(y+j,x+i));
if (pixelvalue>127)
max=255.0;
}
}
}
您索引到结构元素的方式假设它是一个 3 x 3 掩码,因为您期望 i
和 j
从 -1
悬停到 1
。 Mark Ransom 的评估是正确的,因为您将拥有负值的指数。尝试设置m = 15
,这是你的问题所在。这意味着 limit = 7
然后从这个循环的开头开始查看您正在访问的行和列,因为您正在尝试访问具有行优先线性索引的掩码。
如果limit = 7
,这意味着在开头,j = -7, i = -7
等等(j+1)*m = (-7+1)*15 = -90
。还有(2*limit) - (i+1) = (2*7) - (-7+1) = 20
。这最终意味着您正在尝试访问 SE - 90 + 20 = SE - 70
的内存位置,因此您实际上是在评估距离结构元素原点 70 个字节(假设 unsigned char
)的内存位置,而不是顶部结构元素的左角...所以你确定你写的代码正确吗?我很惊讶你还没有遇到任何分段错误。您可能幸运地使用 9 x 9
因为行偏移量为负,但列偏移量将为正并且它们的大小可能相等,因此您可能幸运地访问了所有结构元素,但是这对于更大的掩码尺寸肯定不会如此。
为了确保覆盖所有的mask系数,需要将偏移量改为+limit
,而不是+1
。我也不明白 if
语句中的 2*limit
。您可以直接访问 mask 元素。因此,您需要这样做:
for(int j = -limit; j <=limit ; j++) {
for(int i = -limit; i <=limit ; i++) {
if(*(SE + (j+limit)*m + (i+limit) ) > 0) {
pixelvalue = (*(SE + (j+limit)*m + (i+limit) )) * (Image.at<unsigned char>(y+j,x+i));
if (pixelvalue>127)
max=255.0;
}
}
}
但是,如果我能提出一些建议,因为您正在进行形态二元膨胀,您只需检查结构元素中是否有任何像素接触到白色像素。因为这是一个方形结构元素,所以这会更容易。本质上,在 m x m
像素邻域中,如果任何像素不为零,则将输出设置为 255 并跳出循环。对您的代码进行的小优化可能是:
for(int j = -limit; j <=limit ; j++) {
for(int i = -limit; i <=limit ; i++) {
pixelValue = (*(SE + (j+limit)*m + (i+limit) )); // Get structuring element value
pixelValue *= (Image.at<unsigned char>(y+j,x+i)); // Obtain corresponding intensity
if (pixelValue != 0) { // If non-zero, set output to max and break
max = 255.0;
i = limit + 1; j = limit + 1; // break out of loop
}
}
}
当你有完全黑暗的区域时,这显然不会节省任何东西,但当涉及到完全白色的区域时,双重嵌套 for
循环 运行 通过结构元素只会迭代一次。它可能会节省一些时钟周期,但请始终记住,蛮力形态学本身已经具有可怕的计算复杂性。