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

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。
有一个小故障,输出不应该是黑白的吗?
我认为我使用的例子的创建者使用了错误的乘法例如this(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))对吧?

最佳答案

在c中,^运算符是按位异或运算符。没有幂运算符,通过将其与自身相乘来执行平方运算。
此外,不应将循环停止在距边一小段的位置,每行上的最后一个像素和最后一行不使用当前循环计算。
将系数数组sumXsumX * sumX定义为Gx将允许编译器假定它们的值为常量并优化代码,而无需从数组中加载这些值,从而消除所有这些乘法。
以下是修改版本:

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数组的本地指针可以大大简化代码:
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);

08-18 10:11