一、前言

嗯,玩一玩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_MIN
	110,       //目标最大色度,H_MAX
	           
	45,        //目标最小饱和度,S_MIN
	110,       //目标最大饱和度,S_MAX
	           
	90,        //目标最小亮度,L_MIN
	210,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
//蓝色
TARGET_CONDITION condition1={
	110,				 //目标最小色度,H_MIN
	150,       //目标最大色度,H_MAX
	           
	50,        //目标最小饱和度,S_MIN
	150,       //目标最大饱和度,S_MAX
	           
	100,        //目标最小亮度,L_MIN
	200,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
 
//紫色
TARGET_CONDITION condition2={
	160,				 //目标最小色度,H_MIN
	190,       //目标最大色度,H_MAX
	           
	15,        //目标最小饱和度,S_MIN
	100,       //目标最大饱和度,S_MAX
	           
	15,        //目标最小亮度,L_MIN
	190,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
//黑色
TARGET_CONDITION condition3={
	80,				 //目标最小色度,H_MIN
	160,       //目标最大色度,H_MAX
	           
	10,        //目标最小饱和度,S_MIN
	100,       //目标最大饱和度,S_MAX
	           
	10,        //目标最小亮度,L_MIN
	100,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
//橙色
TARGET_CONDITION condition4={
	1,				 //目标最小色度,H_MIN
	40,       //目标最大色度,H_MAX
	           
	50,        //目标最小饱和度,S_MIN
	120,       //目标最大饱和度,S_MAX
	           
	40,        //目标最小亮度,L_MIN
	220,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX	
};
//黄色
TARGET_CONDITION condition5={
	20,				 //目标最小色度,H_MIN
	70,       //目标最大色度,H_MAX
	           
	30,        //目标最小饱和度,S_MIN
	200,       //目标最大饱和度,S_MAX
	           
	70,        //目标最小亮度,L_MIN
	240,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
 
//棕色
TARGET_CONDITION condition6={
	7,				 //目标最小色度,H_MIN
	22,       //目标最大色度,H_MAX
	           
	1,        //目标最小饱和度,S_MIN
	55,       //目标最大饱和度,S_MAX
	           
	1,        //目标最小亮度,L_MIN
	160,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
//灰白
TARGET_CONDITION condition7={
	60,				 //目标最小色度,H_MIN
	170,       //目标最大色度,H_MAX
	           
	0,        //目标最小饱和度,S_MIN
	25,       //目标最大饱和度,S_MAX
	           
	160,        //目标最小亮度,L_MIN
	220,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,HEIGHT_MAX
};
//红色
TARGET_CONDITION condition8={
	200,				 //目标最小色度,H_MIN
	240,       //目标最大色度,H_MAX
	           
	5,        //目标最小饱和度,S_MIN
	240,       //目标最大饱和度,S_MAX
	           
	5,        //目标最小亮度,L_MIN
	240,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	240,       //目标最大宽度,WIDTH_MAX
	320        //目标最大高度,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;
	}
		
	else
		return 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/3
	SpaceY = condition->HEIGHT_MIN / 3;//最小高度 40/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 );
				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;
	else
		return 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


四、结语

好用 ,太好用了