【问题标题】:2D Discrete Convolution of Image and Mask using C使用 C 的图像和掩码的 2D 离散卷积
【发布时间】:2022-01-04 14:38:04
【问题描述】:

我正在尝试为灰度 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 到 n2 ∑j= -m2 到 m2 h(j,k) * f(x-j, y-k) , 其中 m2 = 掩码宽度的一半 & n2 = 掩码高度的一半

或

【问题讨论】:

    标签: c image-processing convolution discrete


    【解决方案1】:

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

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

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

    【讨论】:

    • 感谢您的回答,现在对计算有了更好的了解。对于myMask-&gt;Rows 部分,它占用了行,因为掩码在 X 和 Y 方向上都翻转了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    • 1970-01-01
    • 2014-05-18
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多