本帖最后由 jinyi7016 于 2018-10-17 13:13 编辑
这次我们使用的是VLIB中的函数。 Canny的输入图像是8位的灰度图。 Canny的过程是先将图像进行高斯滤波,计算梯度,疳调整图像有效像素到图片的中央,这一步是与前面讲的sobel算法的边缘检测结果差别的原因了。再经过抑制非极大值与双阈值算法生成最后的边缘化的图像。
由于输出的也是8位的图像,所以最后还要在bmp文件中加入调色板数据。
以上算法都是使用VLIB中的函数:
- VLIB_doublethresholding();
- VLIB_nonMaximumSuppressionCanny();
- VLIB_xyGradientsAndMagnitude();
- VLIB_conv_7x7_i8_c8s();
复制代码
程序中使用的7*7高斯核:
- char gaussian_7x7[49] =
- {
- 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 4, 6, 4, 1, 0,
- 0, 4, 16, 24, 16, 4, 0,
- 0, 6, 24, 36, 24, 6, 0,
- 0, 4, 16, 24, 16, 4, 0,
- 0, 1, 4, 6, 4, 1, 0,
- 0, 0, 0, 0, 0, 0, 0
- };
复制代码
程序中使用了很多存放中间变量的指针,这些指针要提前分配好空间。
- imageData = (unsigned char*) malloc(sizeof(unsigned char)*pixelNums);
- scratchData = (unsigned char*) malloc(sizeof(unsigned char)*pixelNums);
- gradX = (short*) malloc(sizeof(short)*pixelNums);
- gradY = (short*) malloc(sizeof(short)*pixelNums);
- gradM = (short*) malloc(sizeof(short)*pixelNums);
- nonMax = (unsigned char*) malloc(sizeof(unsigned char)*pixelNums);
- numItems = (int*) malloc(sizeof(numItems));
- listptr = (unsigned int*) malloc(sizeof(unsigned int)*pixelNums);
复制代码
完整源码如下:
- Canny(bmp *m, char *mask_ptr)
- {
- int i;
- bmp newm;
- int bmpWidth; // 图像的宽
- int bmpHeight; // 图像的高
- int biBitCount; // 图像类型,每像素位数
- int newBmpWidth; // 新图像的宽
- int newBmpHeight; // 新图像的高
- int newLineByte;
- // 获取图像宽、高、每像素所占位数等信息
- bmpWidth = m->info.biWidth;
- bmpHeight = m->info.biHeight;
- biBitCount = m->info.biBitcount;
- // 新图像的宽高
- newBmpWidth = bmpWidth;
- newBmpHeight = bmpHeight;
- newLineByte = (newBmpWidth * biBitCount / 8 + 3) / 4 * 4;
- // 申请位图数据区
- newBmpBuf = (unsigned char *)malloc(newLineByte * newBmpHeight);
- // 像素数
- int pixelNums;
- // 图像数据区
- unsigned char* imageData;
- // 过程量
- unsigned char* scratchData;
- // x方向梯度
- short* gradX;
- // y方向梯度
- short* gradY;
- // 梯度幅值
- short* gradM;
- // 非极大值处理结果
- unsigned char* nonMax;
- // 新加入的变量
- int* numItems;
- // 边缘保存
- unsigned int* listptr;
- // 高阈值
- unsigned char hi = 20;
- // 低阈值
- unsigned char lo = 2;
- pixelNums = bmpWidth*bmpHeight;
- imageData = (unsigned char*) malloc(sizeof(unsigned char)*pixelNums);
- scratchData = (unsigned char*) malloc(sizeof(unsigned char)*pixelNums);
- gradX = (short*) malloc(sizeof(short)*pixelNums);
- gradY = (short*) malloc(sizeof(short)*pixelNums);
- gradM = (short*) malloc(sizeof(short)*pixelNums);
- nonMax = (unsigned char*) malloc(sizeof(unsigned char)*pixelNums);
- numItems = (int*) malloc(sizeof(numItems));
- listptr = (unsigned int*) malloc(sizeof(unsigned int)*pixelNums);
- imageData = m->imgBuf;
- // 高斯滤波
- pixelNums = (bmpHeight - 6)*bmpWidth - 6;
- VLIB_conv_7x7_i8_c8s( imageData, // 输入图像的指针
- scratchData, // 输出图像的指针
- pixelNums, // 输出图像的总像素数
- bmpWidth, // 输入图像的宽度
- (int8_t*) mask_ptr, // 7x7 高斯核
- 8); // 用户定义 sum 的右移位数
- // 计算梯度,调用此函数计算梯度并会调整图像的有效像素到图片的中央
- pixelNums = (bmpHeight - 8)*bmpWidth;
- VLIB_xyGradientsAndMagnitude(scratchData,
- gradX + bmpWidth*4 + 4, // 输出梯度
- gradY + bmpWidth*4 + 4, // 输出梯度
- gradM + bmpWidth*4 + 4, // 输出梯度
- bmpWidth,
- bmpHeight - 8);
- // 将 nonMax 首末5行置零
- for(i = 0; i < bmpWidth * 5; i++)
- {
- nonMax[i] = 0;
- }
- for(i = 0; i < bmpWidth * 5; i++)
- {
- nonMax[bmpWidth*(bmpHeight - 5) + i] = 0;
- }
- pixelNums = bmpWidth*(bmpHeight - 10);
- // 抑制非极大值,此函数使用3x3的核,操作的单位是行而不是像素
- VLIB_nonMaximumSuppressionCanny(gradM + bmpWidth*4 + 4,
- gradX + bmpWidth*5 + 5,
- gradY + bmpWidth*5 + 5,
- nonMax + bmpWidth*5 + 5,
- bmpWidth-10, // 每行输出像素
- bmpWidth, // 列数
- bmpHeight-8); // 行数
- // 双阈值算法
- VLIB_doublethresholding(gradM + bmpWidth*5 + 5,
- nonMax + bmpWidth*5 + 5,
- listptr,
- numItems,
- bmpWidth - 10,
- bmpWidth,
- bmpHeight - 10,
- lo,
- hi,
- 0);
- for(i = 0; i < bmpWidth * bmpHeight; i++)
- {
- *(newBmpBuf + i) = (*(nonMax + i) >> 7) * 255;
- }
- newm.file.bfType = 0x4d42; // 类型
- newm.file.bfSize = 54 + 246 *4 +
- newLineByte * newBmpHeight; // 文件长度
- newm.file.bfReserverd1 = 0; // 保留字 1
- newm.file.bfReserverd2 = 0; // 保留字 2
- newm.file.bfbfOffBits = 54 + 256 * 4; // 偏移量
- newm.info.biSize = 40; // 此结构大小
- newm.info.biWidth = newBmpWidth; // 位图的宽度
- newm.info.biHeight = newBmpHeight; // 位图的高度
- newm.info.biPlanes = 1; // 目标设备位图数
- newm.info.biBitcount = 8; // 颜色深度
- newm.info.biCompression = 0; // 位图压缩类型
- newm.info.biSizeImage = newLineByte * newBmpHeight; // 位图大小
- newm.info.biXPelsPermeter = 0; // 位图水平分辨率
- newm.info.biYPelsPermeter = 0; // 位图垂直分辨率
- newm.info.biClrUsed = 0; // 位图实际使用颜色数
- newm.info.biClrImportant = 0; // 位图显示中比较重要颜色数
- // 写入调色板
- //memcpy((void *)(newpColorTable), (void *)(m->pColorTable), 256 * 4);
- newm.pColorTable = (RGBQUAD*)newpColorTable;
- // 写入位图数据
- newm.imgBuf = newBmpBuf;
- return newm;
- }
复制代码
以下是边缘检测的结果,看效果好像比imglib的sobel的效果要好啊。 |