c - 边界图像分割

标签 c image

我正在尝试创建一个代码来找到另一个图像中的边界,如下图所示。

图片

    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 
   ------------------------------------------------
 0: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 
 1: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 
 2: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 
 3: .  .  .  .  x  .  .  .  .  .  .  .  .  .  .  . 
 4: .  .  .  x  .  x  .  .  .  .  x  .  .  .  .  . 
 5: .  .  x  x  .  .  .  .  .  x  x  x  .  .  .  . 
 6: .  .  .  x  x  x  x  x  .  x  x  x  x  .  .  . 
 7: .  .  .  x  x  x  x  x  .  x  x  x  x  .  .  . 
 8: .  .  .  .  .  x  x  x  x  x  x  x  x  .  .  . 
 9: .  .  .  .  .  x  x  x  x  x  x  x  x  .  .  . 
10: .  .  .  .  .  x  x  x  .  x  x  x  .  .  .  . 
11: .  .  .  .  x  .  x  x  x  x  x  .  .  .  .  . 
12: .  .  .  x  .  .  .  .  x  x  .  .  .  .  .  . 
13: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 
14: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 
15: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 

我必须标记作为此图像边界的每个 x。 我正在尝试基于邻居来做到这一点,但我不知道我应该采取什么样的逻辑。 欢迎任何帮助。谢谢。

最佳答案

首先,您需要编写一个处理图像的函数。据推测,图像由二维字符数组表示,因此该函数将需要遍历该数组。第二个函数可用于确定图像的每个 'x' 是否在边缘上。结果可以存储在输出数组中。

现在,要编写可能称为 is_edge() 的第二个函数,您需要确定 'x' 位于边缘上意味着什么的图像。如果前景像素与背景像素相邻('.'),则第一次尝试可能会在图像边缘有一个前景像素。这听起来不错,但生成的图像可能有点“沉重”:

Image edges (is_edge1):
    0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 
   -------------------------------------------------
 0: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 1: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 2: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 3: .  .  .  .  x  .  .  .  .  .  .  .  .  .  .  .  
 4: .  .  .  x  .  x  .  .  .  .  x  .  .  .  .  .  
 5: .  .  x  x  .  .  .  .  .  x  x  x  .  .  .  .  
 6: .  .  .  x  x  x  x  x  .  x  .  x  x  .  .  .  
 7: .  .  .  x  x  x  .  x  .  x  .  .  x  .  .  .  
 8: .  .  .  .  .  x  .  x  x  x  .  .  x  .  .  .  
 9: .  .  .  .  .  x  .  x  x  x  .  x  x  .  .  .  
10: .  .  .  .  .  x  x  x  .  x  x  x  .  .  .  .  
11: .  .  .  .  x  .  x  x  x  x  x  .  .  .  .  .  
12: .  .  .  x  .  .  .  .  x  x  .  .  .  .  .  .  
13: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
14: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
15: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  

这里有一些像素,例如 [5][10],可能已被删除。如果这看起来不太正确,那么您可以重新考虑 is_edge() 函数。相反,如果前景像素与不在其角之一的背景像素相邻,则前景像素位于边缘上怎么办?这应该删除刚刚看到的类型的额外像素:

Image edges (is_edge2):
    0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 
   -------------------------------------------------
 0: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 1: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 2: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 3: .  .  .  .  x  .  .  .  .  .  .  .  .  .  .  .  
 4: .  .  .  x  .  x  .  .  .  .  x  .  .  .  .  .  
 5: .  .  x  x  .  .  .  .  .  x  .  x  .  .  .  .  
 6: .  .  .  x  x  x  x  x  .  x  .  .  x  .  .  .  
 7: .  .  .  x  x  .  .  x  .  x  .  .  x  .  .  .  
 8: .  .  .  .  .  x  .  .  x  .  .  .  x  .  .  .  
 9: .  .  .  .  .  x  .  .  x  .  .  .  x  .  .  .  
10: .  .  .  .  .  x  .  x  .  x  .  x  .  .  .  .  
11: .  .  .  .  x  .  x  x  x  .  x  .  .  .  .  .  
12: .  .  .  x  .  .  .  .  x  x  .  .  .  .  .  .  
13: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
14: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
15: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  

此方法在某些方面似乎更好,但它似乎也删除了太多 内部像素。请注意,[11][9] 处的像素现在已被移除;从原始图像来看,这似乎不应该被删除。一种修改是,如果前景像素与不在其角之一处的背景像素相邻,或者如果它与相对对角处的两个背景像素相邻,则前景像素在边缘上。这将保留“桥接”像素,例如 [11][9] 中的像素:

Image edges (is_edge3):
    0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 
   -------------------------------------------------
 0: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 1: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 2: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
 3: .  .  .  .  x  .  .  .  .  .  .  .  .  .  .  .  
 4: .  .  .  x  .  x  .  .  .  .  x  .  .  .  .  .  
 5: .  .  x  x  .  .  .  .  .  x  .  x  .  .  .  .  
 6: .  .  .  x  x  x  x  x  .  x  .  .  x  .  .  .  
 7: .  .  .  x  x  .  .  x  .  x  .  .  x  .  .  .  
 8: .  .  .  .  .  x  .  .  x  .  .  .  x  .  .  .  
 9: .  .  .  .  .  x  .  .  x  .  .  .  x  .  .  .  
10: .  .  .  .  .  x  .  x  .  x  .  x  .  .  .  .  
11: .  .  .  .  x  .  x  x  x  x  x  .  .  .  .  .  
12: .  .  .  x  .  .  .  .  x  x  .  .  .  .  .  .  
13: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
14: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  
15: .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  

这可能是上述替代方案中最好的。但是考虑这个测试用例:

.  .  .  .  .
.  .  x  .  .
.  x  x  x  .
.  .  x  .  .
.  .  .  .  .

在上面建议的三种方法中,只有第二种会从图像中心移除 x。也许一种方法在某些情况下效果更好,而另一种方法在其他情况下效果更好。或者可能需要更好的方法。

这是用于生成上述输出的完整程序。 find_edges() 函数以函数指针作为参数,因此可以轻松实现、尝试和比较不同的 is_edge() 函数。我相信您可以找到改进此代码的方法。

#include <stdio.h>

#define IMAGE_SZ  16

void show_image(char img[][IMAGE_SZ], size_t img_sz);
void find_edges(char in[][IMAGE_SZ],
                char out[][IMAGE_SZ],
                size_t img_sz,
                int (*is_edge)(size_t, size_t, char [][IMAGE_SZ], size_t));
int is_edge1(size_t y, size_t x, char in[][IMAGE_SZ], size_t img_sz);
int is_edge2(size_t y, size_t x, char in[][IMAGE_SZ], size_t img_sz);
int is_edge3(size_t y, size_t x, char in[][IMAGE_SZ], size_t img_sz);

int main(void)
{
    char image_in[IMAGE_SZ][IMAGE_SZ] = { "................",
                                          "................",
                                          "................",
                                          "....x...........",
                                          "...x.x....x.....",
                                          "..xx.....xxx....",
                                          "...xxxxx.xxxx...",
                                          "...xxxxx.xxxx...",
                                          ".....xxxxxxxx...",
                                          ".....xxxxxxxx...",
                                          ".....xxx.xxx....",
                                          "....x.xxxxx.....",
                                          "...x....xx......",
                                          "................",
                                          "................",
                                          "................" };

    char edge_out[IMAGE_SZ][IMAGE_SZ];

    puts("Input image:");
    show_image(image_in, IMAGE_SZ);

    puts("Image edges (is_edge1):");
    find_edges(image_in, edge_out, IMAGE_SZ, is_edge1);
    show_image(edge_out, IMAGE_SZ);

    puts("Image edges (is_edge2):");
    find_edges(image_in, edge_out, IMAGE_SZ, is_edge2);
    show_image(edge_out, IMAGE_SZ);

    puts("Image edges (is_edge3):");
    find_edges(image_in, edge_out, IMAGE_SZ, is_edge3);
    show_image(edge_out, IMAGE_SZ);

    return 0;
}

void show_image(char img[][IMAGE_SZ], size_t img_sz)
{
    /* print top numbers */
    printf("%4c", ' ');
    for (size_t j = 0; j < img_sz; j++) {
        printf("%-3zu", j);
    }
    putchar('\n');

    /* print dashes */
    printf("%4c", '-');
    for (size_t j = 0; j < img_sz; j++) {
        printf("%3s", "---");
    }
    putchar('\n');

    /* print rows */
    for (size_t i = 0; i < img_sz; i++) {
        printf("%2zu: ", i);
        for (size_t j = 0; j < img_sz; j++) {
            printf("%-3c", img[i][j]);
        }
        putchar('\n');
    }
    putchar('\n');
}

void find_edges(char in[][IMAGE_SZ],
                char out[][IMAGE_SZ],
                size_t img_sz,
                int (*is_edge)(size_t, size_t, char [][IMAGE_SZ], size_t))
{
    for (size_t i = 0; i < img_sz; i++) {
        for (size_t j = 0; j < img_sz; j++) {
            out[i][j] = is_edge(i, j, in, img_sz) ? 'x' : '.';
            }
        }
}

/* A pixel is an edge if it is adjacent to a background pixel */
int is_edge1(size_t y, size_t x, char in[][IMAGE_SZ], size_t img_sz)
{
    int edge_found = 0;
    if (in[y][x] == 'x') {
        size_t y_start = (y == 0 ? 0 : y-1);
        size_t y_stop = (y == (img_sz-1) ? img_sz-1: y+1);
        size_t x_start = (x == 0 ? 0 : x-1);
        size_t x_stop = (x == (img_sz-1) ? img_sz-1 : x+1);


        for (size_t i = y_start; i <= y_stop; i++) {
            for (size_t j = x_start; j <= x_stop; j++) {
                if (in[i][j] == '.') {
                    edge_found = 1;
                    break;
                }
            }
            if (edge_found) {
                break;
            }
        }
    }

    return edge_found;
}

/* a pixel is an edge if it is adjacent to a background pixel that is
 * not a corner pixel
 */
int is_edge2(size_t y, size_t x, char in[][IMAGE_SZ], size_t img_sz)
{
    int edge_found = 0;
    if (in[y][x] == 'x') {
        size_t y_start = (y == 0 ? 0 : y-1);
        size_t y_stop = (y == (img_sz-1) ? img_sz-1: y+1);
        size_t x_start = (x == 0 ? 0 : x-1);
        size_t x_stop = (x == (img_sz-1) ? img_sz-1 : x+1);

        edge_found = (in[y_start][x] == '.' ||
                      in[y][x_start] == '.' ||
                      in[y][x_stop] == '.'  ||
                      in[y_stop][x] == '.');
    }

    return edge_found;
}

/* a pixel is an edge if it is adjacent to a background pixel that is
 * not a corner pixel or if it is adjacent to two opposite diagonal
 * corner pixels.
 */
int is_edge3(size_t y, size_t x, char in[][IMAGE_SZ], size_t img_sz)
{
    int edge_found = 0;
    if (in[y][x] == 'x') {
        size_t y_start = (y == 0 ? 0 : y-1);
        size_t y_stop = (y == (img_sz-1) ? img_sz-1: y+1);
        size_t x_start = (x == 0 ? 0 : x-1);
        size_t x_stop = (x == (img_sz-1) ? img_sz-1 : x+1);

        edge_found = (in[y_start][x] == '.' ||
                      in[y][x_start] == '.' ||
                      in[y][x_stop] == '.'  ||
                      in[y_stop][x] == '.');
        if (edge_found == 0) {
            edge_found = ((in[y_start][x_start] == '.' &&
                           in[y_stop][x_stop] == '.') ||
                          (in[y_start][x_stop] == '.' &&
                           in[y_stop][x_start] == '.'));
        }
    }

    return edge_found;
}

关于c - 边界图像分割,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45222173/

相关文章:

c - 如何生成 _ _ _ 形式的随机数。 _ _ _ _(C语言)

c# - PInvoke 使堆栈不平衡

c - 为 char** 分配内存

c++ - 沿非连续维度对图像进行装箱的最快方法

image - 寻找一种对图像进行按位异或的方法

image - 如何从 Lua 中的 base 64 字符串生成图像文件?

c++ - 哪种音频文件格式最容易操作?

c - 重复的代码,需要缩短

html - 如何在与某些文本相同的行中获取图片(标志)?

python - 翻转图像 Python