STM32+ov7725图像识别(HSL原理)
一、前言
嗯,玩一玩ov7725摄像头,看到个帖子有关于图像识别的,就想玩玩
二、环境
stm32驱动ov7670摄像头识别颜色并追踪_木木so的博客-CSDN博客_stm32f103驱动ov7670摄像头参照这位老哥,这位老哥之上还有鼻祖,嗯
三、正文
在寻常的摄像头刷新图像之后,加上鼻祖的第三方文件库,调用其中的api函数,即可实现腐蚀中心绘制,识别出想要识别的物体中心和方框,嗯,但是物体如果是彩色的,估计就GG了,这个原理就是根据物体的HSL颜色,具体参考链接或者自行百度,HSL比起RGB更容易被机器识别一些。
#include "delay.h"#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "string.h"
#include "ov7670.h"
#include "timer.h"
#include "exti.h"
#include "ColorTracer.h"const u8*LMODE_TBL[5]={"Auto","Sunny","Cloudy","Office","Home"}; //5种光照模式
const u8*EFFECTS_TBL[7]={"Normal","Negative","B&W","Redish","Greenish","Bluish","Antique"}; //7种特效
extern u8 ov_sta; //在exit.c里 面定义
extern u8 ov_frame; //在timer.c里面定义
extern volatile uint8_t Ov7725_Vsync;
//更新LCD显示
u8 R,G,B;
void camera_refresh(void)
{u32 j;u16 color; if(ov_sta)//有帧中断更新?{LCD_Scan_Dir(U2D_L2R); //从上到下,从左到右 if(lcddev.id==0X1963)LCD_Set_Window((lcddev.width-240)/2,(lcddev.height-320)/2,240,320);//将显示区域设置到屏幕中央else if(lcddev.id==0X5510||lcddev.id==0X5310)LCD_Set_Window((lcddev.width-320)/2,(lcddev.height-240)/2,320,240);//将显示区域设置到屏幕中央LCD_WriteRAM_Prepare(); //开始写入GRAM OV7670_RRST=0; //开始复位读指针 OV7670_RCK_L;OV7670_RCK_H;OV7670_RCK_L;OV7670_RRST=1; //复位读指针结束 OV7670_RCK_H;for(j=0;j<76800;j++){OV7670_RCK_L;color=GPIOC->IDR&0XFF; //读数据OV7670_RCK_H; color<<=8; OV7670_RCK_L;color|=GPIOC->IDR&0XFF; //读数据OV7670_RCK_H; LCD->LCD_RAM=color;} ov_sta=0; //清零帧中断标记LCD_Scan_Dir(DFT_SCAN_DIR); //恢复默认扫描方向 }
} u8 i=0; int main(void){ u8 lightmode=0,saturation=2,brightness=2,contrast=2;u8 effect=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级uart_init(921600); //串口初始化为 115200 LCD_Init(); //初始化LCD while(OV7670_Init())//初始化OV7670{LCD_ShowString(30,230,200,16,16,"OV7670 Error!!");delay_ms(200);LCD_Fill(30,230,239,246,WHITE);delay_ms(200);}POINT_COLOR=RED;LCD_ShowString(30,230,200,16,16,"OV7670 Init OK");delay_ms(1500); OV7670_Light_Mode(lightmode);OV7670_Color_Saturation(saturation);OV7670_Brightness(brightness);OV7670_Contrast(contrast);OV7670_Special_Effects(effect); TIM6_Int_Init(10000,7199); //10Khz计数频率,1秒钟中断 EXTI8_Init(); //使能定时器捕获OV7670_Window_Set(12,176,240,320); //设置窗口 OV7670_CS=0; LCD_Clear(BLACK);while(1){ camera_refresh();//更新显示if(Ov7725_Vsync == 2){Ov7725_Vsync = 0;switch(i){case 0:if(Trace(&condition0, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("绿色");}else{i = 1;}break;case 1:if(Trace(&condition1, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("蓝色");}else{i = 2;}break;case 2:if(Trace(&condition2, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("紫色");}else{i = 3;}break;case 3:if(Trace(&condition3, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("黑色");}else{i = 4;}break;case 4:if(Trace(&condition4, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("橙色");}else{i = 5;}break;case 5:if(Trace(&condition5, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("黄色");}else{i = 6;}break;case 6:if(Trace(&condition6, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);printf("棕色");}else{i = 8;}break;
// case 7:
// if(Trace(&condition7, &result))
// {
// LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
// //k = 1;
// }
// else
// {
// i = 8;
// }
// break;case 8:if(Trace(&condition8, &result)){LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);//k = 1;printf("红色");}else{i = 0;}break;}}}
}
#include "ColorTracer.h"
#include "lcd.h"RESULT result;//TARGET_CONDITION condition={50,80,20,250,20,200,40,40,320,240};//识别的是绿色
TARGET_CONDITION condition0={60, //目标最小色度,H_MIN110, //目标最大色度,H_MAX45, //目标最小饱和度,S_MIN110, //目标最大饱和度,S_MAX90, //目标最小亮度,L_MIN210, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
//蓝色
TARGET_CONDITION condition1={110, //目标最小色度,H_MIN150, //目标最大色度,H_MAX50, //目标最小饱和度,S_MIN150, //目标最大饱和度,S_MAX100, //目标最小亮度,L_MIN200, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};//紫色
TARGET_CONDITION condition2={160, //目标最小色度,H_MIN190, //目标最大色度,H_MAX15, //目标最小饱和度,S_MIN100, //目标最大饱和度,S_MAX15, //目标最小亮度,L_MIN190, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
//黑色
TARGET_CONDITION condition3={80, //目标最小色度,H_MIN160, //目标最大色度,H_MAX10, //目标最小饱和度,S_MIN100, //目标最大饱和度,S_MAX10, //目标最小亮度,L_MIN100, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
//橙色
TARGET_CONDITION condition4={1, //目标最小色度,H_MIN40, //目标最大色度,H_MAX50, //目标最小饱和度,S_MIN120, //目标最大饱和度,S_MAX40, //目标最小亮度,L_MIN220, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
//黄色
TARGET_CONDITION condition5={20, //目标最小色度,H_MIN70, //目标最大色度,H_MAX30, //目标最小饱和度,S_MIN200, //目标最大饱和度,S_MAX70, //目标最小亮度,L_MIN240, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};//棕色
TARGET_CONDITION condition6={7, //目标最小色度,H_MIN22, //目标最大色度,H_MAX1, //目标最小饱和度,S_MIN55, //目标最大饱和度,S_MAX1, //目标最小亮度,L_MIN160, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
//灰白
TARGET_CONDITION condition7={60, //目标最小色度,H_MIN170, //目标最大色度,H_MAX0, //目标最小饱和度,S_MIN25, //目标最大饱和度,S_MAX160, //目标最小亮度,L_MIN220, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
//红色
TARGET_CONDITION condition8={200, //目标最小色度,H_MIN240, //目标最大色度,H_MAX5, //目标最小饱和度,S_MIN240, //目标最大饱和度,S_MAX5, //目标最小亮度,L_MIN240, //目标最大亮度,L_MAX40, //目标最小宽度,WIDTH_MIN40, //目标最小高度,HEIGHT_MIN240, //目标最大宽度,WIDTH_MAX320 //目标最大高度,HEIGHT_MAX
};
#define minOf3Values( v1, v2, v3 ) ( (v1<v2) ? ( (v1<v3) ? (v1) : (v3) ) : ( (v2<v3) ? (v2) : (v3) ) )//取rgb中的最小值#define maxOf3Values( v1, v2, v3 ) ( (v1>v2) ? ( (v1>v3) ? (v1) : (v3) ) : ( (v2>v3) ? (v2) : (v3) ) )//取rgb中的最大值typedef struct //RGB
{unsigned char Red; // [0,255]unsigned char Green; // [0,255]unsigned char Blue; // [0,255]
}COLOR_RGB;typedef struct //HLS颜色
{unsigned char Hue; //色度 ,[0,240] unsigned char Lightness; //亮度,[0,240] unsigned char Saturation; //饱和度,[0,240]
}COLOR_HLS;COLOR_HLS h;
typedef struct //搜寻区域
{unsigned int X_Start;unsigned int X_End;unsigned int Y_Start;unsigned int Y_End;
}SEARCH_AREA;/*** @brief 获取 ILI9341 显示器上某一个坐标点的像素数据* @param usX :在特定扫描方向下该点的X坐标* @param usY :在特定扫描方向下该点的Y坐标* @retval 像素数据*/
//uint16_t ILI9341_GetPointPixel( uint16_t usX, uint16_t usY )/*** @brief 读取某一点颜色数据* @param usX :该点的X坐标* @param usY :该点的Y坐标* @param color_rgb :COLOR_RGB结构体,存储颜色数据* @retval 无*/
static void ReadColor( uint16_t usX, uint16_t usY, COLOR_RGB* color_rgb )
{unsigned short rgb;rgb = LCD_ReadPoint( usX, usY ); //获取颜色数据//转换成值域为[0,255]的三原色值color_rgb->Red = (unsigned char)( ( rgb & 0xF800 ) >> 8 );color_rgb->Green = (unsigned char)( ( rgb & 0x07E0 ) >> 3 );color_rgb->Blue = (unsigned char)( ( rgb & 0x001F ) << 3 );//color_rgb->Blue = (unsigned char)( ( rgb & 0x001F ) );
}/*** @brief RGB转HLS* @param color_rgb :COLOR_RGB结构体,存储RGB格式颜色数据* @param color_hls :COLOR_HLS结构体,存储HLS格式颜色数据* @retval 无*/
u8 H,S,L;
static void RGB2HSL( const COLOR_RGB* color_rgb, COLOR_HLS* color_hls )
{int r, g, b;int h, l, s;int max, min, dif;r = color_rgb->Red;g = color_rgb->Green;b = color_rgb->Blue;max = maxOf3Values( r, g, b );min = minOf3Values( r, g, b );dif = max - min;//计算l,亮度l = ( max + min ) * 240 / 255 / 2;//计算h,色度if( max == min )//无定义{s = 0;h = 0;}else{//计算色度if( max == r )//最大值为红色{ if( min == b )//h介于0到40 最小值为蓝色{h = 40 * ( g - b ) / dif;//h = 40 * ( g - n ) / dif;}else if( min == g )//h介于200到240 最小值为绿色{h = 40 * ( g - b ) / dif + 240;}}else if( max == g )//最大值为绿色 40到120{h = 40 * ( b - r ) / dif + 80;}else if( max == b )//最大值为蓝色 120 -200{h = 40 * ( r - g ) / dif + 160;}//计算饱和度if( l == 0 ){s = 0;}else if( l <= 120 ){s = dif * 240 / ( max + min );}else{s = dif * 240 / ( 480 - ( max + min ) );}}
// H = h;
// S = s;
// L = l;color_hls->Hue = h; //色度color_hls->Lightness = l; //亮度color_hls->Saturation = s; //饱和度}/*** @brief 颜色匹配* @param color_hls :COLOR_HLS结构体,存储HLS格式颜色数据* @param condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值* @retval 1:像素点颜色在目标范围内;0:像素点颜色不在目标范围内。*/
static int ColorMatch(const COLOR_HLS* color_hls, const TARGET_CONDITION* condition )
{if(color_hls->Hue > condition->H_MIN &&color_hls->Hue < condition->H_MAX &&color_hls->Lightness > condition->L_MIN &&color_hls->Lightness < condition->L_MAX &&color_hls->Saturation > condition->S_MIN &&color_hls->Saturation < condition->S_MAX){H = color_hls->Hue;S = color_hls->Saturation;L = color_hls->Lightness;return 1;}elsereturn 0;
}/*** @brief 寻找腐蚀中心* @param x :腐蚀中心x坐标* @param y :腐蚀中心y坐标* @param condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值* @param area :SEARCH_AREA结构体,查找腐蚀中心的区域* @retval 1:找到了腐蚀中心,x、y为腐蚀中心的坐标;0:没有找到腐蚀中心。*/
static int SearchCenter(unsigned int* x, unsigned int* y, const TARGET_CONDITION* condition, SEARCH_AREA* area )
{unsigned int i, j, k;unsigned int FailCount=0;unsigned int SpaceX, SpaceY;COLOR_RGB rgb;COLOR_HLS hls;SpaceX = condition->WIDTH_MIN / 3;//最小宽度 40/3SpaceY = condition->HEIGHT_MIN / 3;//最小高度 40/3for(i=area->Y_Start; i<area->Y_End; i+=SpaceY){for(j=area->X_Start; j<area->X_End; j+=SpaceX){FailCount = 0;for(k=0; k<SpaceX+SpaceY; k++){if(k<SpaceX)ReadColor( j+k, i+SpaceY/2, &rgb );elseReadColor( j+SpaceX/2, i+k-SpaceX, &rgb );RGB2HSL( &rgb, &hls );if(!ColorMatch( &hls, condition ))FailCount++;if(FailCount>( (SpaceX+SpaceY) >> ALLOW_FAIL_PER ))break;}if(k == SpaceX+SpaceY){*x = j + SpaceX / 2;*y = i + SpaceY / 2;return 1;}}}return 0;}/*** @brief 从腐蚀中心向外腐蚀,得到新的腐蚀中心* @param oldX :先前的腐蚀中心x坐标* @param oldX :先前的腐蚀中心y坐标* @param condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值* @param result :RESULT结构体,存放检测结果* @retval 1:检测成功;0:检测失败。*/
static int Corrode(unsigned int oldX, unsigned int oldY, const TARGET_CONDITION* condition, RESULT* result )
{unsigned int Xmin, Xmax, Ymin, Ymax;unsigned int i;unsigned int FailCount=0;COLOR_RGB rgb;COLOR_HLS hls;//从中心点查到x最左侧for(i=oldX; i>IMG_X; i--){ReadColor(i, oldY, &rgb);RGB2HSL(&rgb, &hls);if(!ColorMatch(&hls, condition))FailCount++;if(FailCount>(((condition->WIDTH_MIN+condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))break;}Xmin=i;//从中心点查到x最右侧FailCount=0;for(i=oldX; i<IMG_X+IMG_W; i++){ReadColor(i, oldY, &rgb);RGB2HSL(&rgb, &hls);if(!ColorMatch(&hls, condition))FailCount++;if(FailCount>(((condition->WIDTH_MIN+condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))break;}Xmax=i;//y上FailCount=0;for(i=oldY; i>IMG_Y; i--){ReadColor(oldX, i, &rgb);RGB2HSL(&rgb, &hls);if(!ColorMatch(&hls, condition))FailCount++;if(FailCount>(((condition->HEIGHT_MIN+condition->HEIGHT_MAX)>>2)>>ALLOW_FAIL_PER))break;}Ymin=i;//y下FailCount=0;for(i=oldY; i<IMG_Y+IMG_H; i++){ReadColor(oldX, i, &rgb);RGB2HSL(&rgb, &hls);if(!ColorMatch(&hls, condition))FailCount++;if(FailCount>(((condition->HEIGHT_MIN+condition->HEIGHT_MAX)>>2)>>ALLOW_FAIL_PER))break;}Ymax=i;FailCount=0;result->x = (Xmin + Xmax) / 2;result->y = (Ymin + Ymax) / 2;result->w = (Xmax - Xmin);result->h = (Ymax - Ymin);if( (result->w > condition->WIDTH_MIN) && (result->w < condition->WIDTH_MAX) &&(result->h > condition->HEIGHT_MIN) && (result->h < condition->HEIGHT_MAX) )return 1;elsereturn 0;
}int Trace(const TARGET_CONDITION* condition, RESULT* result_final)
{unsigned int i;static unsigned int x0, y0, Flag = 0;static SEARCH_AREA area = {IMG_X, IMG_X+IMG_W, IMG_Y, IMG_Y+IMG_H};//搜索区域RESULT result;
// for(i = 0;i<2;i++)
// {if(Flag == 0){if(SearchCenter(&x0, &y0, condition, &area)){Flag = 1;//break;}else{area.X_Start = IMG_X;area.X_End = IMG_X+IMG_W;area.Y_Start = IMG_Y;area.Y_End = IMG_Y+IMG_H;if(SearchCenter(&x0, &y0, condition, &area)){Flag = 0;return 0;}}}//}result.x = x0;result.y = y0;for(i=0; i<ITERATER_NUM; i++){Corrode(result.x, result.y, condition, &result); //从腐蚀中心向外腐蚀,得到新的腐蚀中心}if( Corrode(result.x, result.y, condition, &result) ){x0 = result.x;y0 = result.y;result_final->x = result.x;result_final->y = result.y;result_final->w = result.w;result_final->h = result.h;Flag = 1;area.X_Start = result.x - ((result.w)>>1);area.X_End = result.x + ((result.w)>>1);area.Y_Start = result.y - ((result.h)>>1);area.Y_End = result.y + ((result.h)>>1);return 1;}else{Flag = 0;return 0;}}//#define min3v(v1, v2, v3) ((v1)>(v2)? ((v2)>(v3)?(v3):(v2)):((v1)>(v3)?(v3):(v1)))
//#define max3v(v1, v2, v3) ((v1)<(v2)? ((v2)<(v3)?(v3):(v2)):((v1)<(v3)?(v3):(v1)))//typedef struct{
// unsigned char red; // [0,255]
// unsigned char green; // [0,255]
// unsigned char blue; // [0,255]
//}COLOR_RGB;//RGB格式颜色//typedef struct{
// unsigned char hue; // [0,240]
// unsigned char saturation; // [0,240]
// unsigned char luminance; // [0,240]
//}COLOR_HSL;//HSL格式颜色//typedef struct{
// unsigned int X_Start;
// unsigned int X_End;
// unsigned int Y_Start;
// unsigned int Y_End;
//}SEARCH_AREA;//区域读取RBG格式颜色,唯一需要移植的函数
//extern unsigned short GUI_ReadBit16Point(unsigned short x,unsigned short y);
//static void ReadColor(unsigned int x,unsigned int y,COLOR_RGB *Rgb)
//{
// unsigned short C16;// C16 = LCD_ReadPoint(x,y);// Rgb->red = (unsigned char)((C16&0xf800)>>8);
// Rgb->green = (unsigned char)((C16&0x07e0)>>3);
// Rgb->blue = (unsigned char)((C16&0x001f)<<3);
//}RGB转HSL
//static void RGBtoHSL(const COLOR_RGB *Rgb, COLOR_HSL *Hsl)
//{
// int h,s,l,maxVal,minVal,difVal;
// int r = Rgb->red;
// int g = Rgb->green;
// int b = Rgb->blue;
//
// maxVal = max3v(r, g, b);
// minVal = min3v(r, g, b);
//
// difVal = maxVal-minVal;
//
// //计算亮度
// l = (maxVal+minVal)*240/255/2;
//
// if(maxVal == minVal)//若r=g=b
// {
// h = 0;
// s = 0;
// }
// else
// {
// //计算色调
// if(maxVal==r)
// {
// if(g>=b)
// h = 40*(g-b)/(difVal);
// else
// h = 40*(g-b)/(difVal) + 240;
// }
// else if(maxVal==g)
// h = 40*(b-r)/(difVal) + 80;
// else if(maxVal==b)
// h = 40*(r-g)/(difVal) + 160;
// //计算饱和度
// if(l == 0)
// s = 0;
// else if(l<=120)
// s = (difVal)*240/(maxVal+minVal);
// else
// s = (difVal)*240/(480 - (maxVal+minVal));
// }
// Hsl->hue = (unsigned char)(((h>240)? 240 : ((h<0)?0:h)));
// Hsl->saturation = (unsigned char)(((s>240)? 240 : ((s<0)?0:s)));
// Hsl->luminance = (unsigned char)(((l>240)? 240 : ((l<0)?0:l)));
//}匹配颜色
//static int ColorMatch(const COLOR_HSL *Hsl,const TARGET_CONDITION *Condition)
//{
// if(
// Hsl->hue > Condition->H_MIN &&
// Hsl->hue < Condition->H_MAX &&
// Hsl->saturation > Condition->S_MIN &&
// Hsl->saturation < Condition->S_MAX &&
// Hsl->luminance > Condition->L_MIN &&
// Hsl->luminance < Condition->L_MAX
// )
// return 1;
// else
// return 0;
//}搜索腐蚀中心
//static int SearchCentre(unsigned int *x,unsigned int *y,const TARGET_CONDITION *Condition,const SEARCH_AREA *Area)
//{
// unsigned int SpaceX,SpaceY,i,j,k,FailCount=0;
// COLOR_RGB Rgb;
// COLOR_HSL Hsl;
//
// SpaceX = Condition->WIDTH_MIN/3;
// SpaceY = Condition->HEIGHT_MIN/3;// for(i=Area->Y_Start;i<Area->Y_End;i+=SpaceY)
// {
// for(j=Area->X_Start;j<Area->X_End;j+=SpaceX)
// {
// FailCount=0;
// for(k=0;k<SpaceX+SpaceY;k++)
// {
// if(k<SpaceX)
// ReadColor(j+k,i+SpaceY/2,&Rgb);
// else
// ReadColor(j+SpaceX/2,i+(k-SpaceX),&Rgb);
// RGBtoHSL(&Rgb,&Hsl);
//
// if(!ColorMatch(&Hsl,Condition))
// FailCount++;
// if(FailCount>((SpaceX+SpaceY)>>ALLOW_FAIL_PER))
// break;
// }
// if(k==SpaceX+SpaceY)
// {
// *x = j+SpaceX/2;
// *y = i+SpaceY/2;
// return 1;
// }
// }
// }
// return 0;
//}从腐蚀中心向外腐蚀,得到新的腐蚀中心
//static int Corrode(unsigned int oldx,unsigned int oldy,const TARGET_CONDITION *Condition,RESULT *Resu)
//{
// unsigned int Xmin,Xmax,Ymin,Ymax,i,FailCount=0;
// COLOR_RGB Rgb;
// COLOR_HSL Hsl;
//
// for(i=oldx;i>IMG_X;i--)
// {
// ReadColor(i,oldy,&Rgb);
// RGBtoHSL(&Rgb,&Hsl);
// if(!ColorMatch(&Hsl,Condition))
// FailCount++;
// if(FailCount>(((Condition->WIDTH_MIN+Condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))
// break;
// }
// Xmin=i;
// FailCount=0;
//
// for(i=oldx;i<IMG_X+IMG_W;i++)
// {
// ReadColor(i,oldy,&Rgb);
// RGBtoHSL(&Rgb,&Hsl);
// if(!ColorMatch(&Hsl,Condition))
// FailCount++;
// if(FailCount>(((Condition->WIDTH_MIN+Condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))
// break;
// }
// Xmax=i;
// FailCount=0;
//
// for(i=oldy;i>IMG_Y;i--)
// {
// ReadColor(oldx,i,&Rgb);
// RGBtoHSL(&Rgb,&Hsl);
// if(!ColorMatch(&Hsl,Condition))
// FailCount++;
// if(FailCount>(((Condition->HEIGHT_MIN+Condition->HEIGHT_MIN)>>2)>>ALLOW_FAIL_PER))
// break;
// }
// Ymin=i;
// FailCount=0;
//
// for(i=oldy;i<IMG_Y+IMG_H;i++)
// {
// ReadColor(oldx,i,&Rgb);
// RGBtoHSL(&Rgb,&Hsl);
// if(!ColorMatch(&Hsl,Condition))
// FailCount++;
// if(FailCount>(((Condition->HEIGHT_MIN+Condition->HEIGHT_MIN)>>2)>>ALLOW_FAIL_PER))
// break;
// }
// Ymax=i;
// FailCount=0;
//
// Resu->x = (Xmin+Xmax)/2;
// Resu->y = (Ymin+Ymax)/2;
// Resu->w = Xmax-Xmin;
// Resu->h = Ymax-Ymin;// if(((Xmax-Xmin)>(Condition->WIDTH_MIN)) && ((Ymax-Ymin)>(Condition->HEIGHT_MIN)) &&\
// ((Xmax-Xmin)<(Condition->WIDTH_MAX)) && ((Ymax-Ymin)<(Condition->HEIGHT_MIN)) )
// return 1;
// else
// return 0;
//}唯一的API,用户将识别条件写入Condition指向的结构体中,该函数将返回目标的x,y坐标和长宽
返回1识别成功,返回1识别失败
//int Trace(const TARGET_CONDITION *Condition,RESULT *Resu)
//{
// unsigned int i;
// static unsigned int x0,y0,flag=0;
// static SEARCH_AREA Area={IMG_X,IMG_X+IMG_W,IMG_Y,IMG_Y+IMG_H};
// RESULT Result;
// // if(flag==0)
// {
// if(SearchCentre(&x0,&y0,Condition,&Area))
// flag=1;
// else
// {
// Area.X_Start= IMG_X ;
// Area.X_End = IMG_X+IMG_W ;
// Area.Y_Start= IMG_Y ;
// Area.Y_End = IMG_Y+IMG_H;// if(SearchCentre(&x0,&y0,Condition,&Area))
// {
// flag=0;
// return 0;
// }
// }
// }
// Result.x = x0;
// Result.y = y0;
//
// for(i=0;i<ITERATER_NUM;i++)
// Corrode(Result.x,Result.y,Condition,&Result);
//
// if(Corrode(Result.x,Result.y,Condition,&Result))
// {
// x0=Result.x;
// y0=Result.y;
// Resu->x=Result.x;
// Resu->y=Result.y;
// Resu->w=Result.w;
// Resu->h=Result.h;
// flag=1;// Area.X_Start= Result.x - ((Result.w)>>1);
// Area.X_End = Result.x + ((Result.w)>>1);
// Area.Y_Start= Result.y - ((Result.h)>>1);
// Area.Y_End = Result.y + ((Result.h)>>1);// return 1;
// }
// else
// {
// flag=0;
// return 0;
// }//}
#ifndef __COLORTRACER_H
#define __COLORTRACER_H#include "stm32f10x.h"#define IMG_X 0 //图片x坐标
#define IMG_Y 0 //图片y坐标
#define IMG_W 240 //图片宽度
#define IMG_H 320 //图片高度#define ALLOW_FAIL_PER 3 //容错率
#define ITERATER_NUM 8 //迭代次数typedef struct //判定为目标的条件
{unsigned char H_MIN; //目标最小色度unsigned char H_MAX; //目标最大色度unsigned char S_MIN; //目标最小饱和度unsigned char S_MAX; //目标最大饱和度unsigned char L_MIN; //目标最小亮度unsigned char L_MAX; //目标最大亮度unsigned int WIDTH_MIN; //目标最小宽度unsigned int HEIGHT_MIN; //目标最小高度unsigned int WIDTH_MAX; //目标最大宽度unsigned int HEIGHT_MAX; //目标最大高度
}TARGET_CONDITION;typedef struct //结果
{unsigned int x; //目标x坐标unsigned int y; //目标y坐标unsigned int w; //目标宽度unsigned int h; //目标高度
}RESULT;extern RESULT result;
extern TARGET_CONDITION condition0;
extern TARGET_CONDITION condition1;
extern TARGET_CONDITION condition2;
extern TARGET_CONDITION condition3;
extern TARGET_CONDITION condition4;
extern TARGET_CONDITION condition5;
extern TARGET_CONDITION condition6;
extern TARGET_CONDITION condition7;
extern TARGET_CONDITION condition8;int Trace(const TARGET_CONDITION* condition, RESULT* result_final);#endif
四、结语
好用 ,太好用了
STM32+ov7725图像识别(HSL原理)相关推荐
- STM32 OV7725摄像头模块的颜色处理和简单物体识别(串口输出图片)
目录 前言 一.摄像头采集数据流程 二.如何将图像显示到电脑上 三.图像二值化 1.什么是RGB? 2.RGB565转RGB888 I.RGB565和RGB888的区别 II.代码 3.RGB转HSL ...
- 好书荐读:阿里达摩院算法专家领衔《深度学习与图像识别:原理与实践》
点上方蓝字计算机视觉联盟获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 编辑:Sophia计算机视觉联盟 报道 | 公众号 CVLianMeng 这本书现在当当新书榜排名前三 既然为大 ...
- 计算机视觉技术的应用实例,图像识别技术都有哪些?图像识别技术原理及应用实例...
图像识别是计算机视觉和人工智能领域的重要组成部分,其终极目标是使计算机具有分析和理解图像内容的能力.图像识别是一个综合性的问题,涵盖图像匹配.图像分类.图像检索.人脸检测.行人检测等技术,并在互联网搜 ...
- 图像识别的原理和应用:从基础知识到实际案例
图像识别的原理和应用:从基础知识到实际案例 图像识别是一种利用计算机对图像进行处理.分析和理解,以识别各种不同模式的目标和对象的技术.图像识别是人工智能和计算机视觉的一个重要分支,它在各个领域都有广泛 ...
- STM32 IAP 在线升级原理全解析
点击左上角的"关注",定期更新 STM32 最新资讯,总有你想要的信息! STM32 IAP 在线升级原理全解析 1. 什么是 IAP? IAP(In-Application ...
- 二维码识别 基于stm32 ov7725
二维码识别 基于stm32 ov7725 二维码识别技术在我们的生活中应用的很方便了,但基本都是基于手机的,目前在公交车上也存在了扫描二维码的机器,上次坏了之后,发现一只小企鹅,原来是基于linux的 ...
- STM32 CAN总线工作原理
CAN总线工作原理 CAN是什么? CAN是Controller Area Network的缩写(以下称为CAN),是ISO*1国际标准化的串行通信协议. 在当前的汽车产业中,出于对安全性.舒适性.方 ...
- STM32 PWM控制舵机——原理、接线、源程序
STM32--PWM 控制舵机 通用定时输出PWM PWM的工作原理 PWM的模式 TIM_OCMode_PWM1 (边沿对齐模式) TIM_OCMode_PWM2(中央对齐模式) 占空比 舵机 实物 ...
- STM32——编码器测速原理及STM32编码器模式
1. 编码器概述 编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感 器,我们可以通过编码器测量到底位移或者速度信息.编码器从输出数据类型上 分,可以分为增量式编码器和绝对式编码器. 从 ...
最新文章
- IOS后台运行机制详解(二)
- pandas_getdummies()
- hibernate java内存一次能取多少条_Hibernate管理Session和批量操作分析
- Rational Rose 2003 下载、破解及安装方法(图文)
- 路由器上IPSEC ×××
- mysql数据库查询的传统句子
- 大数据之-Hadoop3.x_MapReduce_二次排序案例---大数据之hadoop3.x工作笔记0116
- micropython和python区别-选择C/C++还是选择MicroPython来开发?(第0章-第三节)
- 安卓手机管理软件_日程管理软件哪个好?
- i++,++i 作为参数
- VmPlayer 无法启动解决方法一例
- 从一个骗人的技术说起光线追踪——光影技术的里程碑
- 文章集合--作者篇--上【转】
- 乒乓球十一分制比赛规则_乒乓球比赛规则、技术及知识
- MUI-设置沉浸式状态栏
- 小型直播系统系列-乐聊TV的开发(一)
- mysql数据库角色的使用
- Linux内核页表管理-那些鲜为人知的秘密
- Python金融系列第八篇:Fama-French 多因子模型
- 报错Can‘t resolve ‘crypto‘ in ‘E:\test\jwt-demo-master\frontend\node_modules\jwa‘