C6678多核DSP开发——imglib应用之边缘检测
前言:应用dspmcsdk工具下的image processing例程实现了图像边缘检测,之前是拿来用的,为了后续工作只好对该例程进行了分析和学习,以作为dsp开发和图像处理的入门例程。在网上查阅大量资料后发现dsp图像处理基本上都用到了两个强大的库,一个是imglib,另一个是vlib,image processing例程正是用到了imglib的库函数。
什么是图像边缘检测,顾名思义也就是得到某张图片的边缘。那为什么要检测边缘,有何意义呢?我觉得可以这么理解,边缘,作为图像的重要特征之一,也是最基本的特征,如果检测到了图像边缘,那么下一步进行图像特征识别就变的简单了。
官方解释如下:边缘检测在计算机视觉、图像分析等应用中起着重要的作用,是图像分析与识别的重要环节。这是因为图像的边缘包含了用于识别的有用信息,所以边缘检测是图像分析和模式识别的主要特征提取手段。
如何进行边缘检测。边缘检测的算法很多,但是归根到底都是检测图像的灰度变化,变化最大的地方就是边缘,数学上就是针对图像灰度变化梯度进行求导,求极值最大处也就是边缘处。求导的过程引入了算子。常见的边缘检测算子有很多:一阶::Roberts Cross算子,Prewitt算子,Sobel算子,Kirsch算子,罗盘算子;二阶:Marr-Hildreth算子,Canny算子,Laplacian算子。常用的是一阶Sobel算子和二阶的Canny算子。本例中应用的是Sobel算子。
Soble边缘检测算法比较简单,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,尤其是对效率要求较高,而对细纹理不太关心的时候。
2.imglib库简介
大多边缘检测等图像处理的实现方法都被封装为函数,供使用者直接调用。在开发上位机图像处理软件时有强大的OpenCV提供各种图像处理函数。像matlab这种数据分析软件也封装好了库函数直接调用。当然,在嵌入式领域,人们也不会笨笨的自己去写代码。TI公司在DSP图像处理领域也是引入了两个比较好用的库,一个是imglib,另一个是vlib。在imglib中就有各种各样封装好的图像处理函数:
在上图中我们可以看到,imglib库中包含了以下几部分内容:
1)图像分析处理函数库:
a边界和周界函数,它们通常在结构视觉应用中作为结构算子。
b膨胀腐蚀函数,通常用于提高二进制图像膨胀和二进制图像腐蚀算法效果。膨胀和腐蚀在图像处理操作中具有基础的意义,比如打开和关闭都可以从膨胀和腐蚀中建立起来。这些函数在机器视觉和医学成像方面非常有用。
c 边缘检测函数。
d 直方图函数,用来生成图像的柱状图。图像的直方图是一个图像亮度级的统计。例如,对于一个8位像素亮度级别的灰度图像,直方图将包括对应可能的256个像素亮度的256bins。每一个bin包含图像中像素点的个数,尤其是亮度值。
e 阈值计算函数在图像和视频处理系统中图像阈值操作的不同形式满足不同的图像处理需求。例如,一种阈值可以用于把灰度图像数据转化为二进制图像数据,以用于二进制形态处理。另一个阀值可以用于剪裁图像数据以便得到渴望的范围。在机器视觉应用中,阈值用于简单的分割。
2)图像滤波处理算法函数库
a 颜 {MOD}空间转换函数
b卷积函数
c 相关性分析函数,函数实现对像素区域高度优化相关性处理。
d 误差扩散函数,二进制值输出误差扩散技术广泛用在印花行业中。最广泛应用的误差扩散算法是Floyd-Steinberg算法。
e 中值滤波函数,用于使成像中的脉冲噪音产生的影响降到最低。该处理方法可以保护脉冲影响十分严重的局部区域,在安全/保卫、机器视觉和视频压缩系统中得到广泛的应用。
f 像素扩展函数,比如把8位像素点扩展到16位。
3)图像压缩/解压缩函数库
标准图像压缩/解压缩算法程序,如JPEG、MPEG Video和H.26x等算法。
a 前向和反转离散余弦变换(DCT)函数:IMG_fdct_8x8和IMG_idct_8x8。在大多数标准压缩算法中都使用离散余弦变换函数,如JPEG编码/解码、MPEG视频编码/解码和H.26X编码/解码。这些标准压缩算法使用目的是不相同的,比如:JPEG算法主要使用在打印、图像处理和安全系统中等;MPEG视频标准主要在数字电视(DTV)、DVD播放器、机顶盒(Set-Top boxes)、便携视频设备、视频光盘和多媒体应用系统中使用;H.26X标准在视频电话和某些流媒体应用中使用。
b 高性能运动估计函数:利用这些函数可以提高运动图像识别算法性能,在MPEG视频编码和H.26X编码中广泛使用运动图像识别算法。在便携视频系统、流媒体系统和视频电话采用这些视频编码。在视频编码系统中,运动图像识别算法是得到最大计算加强优化。采用TI提供的函数可以使系统中算法性能得到显著改善。
c MPEG-2可变长度解码函数:提供了一个高集成度和高效率解决方案,该方案优化了MPEG-2代码intra和non-intra宏块的可变长度解码、run-length expansion、反转扫描、dequantization、saturation和mismatch控制。任何MPEG-2视频解码系统的性能依赖于每个解码步骤的高效实现。
d 量化函数:量子化是许多图像视频压缩系统中的积分步骤,包括DCT压缩算法基础之上各种变异算法,例如JPEG、MPEG和H.26X等算法。在这样的系统中采用IMG_quantize子程序可以提高量子化步骤的速度和性能。
e 小波处理函数:在JPEG2000和MPEG-4等算法中,小波处理得到的广泛的应用,并将发展成为一种标准,典型应用于提高静止图像压缩的性能方面,而且在许多各种图像压缩系统都是建立在小波处理基础之上。IMG_wave_horz和IMG_wave_vert函数用于计算水平和垂直小波变换。利用该两个函数可以计算图像数据2维小波变换。该子程序在文档约束之内使用非常灵活,可以满足宽范围的特殊小波变换和图像维数。
4.imglib库的sobel边缘检测功能实现
i
mage processing例程实现了读取8bit或者24bitBMP图片进行边缘检测,之后将检测到的边缘以BMP图片的格式输出。其编程数据流和主要用到的函数如下分析:例程源码见
《C6678多核DSP开发—image_processing》中所提到的目录。
1)读取BMP图像数据:读取一个BMP文件,将数据存放于CCD_raw_data中,进入图像处理函数。
FILE * fpr = 0;
raw_image_data_t CCD_raw_data = {0, 0};
fpr=
fopen(image_name,
"rb");
fseek(fpr, 0, SEEK_END);
CCD_raw_data.
length =
ftell(fpr);
fseek(fpr, 0, SEEK_SET);
CCD_raw_data.
data =
malloc(CCD_raw_data.
length);
do {
ret_val =
fread(CCD_raw_data.
data + read_length, 1, CCD_raw_data.
length - read_length, fpr);
read_length += ret_val;
}
while (read_length < CCD_raw_data.
length);
mc_process_bmp(
edge_detection, &CCD_raw_data,&out_raw_image, 8, &processing_time);
2)读取BMP图像文件头信息:该函数在mcip_bmp_utils文件中
bmp_read_header(p_input_image,&bmp_header)
3)读取图像RGB {MOD}彩数据
bmp_read_colormap(p_input_image,&bmp_header, p_color_table)
3)以像素为单位读取图像:RGB是24bit 分3个字节为一个像素点。
bmp_read_image (p_input_image,&bmp_header, pixel_array_rgb)
4)将整个图像切割为8个slices分别处理
mc_fill_slice_info(&bmp_header, pixel_array_rgb,number_of_slices, p_slice, p_color_table)
5)针对每片图像将RGB转化为8bit灰度图,公式为:Y = 0.299R + 0.587G + 0.114B
convert_rgb_to_y (p_info->
bitspp, p_info->
p_color_table,
p_info->
rgb_in, y,
p_info->
width, p_info->
height)
6)调用imglib库函数进行sobel滤波
IMG_sobel_3x3_8(y, sobel, p_info->
width, p_info->
height);
7)调用imglib库阈值函数,进行图像二值化
IMG_thr_le2min_8(sobel, p_info->
out,
p_info->
width, p_info->
height, IMAGE_THRESHOLD_VALUE);
8)将每片处理完的图像整合在一起
memcpy(&(pixel_array_edge[0]), p_slice[0].
out, slice_height * bmp_header.
dib.
image_width);
if (number_of_slices > 1)
{
for (
i = 1;
i < number_of_slices;
i++)
{
memcpy(pixel_array_edge + (
i * slice_height * bmp_header.
dib.
image_width),
p_slice[
i].
out + (bmp_header.
dib.
image_width * guard_height), slice_height * bmp_header.
dib.
image_width);
}
}
9)将检测到的边缘图像数据灰度化,添加BMP信息头,作为BMP文件信息准备输出
bmp_write_gray_bmpfile (p_output_image, pixel_array_edge,
bmp_header.
dib.
image_width, bmp_header.
dib.
image_height)
10)最终将BMP数据文件输出,写入文件
fpro =
fopen(out_image_name,
"wb");
do {
ret_val =
fwrite(out_raw_image.
data + write_length, 1, out_raw_image.
length - write_length, fpro);
write_length += ret_val;
}
while (write_length < out_raw_image.
length);