索贝尔算法实现

时间:2016-03-12 23:11:04

标签: c algorithm

我真的很接近实现这个算法,但我的代码存在一些问题。

int Gx[3][3] = {{ -1, 0, 1 },
                { -2, 0, 2 },
                { -1, 0, 1 }};

int Gy[3][3] = {{ -1, -2, -1 },
                {  0,  0,  0 },
                {  1,  2,  1 }};

unsigned int x, y;
long sumX, sumY;
int SUM;

for (x = 0; x < image->w - 1; x++) {
    for (y = 0; y < image->h - 1; y++) {
        sumX = 0;
        sumY = 0;
        if (x == 0 || x == image->w - 1)
            SUM = 0;
        else if (y == 0 || y == image->h - 1)
            SUM = 0;
        else {
            sumX = (Gx[0][0] * image->pixels[(y-1)*image->w+(x-1)]) + (Gx[0][1] * image->pixels[(y-1)*image->w+(x)]) + (Gx[0][2] * image->pixels[(y-1)*image->w+(x+1)]) +
                   (Gx[1][0] * image->pixels[(y)*image->w+(x-1)]) + (Gx[1][1] * image->pixels[(y)*image->w+(x)]) + (Gx[1][2] * image->pixels[(y)*image->w+(x+1)]) +
                   (Gx[2][0] * image->pixels[(y+1)*image->w+(x-1)]) + (Gx[2][1] * image->pixels[(y+1)*image->w+(x)]) + (Gx[2][2] * image->pixels[(y+1)*image->w+(x+1)]);

            sumY = (Gy[0][0] * image->pixels[(y-1)*image->w+(x-1)]) + (Gy[0][1] * image->pixels[(y-1)*image->w+(x)]) + (Gy[0][2] * image->pixels[(y-1)*image->w+(x+1)]) +
                   (Gy[1][0] * image->pixels[(y)*image->w+(x-1)]) + (Gy[1][1] * image->pixels[(y)*image->w+(x)]) + (Gy[1][2] * image->pixels[(y)*image->w+(x+1)]) +
                   (Gy[2][0] * image->pixels[(y+1)*image->w+(x-1)]) + (Gy[2][1] * image->pixels[(y+1)*image->w+(x)]) + (Gy[2][2] * image->pixels[(y+1)*image->w+(x+1)]);
        }


        SUM = sqrtf((sumX^2) + (sumY^2));

        image->pixels[y * image->w + x] = SUM;
    }
}

我使用了用Ruby编写的implementation并将其转换为C.

有一个小故障,输出不应该是黑白的?

我认为我使用的例子的创建者使用了错误的乘法。例如这个(sobel_x[0][0] * img.at(x-1,y-1)),在这里他将sobel数组的索引乘以0,0(-1)与像素0,0相乘,因为x和y位于中心(1,1)像素阵列。相反,他应该使用(sobel_x[0][0] * img.at(x+1,y+1))对吧?

1 个答案:

答案 0 :(得分:0)

在C中,^运算符是按位xor运算符。没有幂运算符,通过将其与自身相乘来执行平方sumXsumX * sumX

此外,你不应该把你的循环从边缘缩短一半,每一行的最后一个像素和最后一行不是用你当前的循环来计算的。

将系数数组GxGy定义为static const将允许编译器将其值保持为常量并优化代码而不从数组中加载这些值,从而删除所有这些乘法。

以下是修改后的版本:

static const int Gx[3][3] = {{ -1, 0, 1 },
                             { -2, 0, 2 },
                             { -1, 0, 1 }};

static const int Gy[3][3] = {{ -1, -2, -1 },
                             {  0,  0,  0 },
                             {  1,  2,  1 }};

unsigned int x, y;
long sumX, sumY;
int SUM;

for (x = 0; x < image->w; x++) {
    for (y = 0; y < image->h; y++) {
        sumX = 0;
        sumY = 0;     
        if (x > 0 && x < image->w - 1 && y > 0 && y < image->h - 1) {
            sumX = (Gx[0][0] * image->pixels[(y - 1) * image->w + (x - 1)]) +
                   (Gx[0][1] * image->pixels[(y - 1) * image->w + (x)]) +
                   (Gx[0][2] * image->pixels[(y - 1) * image->w + (x + 1)]) +
                   (Gx[1][0] * image->pixels[(y) * image->w + (x - 1)]) +
                   (Gx[1][1] * image->pixels[(y) * image->w + (x)]) +
                   (Gx[1][2] * image->pixels[(y) * image->w + (x + 1)]) +
                   (Gx[2][0] * image->pixels[(y + 1) * image->w + (x - 1)]) +
                   (Gx[2][1] * image->pixels[(y + 1) * image->w + (x)]) +
                   (Gx[2][2] * image->pixels[(y + 1) * image->w + (x + 1)]);

            sumY = (Gy[0][0] * image->pixels[(y - 1) * image->w + (x - 1)]) +
                   (Gy[0][1] * image->pixels[(y - 1) * image->w + (x)]) +
                   (Gy[0][2] * image->pixels[(y - 1) * image->w + (x + 1)]) +
                   (Gy[1][0] * image->pixels[(y) * image->w + (x - 1)]) +
                   (Gy[1][1] * image->pixels[(y) * image->w + (x)]) +
                   (Gy[1][2] * image->pixels[(y) * image->w + (x + 1)]) +
                   (Gy[2][0] * image->pixels[(y + 1) * image->w + (x - 1)]) +
                   (Gy[2][1] * image->pixels[(y + 1) * image->w + (x)]) +
                   (Gy[2][2] * image->pixels[(y + 1) * image->w + (x + 1)]);
        }
        SUM = sqrtf(sumX * sumX + sumY * sumY);
        image->pixels[y * image->w + x] = SUM;
    }
}

请注意,使用正确定义的2D数组image->pixels的本地指针可以大大简化代码:

static const int Gx[3][3] = {{ -1, 0, 1 },
                             { -2, 0, 2 },
                             { -1, 0, 1 }};
static const int Gy[3][3] = {{ -1, -2, -1 },
                             {  0,  0,  0 },
                             {  1,  2,  1 }};
unsigned int x, y;
long sumX, sumY;
pixel_type (*pixels)[image->w] = (void*)image->pixels;

for (x = 0; x < image->w; x++) {
    for (y = 0; y < image->h; y++) {
        sumX = sumY = 0;
        if (x > 0 && x < image->w - 1 && y > 0 && y < image->h - 1) {
            sumX = (Gx[0][0] * pixels[y - 1][x - 1]) +
                   (Gx[0][1] * pixels[y - 1][x]) +
                   (Gx[0][2] * pixels[y - 1][x + 1]) +
                   (Gx[1][0] * pixels[y][x - 1]) +
                   (Gx[1][1] * pixels[y][x]) +
                   (Gx[1][2] * pixels[y][x + 1]) +
                   (Gx[2][0] * pixels[y + 1][x - 1]) +
                   (Gx[2][1] * pixels[y + 1][x]) +
                   (Gx[2][2] * pixels[y + 1][x + 1]);

            sumY = (Gy[0][0] * pixels[y - 1][x - 1]) +
                   (Gy[0][1] * pixels[y - 1][x]) +
                   (Gy[0][2] * pixels[y - 1][x + 1]) +
                   (Gy[1][0] * pixels[y][x - 1]) +
                   (Gy[1][1] * pixels[y][x]) +
                   (Gy[1][2] * pixels[y][x + 1]) +
                   (Gy[2][0] * pixels[y + 1][x - 1]) +
                   (Gy[2][1] * pixels[y + 1][x]) +
                   (Gy[2][2] * pixels[y + 1][x + 1]);
        }
        pixels[y][x] = sqrtf(sumX * sumX + sumY * sumY);
    }
}

仍然存在一个主要问题:您无法就地计算此过滤器,因为修改后的像素值将用于下一列和行。您必须使用临时数组来存储结果:

static const int Gx[3][3] = {{ -1, 0, 1 },
                             { -2, 0, 2 },
                             { -1, 0, 1 }};
static const int Gy[3][3] = {{ -1, -2, -1 },
                             {  0,  0,  0 },
                             {  1,  2,  1 }};
unsigned int x, y;
long sumX, sumY;
pixel_type (*pixels)[image->w] = (void*)image->pixels;
pixel_type (*dest)[image->w] = malloc(image->h * sizeof(*dest));

for (x = 0; x < image->w; x++) {
    for (y = 0; y < image->h; y++) {
        sumX = sumY = 0;
        if (x > 0 && x < image->w - 1 && y > 0 && y < image->h - 1) {
            sumX = (Gx[0][0] * pixels[y - 1][x - 1]) +
                   (Gx[0][1] * pixels[y - 1][x]) +
                   (Gx[0][2] * pixels[y - 1][x + 1]) +
                   (Gx[1][0] * pixels[y][x - 1]) +
                   (Gx[1][1] * pixels[y][x]) +
                   (Gx[1][2] * pixels[y][x + 1]) +
                   (Gx[2][0] * pixels[y + 1][x - 1]) +
                   (Gx[2][1] * pixels[y + 1][x]) +
                   (Gx[2][2] * pixels[y + 1][x + 1]);

            sumY = (Gy[0][0] * pixels[y - 1][x - 1]) +
                   (Gy[0][1] * pixels[y - 1][x]) +
                   (Gy[0][2] * pixels[y - 1][x + 1]) +
                   (Gy[1][0] * pixels[y][x - 1]) +
                   (Gy[1][1] * pixels[y][x]) +
                   (Gy[1][2] * pixels[y][x + 1]) +
                   (Gy[2][0] * pixels[y + 1][x - 1]) +
                   (Gy[2][1] * pixels[y + 1][x]) +
                   (Gy[2][2] * pixels[y + 1][x + 1]);
        }
        dest[y][x] = sqrtf(sumX * sumX + sumY * sumY);
    }
}
memcpy(pixels, dest, image->h * sizeof(*pixels));
free(dest);