STM32摄像头实验相关源码分享[一、颜色识别]

要每天养成写博客的习惯,可是,苦于最近学习没有进展啊。
无奈把自己去年学习STM32以及做相关项目时的代码发出来水水博客吧!
本代码在原子哥摄像头实验基础上做了相关更改。
color.c部分[用于设定颜色值、匹配颜色等]:

#include "color.h"
#include "sys.h"
#include "lcd.h"
#include <stdio.h>
RESULT result;
TARGET_CONDITION condition={
	60,				 //目标最小色度,H_MIN
	110,       //目标最大色度,H_MAX
	           
	50,        //目标最小饱和度,S_MIN
	240,       //目标最大饱和度,S_MAX
	           
	60,        //目标最小亮度,L_MIN
	190,       //目标最大亮度,L_MAX
	           
	40,        //目标最小宽度,WIDTH_MIN
	40,        //目标最小高度,HEIGHT_MIN
	           
	320,       //目标最大宽度,WIDTH_MAX
	240        //目标最大高度,HEIGHT_MAX蟾叨龋琀EIGHT_MAX
};


typedef struct						//HLS颜色
{
	unsigned char Hue;					//色度	,[0,240]				
	unsigned char Lightness;		//亮度,[0,240]	     
	unsigned char Saturation;		//饱和度,[0,240]	     
}COLOR_HLS;

typedef struct 						//RGB
{
	unsigned char Red;					// [0,255]
	unsigned char Green;        // [0,255]
	unsigned char Blue;         // [0,255]
}COLOR_RGB;
/**************************************/
//读取某点的颜色
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 );	
}
/*************************************/
//RGB转换为HLS
//H:色度
//L:亮度
//S:饱和度
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;
			}
			else if( min == g )//h介于200到240
			{
				h = 40 * ( g - b ) / dif + 240;
			}
			
		}
		else if( max == g )
		{
			h = 40 * ( b - r ) / dif + 80;
		}
		else if( max == b )
		{
			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 ) );
		}		 
	}   
    color_hls->Hue = h;							//色度
	color_hls->Lightness = l;				//亮度
	color_hls->Saturation = s;			//饱和度
}

/************************************************/
 //  颜色匹配
//color_hls :COLOR_HLS结构体,存储HLS格式颜色数据
//  condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值
// 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
	)
		return 1;
	else
		return 0;
}



/****************************************************/
//  寻找腐蚀中心
//  x :腐蚀中心x坐标
//  y :腐蚀中心y坐标
//  condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值
//  area :SEARCH_AREA结构体,查找腐蚀中心的区域
// 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;
	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 );
				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;
		
}

/***************************************************/
// 从腐蚀中心向外腐蚀,得到新的腐蚀中心
//  oldX :先前的腐蚀中心x坐标
//  oldX :先前的腐蚀中心y坐标
//  condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值
//  result :RESULT结构体,存放检测结果
// 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;
	
	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;
	
	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;
	
	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;
	
	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;
	
	if(Flag == 0)
	{
		if(SearchCenter(&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(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;
	}
	
}

main.c部分:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"	 
#include "string.h"
#include "ov7670.h"
#include "tpad.h"
#include "timer.h"
#include "exti.h"
#include "usmart.h"
#include "color.h"

 
/************************************************
 ALIENTEK精英STM32开发板实验33
 摄像头OV7670 实验
 技术支持:www.openedv.com
 淘宝店铺:http://eboard.taobao.com 
 关注微信公众平台微信号:"正点原子",免费获取STM32资料。
 广州市星翼电子科技有限公司  
 作者:正点原子 @ALIENTEK
************************************************/

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里面定义		 
//更新LCD显示
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;  
//            if(color>25500)
//                color=0x0000;
//            else
//                color=0xffff;
			LCD->LCD_RAM=color;            
		}   			       
            
 		ov_sta=0;					//清零帧中断标记
		ov_frame++; 
		LCD_Scan_Dir(DFT_SCAN_DIR);	//恢复默认扫描方向 
        if(Trace(&condition, &result))
		{
            LCD_DrawRectangle( result.x-result.w/2, result.y-result.h/2, result.x-result.w/2+result.w,  result.y-result.h/2+result.h);
            LCD_DrawRectangle( result.x-2, result.y-2,result.x+2, result.y+2);
           
		}
	} 
}	   


 int main(void)
 {	 
	//u8 key;
	u8 lightmode=0,saturation=2,contrast=2;
	u8 effect=0;	 
 	u8 i=0;	    
	u8 msgbuf[15];				//消息缓存区
	u8 tm=0; 
   //  u16 t=0;
   // u16 a,b,c;
	delay_init();	    	 //延时函数初始化	  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	//串口初始化为 115200
 	usmart_dev.init(72);		//初始化USMART		
 	LED_Init();		  			//初始化与LED连接的硬件接口
	KEY_Init();					//初始化按键
	LCD_Init();			   		//初始化LCD  
	TPAD_Init(6);				//触摸按键初始化 
 	POINT_COLOR=RED;			//设置字体为红色 
	LCD_ShowString(30,50,200,16,16,"ELITE STM32F103 ^_^");	
	LCD_ShowString(30,70,200,16,16,"OV7670 TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2015/1/18"); 
	LCD_ShowString(30,130,200,16,16,"KEY0:Light Mode");
	LCD_ShowString(30,150,200,16,16,"KEY1:Saturation");
	LCD_ShowString(30,170,200,16,16,"KEY_UP:Contrast");
	LCD_ShowString(30,190,200,16,16,"TPAD:Effects");	 
  	LCD_ShowString(30,210,200,16,16,"OV7670 Init...");	  
//	while(OV7670_Init())//初始化OV7670
	OV7670_Init();//初始化OV7670
	{
		LCD_ShowString(30,210,200,16,16,"OV7670 Error!!");
		delay_ms(200);
	    LCD_Fill(30,210,239,246,WHITE);
		delay_ms(200);
	}
 	LCD_ShowString(30,210,200,16,16,"OV7670 Init OK");
	delay_ms(1500);	 	   
	OV7670_Light_Mode(lightmode);
	OV7670_Color_Saturation(saturation);
	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)
	{	
		POINT_COLOR=BLUE;        
       // key=KEY_Scan(0);//不支持连按
//		if(key)
//		{
//			tm=20;
//			switch(key)
//			{				    
//				case KEY0_PRES:	//灯光模式Light Mode
//					lightmode++;
//					if(lightmode>4)lightmode=0;
//					OV7670_Light_Mode(lightmode);
//					sprintf((char*)msgbuf,"%s",LMODE_TBL[lightmode]);
//					break;
//				case KEY1_PRES:	//饱和度Saturation
//					saturation++;
//					if(saturation>4)saturation=0;
//					OV7670_Color_Saturation(saturation);
//					sprintf((char*)msgbuf,"Saturation:%d",(signed char)saturation-2);
//					break;
//				case WKUP_PRES:	//对比度Contrast			    
//					contrast++;
//					if(contrast>4)contrast=0;
//					OV7670_Contrast(contrast);
//					sprintf((char*)msgbuf,"Contrast:%d",(signed char)contrast-2);
//					break;
//			}
//		}	 
//		if(TPAD_Scan(0))//检测到触摸按键 
//		{
//			effect++;
//			if(effect>6)effect=0;
//			OV7670_Special_Effects(effect);//设置特效
//	 		sprintf((char*)msgbuf,"%s",EFFECTS_TBL[effect]);
//			tm=20;
//		} 
            
		camera_refresh();//更新显示
       
 		if(tm)
		{
			LCD_ShowString((lcddev.width-240)/2+30,(lcddev.height-320)/2+60,200,16,16,msgbuf);
			tm--;
		}
		i++;
		if(i==15)//DS0闪烁.
		{
			i=0;
			LED0=!LED0;
 		}
	}	   
}














发布了17 篇原创文章 · 获赞 4 · 访问量 380

猜你喜欢

转载自blog.csdn.net/qq_34916678/article/details/105400773