OPEN-EC快速食用指南(四)简单使用类似OpenCV的API实现黑色物体检测
本实验就以检测黑色圆珠笔为例,将检测到的结果通过串口2发送出来。

大致思路
- 把摄像头获取的图像转化成灰度。
- 灰度通过设定阈值二值化得到单色图像。
- 对单色图像腐蚀膨胀去除噪声。
- 在单色图像中寻找连通域。
- 找出最大的连通域。
- 把最终的结果在彩色原图中框出来。
- 通过串口2发送检测结果的坐标。
代码
setup
void setup() {
app_camera_main();
app_led_init();
app_led_set(0);
uart2_init(115200);
Lcd_Init();
Lcd_Clear(WHITE);
}
初始化摄像头、LCD、串口2
下面是loop
图像读取以及转灰度
Image img=image_read_from_camera();
Image gray=image_rgb565_to_gray(img);
二值化
Image bin=image_binary(gray,100,0);
//阈值设置为100,最后的0表示不反色,即灰度值大于阈值的是255,小于的是0
先看一下二值化的结果
display_show_img(bin);
调调阈值,找出最合适的阈值。
最后记得释放内存:
image_free(img);
image_free(gray);
image_free(bin);
二值化的结果:(阈值为90)

还是存在一些噪声。
腐蚀膨胀去噪声
Image erode_res=image_erode(bin,3);
Image dilate_res=image_dilate(erode_res,3);
然后显示去噪声之后的结果:
display_show_img(dilate_res);
//要把之前显示二值化图像的那行注释掉
结果:

找连通域
接下来只需要找连通域就可以了。
//先建一个数组用于存放矩形
Rect rects[100];
int rect_num=image_find_contours(dilate_res,rects);
//返回值是连通域个数,连通域的最小外接矩形存放在传进去的地址中。
画框显示
为了去除稍微大一点的噪声,选取了面积最大的连通域作为最终结果。
if(rect_num>0){
int max_sqr=rects[0].w*rects[0].h;
int max_index=0;
for(int i=1;i<rect_num;i++){
if(rects[i].w*rects[i].h > max_sqr){
max_sqr=rects[i].w*rects[i].h;
max_index=i;
}
}
image_draw_rect(img,rects[max_index].x,rects[max_index].y,rects[max_index].w,rects[max_index].h,COLOR16(255,0,0));
}
最终的结果:

显示中心坐标
矩形框的几何中心作为他的坐标,
计算方式是(x+w/2,y+h/2)
char s[30];
sprintf(s,"(%3d,%3d)",rects[max_index].x+rects[max_index].w/2,rects[max_index].y+rects[max_index].h/2);
display_show_string_bottom(s,0,COLOR16(0,0,255));
显示结果:

中心坐标通过串口2发送
同样现在setup初始化串口二,详情见上一篇。
得到中心坐标之后,因为图片尺寸是160x120,宽高都在一个字节(255)以内,所以套上一个帧头,直接把两个字节(x和y)发出去。帧头用0x55 0x56
例如,上述得到的坐标是91,88,那么发送的数据是
十进制:[85,86,91,88]
十六进制:[0x55,0x56,0x5b,0x58]
char send_data[4]={0x55,0x56,rects[max_index].x+rects[max_index].w/2,rects[max_index].y+rects[max_index].h/2};
uart_write_bytes(UART_NUM_2, send_data, 4);
串口2连上电脑,打开串口调试助手,记得选中16进制接收,然后把宽度拉的小一点,一行四个字节,就看的清发过来的数据了。下面是结果:

完整的代码
#include "esp_camera.h"
#include "app_led.h"
#include "app_camera.h"
#include "display.h"
#include "app_uart.h"
#include "image.h"
void setup() {
app_camera_main();
app_led_init();
app_led_set(0);
uart2_init(115200);
Lcd_Init();
Lcd_Clear(WHITE);
}
void loop() {
Image img=image_read_from_camera();
Image gray=image_rgb565_to_gray(img);
Image bin=image_binary(gray,90,0);
Image erode_res=image_erode(bin,3);
Image dilate_res=image_dilate(erode_res,3);
Rect rects[100];
int rect_num=image_find_contours(dilate_res,rects);
if(rect_num>0){
int max_sqr=rects[0].w*rects[0].h;
int max_index=0;
for(int i=1;i<rect_num;i++){
if(rects[i].w*rects[i].h > max_sqr){
max_sqr=rects[i].w*rects[i].h;
max_index=i;
}
}
image_draw_rect(img,rects[max_index].x,rects[max_index].y,rects[max_index].w,rects[max_index].h,COLOR16(255,0,0));
char s[30];
sprintf(s,"(%3d,%3d)",rects[max_index].x+rects[max_index].w/2,rects[max_index].y+rects[max_index].h/2);
display_show_string_bottom(s,0,COLOR16(0,0,255));
char send_data[4]={0x55,0x56,rects[max_index].x+rects[max_index].w/2,rects[max_index].y+rects[max_index].h/2};
uart_write_bytes(UART_NUM_2, send_data, 4);
}
display_show_img(img);
image_free(img);
image_free(gray);
image_free(bin);
image_free(erode_res);
image_free(dilate_res);
app_led_toggle();
}

浙公网安备 33010602011771号