0

我正在尝试为灰度 bmp 图像制作卷积算法。下面的代码来自 Udemy 上的图像处理课程,但是关于使用的变量和公式的解释有点短。问题出在二维离散卷积部分,我无法理解此处实现的公式

struct Mask{
int Rows;
int Cols;
unsigned char *Data;
};

int main()
{
    int imgWidth, imgHeight, imgBitDepth;
    unsigned char imgHeader[BMP_HEADER_SIZE];
    unsigned char imgColorTable[BMP_COLOR_TABLE_SIZE];
    unsigned char imgBuffer[CUSTOM_IMG_SIZE];
    unsigned char imgBuffer2[CUSTOM_IMG_SIZE];

    const char imgName[] = "images/cameraman.bmp";
    const char newImgName[] = "images/cameraman_new.bmp";

    struct Mask lpMask;
    signed char *tmp;
    int i;

    lpMask.Cols = lpMask.Rows = 5;
    lpMask.Data = (unsigned char *)malloc(25);

    /* -1 -1 -1 -1 -1
       -1 -1 -1 -1 -1
       -1 -1 24 -1 -1
       -1 -1 -1 -1 -1
       -1 -1 -1 -1 -1*/

    //set all mask values to -1
    tmp = (signed char *)lpMask.Data;
    for (i = 0; i < 25; ++i)
    {
        *tmp = -1;
        ++tmp;
    }
    //set middle value to 24
    tmp = (signed char *)lpMask.Data + 13;
    *tmp = 24;

    imageReader(imgName, &imgHeight, &imgWidth, &imgBitDepth, imgHeader, imgColorTable, imgBuffer);
    Convolve(imgHeight, imgWidth, &lpMask, imgBuffer, imgBuffer2);
    imageWriter(newImgName, imgHeader, imgColorTable, imgBuffer2, imgBitDepth);

    printf("Success!\n");

    return 0;
}

//2D Discrete Convolution
void Convolve(int imgRows, int imgCols, struct Mask *myMask, unsigned char *input_buf, unsigned char *output_buf)
{
    long i, j, m, n, idx, jdx;
    int ms, im, val;
    unsigned char *tmp;

    //outer summation loop - image
    for (i = 0; i < imgRows; ++i)
        //inner summation loop - image
        for (j = 0; j < imgCols; ++j)
        {
            val = 0;

            //outer summation loop - mask
            for (m = 0; m < myMask->Rows; ++m)
                //inner summation loop - mask
                for (n = 0; n < myMask->Cols; ++n)
                {
                    


                    //Issue in understanding below part
                    ms = (signed char)*(myMask->Data + m * myMask->Rows + n);
                    // index of input img, used for checking boundary
                    idx = i - m;
                    jdx = j - n;
                    if (idx >= 0 && jdx >= 0)  //ignore input samples which are out of bound
                    im = *(input_buf + idx * imgRows + jdx);        
                    val += ms * im;
                }
                //truncate values to remain inside 0to255 range
            if (val > 255) val = 255;
            if (val < 0)   val = 0;
            tmp = output_buf + i * imgRows + j;
            *tmp = (unsigned char)val;
        }
}

在 3 行中,使用的公式相似且最难理解其实现,如果可能,请帮助理解这些代码逻辑或它们到底在做什么:

ms = (signed char)*(myMask->Data + m * myMask->Rows + n);
im = *(input_buf + idx * imgRows + jdx);
tmp = output_buf + i * imgRows + j;

对于使用的公式/伪代码,请查看以下网站上的卷积部分:- https://en.wikipedia.org/wiki/Kernel_(image_processing)

或者

g(x,y) = ∑k= -n2 to n2 ∑j= -m2 to m2 h(j,k) * f(xj, yk) ,其中 m2 = 掩码宽度的一半 & n2 = 掩码高度的一半

或者

Udemy课程中的卷积公式

4

1 回答 1

0

您询问的表达式只是计算在二维(行、列)中索引的特定像素的位置,存储在平面内存缓冲区中。

例如,ms = (signed char)*(myMask->Data + m * myMask->Rows + n);从掩码图像数据缓冲区本身开始myMask->Data,它是一个指针。第一行数据首先显示,然后是第二行。因此,要访问第 m 行第 n 列的像素,您首先必须跳过 m 行数据,即行 * m 的大小。然后你必须跳过行内的 n 个像素。一旦计算出像素的位置,就会使用 * 取消引用它。

我对这个示例代码的唯一抱怨是 name myMask->Rows。在这种情况下,m 表示行索引,为了计算偏移量,它乘以行的大小,行的大小应该是图像中的列数,而不是行数。所以那个参考应该是myMask->Cols.

于 2022-01-05T15:10:31.007 回答