使用 C 对图像和蒙版进行二维离散卷积
2D Discrete Convolution of Image and Mask using C
我正在尝试为灰度 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;
对于 formula/pseudocode 使用,检查以下网站上的卷积部分:- 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 = 掩码高度的一半
或
您询问的表达式只是计算以二维(行、列)索引的特定像素的位置,存储在平面内存缓冲区中。
例如,ms = (signed char)*(myMask->Data + m * myMask->Rows + n);
从掩码图像数据缓冲区本身开始,myMask->Data
,它是一个指针。第一行数据首先显示,然后是第二行。所以要访问m行n列的像素,首先要跳过m行数据,也就是行*m的大小。然后你必须跳过行内的 n 个像素。一旦像素的位置被计算出来,它就会被取消引用 *.
我对这个示例代码的唯一抱怨是名称 myMask->Rows
。在这种情况下,m 表示行索引,为了计算偏移量,它乘以行的大小,应该 是图像中的列数,而不是列数的行。因此该参考应改为 myMask->Cols
.
我正在尝试为灰度 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;
对于 formula/pseudocode 使用,检查以下网站上的卷积部分:- 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 = 掩码高度的一半
或
您询问的表达式只是计算以二维(行、列)索引的特定像素的位置,存储在平面内存缓冲区中。
例如,ms = (signed char)*(myMask->Data + m * myMask->Rows + n);
从掩码图像数据缓冲区本身开始,myMask->Data
,它是一个指针。第一行数据首先显示,然后是第二行。所以要访问m行n列的像素,首先要跳过m行数据,也就是行*m的大小。然后你必须跳过行内的 n 个像素。一旦像素的位置被计算出来,它就会被取消引用 *.
我对这个示例代码的唯一抱怨是名称 myMask->Rows
。在这种情况下,m 表示行索引,为了计算偏移量,它乘以行的大小,应该 是图像中的列数,而不是列数的行。因此该参考应改为 myMask->Cols
.