图像特征提取示例
图像变换示例执行脚本位于 ucp_tutorial/vp/vp_samples/script/03_feature_extraction 目录下,
图片特征提取通常分为点特征和边缘特征,该示例主要展示了不同的边缘特征提取方法,包括形态学处理获取边缘、组合XY方向梯度获取边缘和canny算法,详细的实现方法请结合示例源码对比实践。
此示例中,直接执行示例脚本会默认通过canny算法计算图片边缘,若希望更改检测图片边缘的方法,则可以通过在执行示例脚本时追加参数来控制执行的流程,参数的追加规则如下:
sh run_feature_extraction.sh [edge operate]
其中,edge operate为可选参数,边缘检测算法。
此外还可以通过追加 -help 命令获取所有可用的追加参数列表。
算子执行后会在 vp_samples/script/03_feature_extraction 目录下保存图片处理结果,本示例的生成物内容如下:
vp_samples
└── script // 图片数据目录
└── 03_feature_extraction
└── feature_edge_image.jpg // 边缘输出图片
在示例实现过程中,为了建立字符串与边缘检测函数之间的联系,参数 edge_op 定义如下:
typedef int32_t (*example_fn)(hbVPImage &src, hbVPImage &dst);
static std::map<std::string, example_fn> edge_op = {
{"morphology_edge", morphology_edge},
{"canny_edge", canny_edge},
{"sobel_edge", sobel_edge},
{"default", canny_edge}};
追加参数的适配方法与其他示例一致,代码如下:
/**===============================================================
* process image with feature edge operate
* ===============================================================*/
if (argc > 0) {
ret = edge_op[argv[0]](src, dst);
LOGE_AND_RETURN_IF(0 != ret, HB_UCP_INVALID_ARGUMENT,
"feature edge operate failed");
} else {
ret = edge_op["default"](src, dst);
LOGE_AND_RETURN_IF(0 != ret, HB_UCP_INVALID_ARGUMENT,
"feature edge operate failed");
}
morphology_edge
使用形态学方法提取图片的边缘特征,主要使用了 hbVPDilate 和 hbVPErode 算子,处理步骤如下:
- 对原图使用dilate算子处理,获取膨胀后的图像,膨胀操作会让原图中的浅色区域更为凸出。
- 对原图使用erode算子处理,获取腐蚀后的图像,腐蚀操作会让原图中的深色区域更为凸出。
- 将膨胀后的图像减去腐蚀后的图像就可以得到深色与浅色区域间的分界线,即图像的边缘。
核心源码如下:
/**===============================================================
* process gradient operate, dilate - erode
* ===============================================================*/
ret = dilate(src, dilate_img);
LOGE_AND_RETURN_IF(0 != ret, HB_UCP_INVALID_ARGUMENT, "dilate failed");
hbSysFlushMem(&dilate_mem, HB_SYS_MEM_CACHE_INVALIDATE);
cv::Mat dst_mat_dilate(img_height, img_width, CV_8U, dilate_img.dataVirAddr);
ret = erode(src, erode_img);
LOGE_AND_RETURN_IF(0 != ret, HB_UCP_INVALID_ARGUMENT, "erode failed");
hbSysFlushMem(&erode_mem, HB_SYS_MEM_CACHE_INVALIDATE);
cv::Mat dst_mat_erode(img_height, img_width, CV_8U, erode_img.dataVirAddr);
cv::Mat dst_mat(img_height, img_width, CV_8U, dst.dataVirAddr);
dst_mat = dst_mat_dilate - dst_mat_erode;
边缘提取效果如下图:

sobel_edge
使用 hbVPSobel 算子提取图片的边缘特征,处理步骤如下:
- 对原图使用
hbVPSobel 算子获取X方向梯度图像。
- 对原图使用
hbVPSobel 算子获取Y方向梯度图像。
- 将XY方向上的梯度图像组合起来,即可获得XY方向上的边缘特征。
其中XY方向梯度图像组合的核心源码如下:
cv::Mat mat_temp(img_height, img_width, CV_8U, dst.dataVirAddr);
uint8_t *ptr = mat_temp.data;
int16_t *ptr_x = reinterpret_cast<int16_t *>(dst_x_mem.virAddr);
int16_t *ptr_y = reinterpret_cast<int16_t *>(dst_y_mem.virAddr);
for (int j = 0; j < img_height * img_width; ++j) {
int16_t val = ptr_x[j] * 0.5 + ptr_y[j] * 0.5;
val = val < 0 ? 0 : (val > 255 ? 255 : val);
ptr[j] = static_cast<uint8_t>(val);
}
边缘提取效果如下图:

canny_edge
使用 hbVPCanny 算子提取图片的边缘特征,算子原理及接口请参考 hbVPCanny 。