当前位置:   article > 正文

STM32+ov7725图像识别(HSL原理)_stm32图像识别

stm32图像识别

一、前言

嗯,玩一玩ov7725摄像头,看到个帖子有关于图像识别的,就想玩玩

二、环境

stm32驱动ov7670摄像头识别颜色并追踪_木木so的博客-CSDN博客_stm32f103驱动ov7670摄像头参照这位老哥,这位老哥之上还有鼻祖,嗯

三、正文

在寻常的摄像头刷新图像之后,加上鼻祖的第三方文件库,调用其中的api函数,即可实现腐蚀中心绘制,识别出想要识别的物体中心和方框,嗯,但是物体如果是彩色的,估计就GG了,这个原理就是根据物体的HSL颜色,具体参考链接或者自行百度,HSL比起RGB更容易被机器识别一些。

  1. #include "delay.h"
  2. #include "sys.h"
  3. #include "lcd.h"
  4. #include "usart.h"
  5. #include "string.h"
  6. #include "ov7670.h"
  7. #include "timer.h"
  8. #include "exti.h"
  9. #include "ColorTracer.h"
  10. const u8*LMODE_TBL[5]={"Auto","Sunny","Cloudy","Office","Home"}; //5种光照模式
  11. const u8*EFFECTS_TBL[7]={"Normal","Negative","B&W","Redish","Greenish","Bluish","Antique"}; //7种特效
  12. extern u8 ov_sta; //exit.c里 面定义
  13. extern u8 ov_frame; //在timer.c里面定义
  14. extern volatile uint8_t Ov7725_Vsync;
  15. //更新LCD显示
  16. u8 R,G,B;
  17. void camera_refresh(void)
  18. {
  19. u32 j;
  20. u16 color;
  21. if(ov_sta)//有帧中断更新?
  22. {
  23. LCD_Scan_Dir(U2D_L2R); //从上到下,从左到右
  24. if(lcddev.id==0X1963)LCD_Set_Window((lcddev.width-240)/2,(lcddev.height-320)/2,240,320);//将显示区域设置到屏幕中央
  25. else if(lcddev.id==0X5510||lcddev.id==0X5310)LCD_Set_Window((lcddev.width-320)/2,(lcddev.height-240)/2,320,240);//将显示区域设置到屏幕中央
  26. LCD_WriteRAM_Prepare(); //开始写入GRAM
  27. OV7670_RRST=0; //开始复位读指针
  28. OV7670_RCK_L;
  29. OV7670_RCK_H;
  30. OV7670_RCK_L;
  31. OV7670_RRST=1; //复位读指针结束
  32. OV7670_RCK_H;
  33. for(j=0;j<76800;j++)
  34. {
  35. OV7670_RCK_L;
  36. color=GPIOC->IDR&0XFF; //读数据
  37. OV7670_RCK_H;
  38. color<<=8;
  39. OV7670_RCK_L;
  40. color|=GPIOC->IDR&0XFF; //读数据
  41. OV7670_RCK_H;
  42. LCD->LCD_RAM=color;
  43. }
  44. ov_sta=0; //清零帧中断标记
  45. LCD_Scan_Dir(DFT_SCAN_DIR); //恢复默认扫描方向
  46. }
  47. }
  48. u8 i=0;
  49. int main(void)
  50. {
  51. u8 lightmode=0,saturation=2,brightness=2,contrast=2;
  52. u8 effect=0;
  53. delay_init(); //延时函数初始化
  54. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组22位抢占优先级,2位响应优先级
  55. uart_init(921600); //串口初始化为 115200
  56. LCD_Init(); //初始化LCD
  57. while(OV7670_Init())//初始化OV7670
  58. {
  59. LCD_ShowString(30,230,200,16,16,"OV7670 Error!!");
  60. delay_ms(200);
  61. LCD_Fill(30,230,239,246,WHITE);
  62. delay_ms(200);
  63. }
  64. POINT_COLOR=RED;
  65. LCD_ShowString(30,230,200,16,16,"OV7670 Init OK");
  66. delay_ms(1500);
  67. OV7670_Light_Mode(lightmode);
  68. OV7670_Color_Saturation(saturation);
  69. OV7670_Brightness(brightness);
  70. OV7670_Contrast(contrast);
  71. OV7670_Special_Effects(effect);
  72. TIM6_Int_Init(10000,7199); //10Khz计数频率,1秒钟中断
  73. EXTI8_Init(); //使能定时器捕获
  74. OV7670_Window_Set(12,176,240,320); //设置窗口
  75. OV7670_CS=0;
  76. LCD_Clear(BLACK);
  77. while(1)
  78. {
  79. camera_refresh();//更新显示
  80. if(Ov7725_Vsync == 2)
  81. {
  82. Ov7725_Vsync = 0;
  83. switch(i)
  84. {
  85. case 0:
  86. if(Trace(&condition0, &result))
  87. {
  88. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  89. printf("绿色");
  90. }
  91. else
  92. {
  93. i = 1;
  94. }
  95. break;
  96. case 1:
  97. if(Trace(&condition1, &result))
  98. {
  99. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  100. printf("蓝色");
  101. }
  102. else
  103. {
  104. i = 2;
  105. }
  106. break;
  107. case 2:
  108. if(Trace(&condition2, &result))
  109. {
  110. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  111. printf("紫色");
  112. }
  113. else
  114. {
  115. i = 3;
  116. }
  117. break;
  118. case 3:
  119. if(Trace(&condition3, &result))
  120. {
  121. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  122. printf("黑色");
  123. }
  124. else
  125. {
  126. i = 4;
  127. }
  128. break;
  129. case 4:
  130. if(Trace(&condition4, &result))
  131. {
  132. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  133. printf("橙色");
  134. }
  135. else
  136. {
  137. i = 5;
  138. }
  139. break;
  140. case 5:
  141. if(Trace(&condition5, &result))
  142. {
  143. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  144. printf("黄色");
  145. }
  146. else
  147. {
  148. i = 6;
  149. }
  150. break;
  151. case 6:
  152. if(Trace(&condition6, &result))
  153. {
  154. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  155. printf("棕色");
  156. }
  157. else
  158. {
  159. i = 8;
  160. }
  161. break;
  162. // case 7:
  163. // if(Trace(&condition7, &result))
  164. // {
  165. // LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  166. // //k = 1;
  167. // }
  168. // else
  169. // {
  170. // i = 8;
  171. // }
  172. // break;
  173. case 8:
  174. if(Trace(&condition8, &result))
  175. {
  176. LCD_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
  177. //k = 1;
  178. printf("红色");
  179. }
  180. else
  181. {
  182. i = 0;
  183. }
  184. break;
  185. }
  186. }
  187. }
  188. }

  1. #include "ColorTracer.h"
  2. #include "lcd.h"
  3. RESULT result;
  4. //TARGET_CONDITION condition={50,80,20,250,20,200,40,40,320,240};
  5. //识别的是绿色
  6. TARGET_CONDITION condition0={
  7. 60, //目标最小色度,H_MIN
  8. 110, //目标最大色度,H_MAX
  9. 45, //目标最小饱和度,S_MIN
  10. 110, //目标最大饱和度,S_MAX
  11. 90, //目标最小亮度,L_MIN
  12. 210, //目标最大亮度,L_MAX
  13. 40, //目标最小宽度,WIDTH_MIN
  14. 40, //目标最小高度,HEIGHT_MIN
  15. 240, //目标最大宽度,WIDTH_MAX
  16. 320 //目标最大高度,HEIGHT_MAX
  17. };
  18. //蓝色
  19. TARGET_CONDITION condition1={
  20. 110, //目标最小色度,H_MIN
  21. 150, //目标最大色度,H_MAX
  22. 50, //目标最小饱和度,S_MIN
  23. 150, //目标最大饱和度,S_MAX
  24. 100, //目标最小亮度,L_MIN
  25. 200, //目标最大亮度,L_MAX
  26. 40, //目标最小宽度,WIDTH_MIN
  27. 40, //目标最小高度,HEIGHT_MIN
  28. 240, //目标最大宽度,WIDTH_MAX
  29. 320 //目标最大高度,HEIGHT_MAX
  30. };
  31. //紫色
  32. TARGET_CONDITION condition2={
  33. 160, //目标最小色度,H_MIN
  34. 190, //目标最大色度,H_MAX
  35. 15, //目标最小饱和度,S_MIN
  36. 100, //目标最大饱和度,S_MAX
  37. 15, //目标最小亮度,L_MIN
  38. 190, //目标最大亮度,L_MAX
  39. 40, //目标最小宽度,WIDTH_MIN
  40. 40, //目标最小高度,HEIGHT_MIN
  41. 240, //目标最大宽度,WIDTH_MAX
  42. 320 //目标最大高度,HEIGHT_MAX
  43. };
  44. //黑色
  45. TARGET_CONDITION condition3={
  46. 80, //目标最小色度,H_MIN
  47. 160, //目标最大色度,H_MAX
  48. 10, //目标最小饱和度,S_MIN
  49. 100, //目标最大饱和度,S_MAX
  50. 10, //目标最小亮度,L_MIN
  51. 100, //目标最大亮度,L_MAX
  52. 40, //目标最小宽度,WIDTH_MIN
  53. 40, //目标最小高度,HEIGHT_MIN
  54. 240, //目标最大宽度,WIDTH_MAX
  55. 320 //目标最大高度,HEIGHT_MAX
  56. };
  57. //橙色
  58. TARGET_CONDITION condition4={
  59. 1, //目标最小色度,H_MIN
  60. 40, //目标最大色度,H_MAX
  61. 50, //目标最小饱和度,S_MIN
  62. 120, //目标最大饱和度,S_MAX
  63. 40, //目标最小亮度,L_MIN
  64. 220, //目标最大亮度,L_MAX
  65. 40, //目标最小宽度,WIDTH_MIN
  66. 40, //目标最小高度,HEIGHT_MIN
  67. 240, //目标最大宽度,WIDTH_MAX
  68. 320 //目标最大高度,HEIGHT_MAX
  69. };
  70. //黄色
  71. TARGET_CONDITION condition5={
  72. 20, //目标最小色度,H_MIN
  73. 70, //目标最大色度,H_MAX
  74. 30, //目标最小饱和度,S_MIN
  75. 200, //目标最大饱和度,S_MAX
  76. 70, //目标最小亮度,L_MIN
  77. 240, //目标最大亮度,L_MAX
  78. 40, //目标最小宽度,WIDTH_MIN
  79. 40, //目标最小高度,HEIGHT_MIN
  80. 240, //目标最大宽度,WIDTH_MAX
  81. 320 //目标最大高度,HEIGHT_MAX
  82. };
  83. //棕色
  84. TARGET_CONDITION condition6={
  85. 7, //目标最小色度,H_MIN
  86. 22, //目标最大色度,H_MAX
  87. 1, //目标最小饱和度,S_MIN
  88. 55, //目标最大饱和度,S_MAX
  89. 1, //目标最小亮度,L_MIN
  90. 160, //目标最大亮度,L_MAX
  91. 40, //目标最小宽度,WIDTH_MIN
  92. 40, //目标最小高度,HEIGHT_MIN
  93. 240, //目标最大宽度,WIDTH_MAX
  94. 320 //目标最大高度,HEIGHT_MAX
  95. };
  96. //灰白
  97. TARGET_CONDITION condition7={
  98. 60, //目标最小色度,H_MIN
  99. 170, //目标最大色度,H_MAX
  100. 0, //目标最小饱和度,S_MIN
  101. 25, //目标最大饱和度,S_MAX
  102. 160, //目标最小亮度,L_MIN
  103. 220, //目标最大亮度,L_MAX
  104. 40, //目标最小宽度,WIDTH_MIN
  105. 40, //目标最小高度,HEIGHT_MIN
  106. 240, //目标最大宽度,WIDTH_MAX
  107. 320 //目标最大高度,HEIGHT_MAX
  108. };
  109. //红色
  110. TARGET_CONDITION condition8={
  111. 200, //目标最小色度,H_MIN
  112. 240, //目标最大色度,H_MAX
  113. 5, //目标最小饱和度,S_MIN
  114. 240, //目标最大饱和度,S_MAX
  115. 5, //目标最小亮度,L_MIN
  116. 240, //目标最大亮度,L_MAX
  117. 40, //目标最小宽度,WIDTH_MIN
  118. 40, //目标最小高度,HEIGHT_MIN
  119. 240, //目标最大宽度,WIDTH_MAX
  120. 320 //目标最大高度,HEIGHT_MAX
  121. };
  122. #define minOf3Values( v1, v2, v3 ) ( (v1<v2) ? ( (v1<v3) ? (v1) : (v3) ) : ( (v2<v3) ? (v2) : (v3) ) )//取rgb中的最小值
  123. #define maxOf3Values( v1, v2, v3 ) ( (v1>v2) ? ( (v1>v3) ? (v1) : (v3) ) : ( (v2>v3) ? (v2) : (v3) ) )//取rgb中的最大值
  124. typedef struct //RGB
  125. {
  126. unsigned char Red; // [0,255]
  127. unsigned char Green; // [0,255]
  128. unsigned char Blue; // [0,255]
  129. }COLOR_RGB;
  130. typedef struct //HLS颜色
  131. {
  132. unsigned char Hue; //色度 ,[0,240]
  133. unsigned char Lightness; //亮度,[0,240]
  134. unsigned char Saturation; //饱和度,[0,240]
  135. }COLOR_HLS;
  136. COLOR_HLS h;
  137. typedef struct //搜寻区域
  138. {
  139. unsigned int X_Start;
  140. unsigned int X_End;
  141. unsigned int Y_Start;
  142. unsigned int Y_End;
  143. }SEARCH_AREA;
  144. /**
  145. * @brief 获取 ILI9341 显示器上某一个坐标点的像素数据
  146. * @param usX :在特定扫描方向下该点的X坐标
  147. * @param usY :在特定扫描方向下该点的Y坐标
  148. * @retval 像素数据
  149. */
  150. //uint16_t ILI9341_GetPointPixel( uint16_t usX, uint16_t usY )
  151. /**
  152. * @brief 读取某一点颜色数据
  153. * @param usX :该点的X坐标
  154. * @param usY :该点的Y坐标
  155. * @param color_rgb :COLOR_RGB结构体,存储颜色数据
  156. * @retval 无
  157. */
  158. static void ReadColor( uint16_t usX, uint16_t usY, COLOR_RGB* color_rgb )
  159. {
  160. unsigned short rgb;
  161. rgb = LCD_ReadPoint( usX, usY ); //获取颜色数据
  162. //转换成值域为[0,255]的三原色值
  163. color_rgb->Red = (unsigned char)( ( rgb & 0xF800 ) >> 8 );
  164. color_rgb->Green = (unsigned char)( ( rgb & 0x07E0 ) >> 3 );
  165. color_rgb->Blue = (unsigned char)( ( rgb & 0x001F ) << 3 );
  166. //color_rgb->Blue = (unsigned char)( ( rgb & 0x001F ) );
  167. }
  168. /**
  169. * @brief RGB转HLS
  170. * @param color_rgb :COLOR_RGB结构体,存储RGB格式颜色数据
  171. * @param color_hls :COLOR_HLS结构体,存储HLS格式颜色数据
  172. * @retval 无
  173. */
  174. u8 H,S,L;
  175. static void RGB2HSL( const COLOR_RGB* color_rgb, COLOR_HLS* color_hls )
  176. {
  177. int r, g, b;
  178. int h, l, s;
  179. int max, min, dif;
  180. r = color_rgb->Red;
  181. g = color_rgb->Green;
  182. b = color_rgb->Blue;
  183. max = maxOf3Values( r, g, b );
  184. min = minOf3Values( r, g, b );
  185. dif = max - min;
  186. //计算l,亮度
  187. l = ( max + min ) * 240 / 255 / 2;
  188. //计算h,色度
  189. if( max == min )//无定义
  190. {
  191. s = 0;
  192. h = 0;
  193. }
  194. else
  195. {
  196. //计算色度
  197. if( max == r )//最大值为红色
  198. {
  199. if( min == b )//h介于040 最小值为蓝色
  200. {
  201. h = 40 * ( g - b ) / dif;//h = 40 * ( g - n ) / dif;
  202. }
  203. else if( min == g )//h介于200240 最小值为绿色
  204. {
  205. h = 40 * ( g - b ) / dif + 240;
  206. }
  207. }
  208. else if( max == g )//最大值为绿色 40120
  209. {
  210. h = 40 * ( b - r ) / dif + 80;
  211. }
  212. else if( max == b )//最大值为蓝色 120 -200
  213. {
  214. h = 40 * ( r - g ) / dif + 160;
  215. }
  216. //计算饱和度
  217. if( l == 0 )
  218. {
  219. s = 0;
  220. }
  221. else if( l <= 120 )
  222. {
  223. s = dif * 240 / ( max + min );
  224. }
  225. else
  226. {
  227. s = dif * 240 / ( 480 - ( max + min ) );
  228. }
  229. }
  230. // H = h;
  231. // S = s;
  232. // L = l;
  233. color_hls->Hue = h; //色度
  234. color_hls->Lightness = l; //亮度
  235. color_hls->Saturation = s; //饱和度
  236. }
  237. /**
  238. * @brief 颜色匹配
  239. * @param color_hls :COLOR_HLS结构体,存储HLS格式颜色数据
  240. * @param condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值
  241. * @retval 1:像素点颜色在目标范围内;0:像素点颜色不在目标范围内。
  242. */
  243. static int ColorMatch(const COLOR_HLS* color_hls, const TARGET_CONDITION* condition )
  244. {
  245. if(
  246. color_hls->Hue > condition->H_MIN &&
  247. color_hls->Hue < condition->H_MAX &&
  248. color_hls->Lightness > condition->L_MIN &&
  249. color_hls->Lightness < condition->L_MAX &&
  250. color_hls->Saturation > condition->S_MIN &&
  251. color_hls->Saturation < condition->S_MAX
  252. )
  253. {
  254. H = color_hls->Hue;
  255. S = color_hls->Saturation;
  256. L = color_hls->Lightness;return 1;
  257. }
  258. else
  259. return 0;
  260. }
  261. /**
  262. * @brief 寻找腐蚀中心
  263. * @param x :腐蚀中心x坐标
  264. * @param y :腐蚀中心y坐标
  265. * @param condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值
  266. * @param area :SEARCH_AREA结构体,查找腐蚀中心的区域
  267. * @retval 1:找到了腐蚀中心,x、y为腐蚀中心的坐标;0:没有找到腐蚀中心。
  268. */
  269. static int SearchCenter(unsigned int* x, unsigned int* y, const TARGET_CONDITION* condition, SEARCH_AREA* area )
  270. {
  271. unsigned int i, j, k;
  272. unsigned int FailCount=0;
  273. unsigned int SpaceX, SpaceY;
  274. COLOR_RGB rgb;
  275. COLOR_HLS hls;
  276. SpaceX = condition->WIDTH_MIN / 3;//最小宽度 40/3
  277. SpaceY = condition->HEIGHT_MIN / 3;//最小高度 40/3
  278. for(i=area->Y_Start; i<area->Y_End; i+=SpaceY)
  279. {
  280. for(j=area->X_Start; j<area->X_End; j+=SpaceX)
  281. {
  282. FailCount = 0;
  283. for(k=0; k<SpaceX+SpaceY; k++)
  284. {
  285. if(k<SpaceX)
  286. ReadColor( j+k, i+SpaceY/2, &rgb );
  287. else
  288. ReadColor( j+SpaceX/2, i+k-SpaceX, &rgb );
  289. RGB2HSL( &rgb, &hls );
  290. if(!ColorMatch( &hls, condition ))
  291. FailCount++;
  292. if(FailCount>( (SpaceX+SpaceY) >> ALLOW_FAIL_PER ))
  293. break;
  294. }
  295. if(k == SpaceX+SpaceY)
  296. {
  297. *x = j + SpaceX / 2;
  298. *y = i + SpaceY / 2;
  299. return 1;
  300. }
  301. }
  302. }
  303. return 0;
  304. }
  305. /**
  306. * @brief 从腐蚀中心向外腐蚀,得到新的腐蚀中心
  307. * @param oldX :先前的腐蚀中心x坐标
  308. * @param oldX :先前的腐蚀中心y坐标
  309. * @param condition :TARGET_CONDITION结构体,存放希望的颜色数据阈值
  310. * @param result :RESULT结构体,存放检测结果
  311. * @retval 1:检测成功;0:检测失败。
  312. */
  313. static int Corrode(unsigned int oldX, unsigned int oldY, const TARGET_CONDITION* condition, RESULT* result )
  314. {
  315. unsigned int Xmin, Xmax, Ymin, Ymax;
  316. unsigned int i;
  317. unsigned int FailCount=0;
  318. COLOR_RGB rgb;
  319. COLOR_HLS hls;
  320. //从中心点查到x最左侧
  321. for(i=oldX; i>IMG_X; i--)
  322. {
  323. ReadColor(i, oldY, &rgb);
  324. RGB2HSL(&rgb, &hls);
  325. if(!ColorMatch(&hls, condition))
  326. FailCount++;
  327. if(FailCount>(((condition->WIDTH_MIN+condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))
  328. break;
  329. }
  330. Xmin=i;
  331. //从中心点查到x最右侧
  332. FailCount=0;
  333. for(i=oldX; i<IMG_X+IMG_W; i++)
  334. {
  335. ReadColor(i, oldY, &rgb);
  336. RGB2HSL(&rgb, &hls);
  337. if(!ColorMatch(&hls, condition))
  338. FailCount++;
  339. if(FailCount>(((condition->WIDTH_MIN+condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))
  340. break;
  341. }
  342. Xmax=i;
  343. //y上
  344. FailCount=0;
  345. for(i=oldY; i>IMG_Y; i--)
  346. {
  347. ReadColor(oldX, i, &rgb);
  348. RGB2HSL(&rgb, &hls);
  349. if(!ColorMatch(&hls, condition))
  350. FailCount++;
  351. if(FailCount>(((condition->HEIGHT_MIN+condition->HEIGHT_MAX)>>2)>>ALLOW_FAIL_PER))
  352. break;
  353. }
  354. Ymin=i;
  355. //y下
  356. FailCount=0;
  357. for(i=oldY; i<IMG_Y+IMG_H; i++)
  358. {
  359. ReadColor(oldX, i, &rgb);
  360. RGB2HSL(&rgb, &hls);
  361. if(!ColorMatch(&hls, condition))
  362. FailCount++;
  363. if(FailCount>(((condition->HEIGHT_MIN+condition->HEIGHT_MAX)>>2)>>ALLOW_FAIL_PER))
  364. break;
  365. }
  366. Ymax=i;
  367. FailCount=0;
  368. result->x = (Xmin + Xmax) / 2;
  369. result->y = (Ymin + Ymax) / 2;
  370. result->w = (Xmax - Xmin);
  371. result->h = (Ymax - Ymin);
  372. if( (result->w > condition->WIDTH_MIN) && (result->w < condition->WIDTH_MAX) &&
  373. (result->h > condition->HEIGHT_MIN) && (result->h < condition->HEIGHT_MAX) )
  374. return 1;
  375. else
  376. return 0;
  377. }
  378. int Trace(const TARGET_CONDITION* condition, RESULT* result_final)
  379. {
  380. unsigned int i;
  381. static unsigned int x0, y0, Flag = 0;
  382. static SEARCH_AREA area = {IMG_X, IMG_X+IMG_W, IMG_Y, IMG_Y+IMG_H};//搜索区域
  383. RESULT result;
  384. // for(i = 0;i<2;i++)
  385. // {
  386. if(Flag == 0)
  387. {
  388. if(SearchCenter(&x0, &y0, condition, &area))
  389. {
  390. Flag = 1;
  391. //break;
  392. }
  393. else
  394. {
  395. area.X_Start = IMG_X;
  396. area.X_End = IMG_X+IMG_W;
  397. area.Y_Start = IMG_Y;
  398. area.Y_End = IMG_Y+IMG_H;
  399. if(SearchCenter(&x0, &y0, condition, &area))
  400. {
  401. Flag = 0;
  402. return 0;
  403. }
  404. }
  405. }
  406. //}
  407. result.x = x0;
  408. result.y = y0;
  409. for(i=0; i<ITERATER_NUM; i++)
  410. {
  411. Corrode(result.x, result.y, condition, &result); //从腐蚀中心向外腐蚀,得到新的腐蚀中心
  412. }
  413. if( Corrode(result.x, result.y, condition, &result) )
  414. {
  415. x0 = result.x;
  416. y0 = result.y;
  417. result_final->x = result.x;
  418. result_final->y = result.y;
  419. result_final->w = result.w;
  420. result_final->h = result.h;
  421. Flag = 1;
  422. area.X_Start = result.x - ((result.w)>>1);
  423. area.X_End = result.x + ((result.w)>>1);
  424. area.Y_Start = result.y - ((result.h)>>1);
  425. area.Y_End = result.y + ((result.h)>>1);
  426. return 1;
  427. }
  428. else
  429. {
  430. Flag = 0;
  431. return 0;
  432. }
  433. }
  434. //#define min3v(v1, v2, v3) ((v1)>(v2)? ((v2)>(v3)?(v3):(v2)):((v1)>(v3)?(v3):(v1)))
  435. //#define max3v(v1, v2, v3) ((v1)<(v2)? ((v2)<(v3)?(v3):(v2)):((v1)<(v3)?(v3):(v1)))
  436. //typedef struct{
  437. // unsigned char red; // [0,255]
  438. // unsigned char green; // [0,255]
  439. // unsigned char blue; // [0,255]
  440. //}COLOR_RGB;//RGB格式颜色
  441. //typedef struct{
  442. // unsigned char hue; // [0,240]
  443. // unsigned char saturation; // [0,240]
  444. // unsigned char luminance; // [0,240]
  445. //}COLOR_HSL;//HSL格式颜色
  446. //typedef struct{
  447. // unsigned int X_Start;
  448. // unsigned int X_End;
  449. // unsigned int Y_Start;
  450. // unsigned int Y_End;
  451. //}SEARCH_AREA;//区域
  452. 读取RBG格式颜色,唯一需要移植的函数
  453. //extern unsigned short GUI_ReadBit16Point(unsigned short x,unsigned short y);
  454. //static void ReadColor(unsigned int x,unsigned int y,COLOR_RGB *Rgb)
  455. //{
  456. // unsigned short C16;
  457. // C16 = LCD_ReadPoint(x,y);
  458. // Rgb->red = (unsigned char)((C16&0xf800)>>8);
  459. // Rgb->green = (unsigned char)((C16&0x07e0)>>3);
  460. // Rgb->blue = (unsigned char)((C16&0x001f)<<3);
  461. //}
  462. RGB转HSL
  463. //static void RGBtoHSL(const COLOR_RGB *Rgb, COLOR_HSL *Hsl)
  464. //{
  465. // int h,s,l,maxVal,minVal,difVal;
  466. // int r = Rgb->red;
  467. // int g = Rgb->green;
  468. // int b = Rgb->blue;
  469. //
  470. // maxVal = max3v(r, g, b);
  471. // minVal = min3v(r, g, b);
  472. //
  473. // difVal = maxVal-minVal;
  474. //
  475. // //计算亮度
  476. // l = (maxVal+minVal)*240/255/2;
  477. //
  478. // if(maxVal == minVal)//若r=g=b
  479. // {
  480. // h = 0;
  481. // s = 0;
  482. // }
  483. // else
  484. // {
  485. // //计算色调
  486. // if(maxVal==r)
  487. // {
  488. // if(g>=b)
  489. // h = 40*(g-b)/(difVal);
  490. // else
  491. // h = 40*(g-b)/(difVal) + 240;
  492. // }
  493. // else if(maxVal==g)
  494. // h = 40*(b-r)/(difVal) + 80;
  495. // else if(maxVal==b)
  496. // h = 40*(r-g)/(difVal) + 160;
  497. // //计算饱和度
  498. // if(l == 0)
  499. // s = 0;
  500. // else if(l<=120)
  501. // s = (difVal)*240/(maxVal+minVal);
  502. // else
  503. // s = (difVal)*240/(480 - (maxVal+minVal));
  504. // }
  505. // Hsl->hue = (unsigned char)(((h>240)? 240 : ((h<0)?0:h)));
  506. // Hsl->saturation = (unsigned char)(((s>240)? 240 : ((s<0)?0:s)));
  507. // Hsl->luminance = (unsigned char)(((l>240)? 240 : ((l<0)?0:l)));
  508. //}
  509. 匹配颜色
  510. //static int ColorMatch(const COLOR_HSL *Hsl,const TARGET_CONDITION *Condition)
  511. //{
  512. // if(
  513. // Hsl->hue > Condition->H_MIN &&
  514. // Hsl->hue < Condition->H_MAX &&
  515. // Hsl->saturation > Condition->S_MIN &&
  516. // Hsl->saturation < Condition->S_MAX &&
  517. // Hsl->luminance > Condition->L_MIN &&
  518. // Hsl->luminance < Condition->L_MAX
  519. // )
  520. // return 1;
  521. // else
  522. // return 0;
  523. //}
  524. 搜索腐蚀中心
  525. //static int SearchCentre(unsigned int *x,unsigned int *y,const TARGET_CONDITION *Condition,const SEARCH_AREA *Area)
  526. //{
  527. // unsigned int SpaceX,SpaceY,i,j,k,FailCount=0;
  528. // COLOR_RGB Rgb;
  529. // COLOR_HSL Hsl;
  530. //
  531. // SpaceX = Condition->WIDTH_MIN/3;
  532. // SpaceY = Condition->HEIGHT_MIN/3;
  533. // for(i=Area->Y_Start;i<Area->Y_End;i+=SpaceY)
  534. // {
  535. // for(j=Area->X_Start;j<Area->X_End;j+=SpaceX)
  536. // {
  537. // FailCount=0;
  538. // for(k=0;k<SpaceX+SpaceY;k++)
  539. // {
  540. // if(k<SpaceX)
  541. // ReadColor(j+k,i+SpaceY/2,&Rgb);
  542. // else
  543. // ReadColor(j+SpaceX/2,i+(k-SpaceX),&Rgb);
  544. // RGBtoHSL(&Rgb,&Hsl);
  545. //
  546. // if(!ColorMatch(&Hsl,Condition))
  547. // FailCount++;
  548. // if(FailCount>((SpaceX+SpaceY)>>ALLOW_FAIL_PER))
  549. // break;
  550. // }
  551. // if(k==SpaceX+SpaceY)
  552. // {
  553. // *x = j+SpaceX/2;
  554. // *y = i+SpaceY/2;
  555. // return 1;
  556. // }
  557. // }
  558. // }
  559. // return 0;
  560. //}
  561. 从腐蚀中心向外腐蚀,得到新的腐蚀中心
  562. //static int Corrode(unsigned int oldx,unsigned int oldy,const TARGET_CONDITION *Condition,RESULT *Resu)
  563. //{
  564. // unsigned int Xmin,Xmax,Ymin,Ymax,i,FailCount=0;
  565. // COLOR_RGB Rgb;
  566. // COLOR_HSL Hsl;
  567. //
  568. // for(i=oldx;i>IMG_X;i--)
  569. // {
  570. // ReadColor(i,oldy,&Rgb);
  571. // RGBtoHSL(&Rgb,&Hsl);
  572. // if(!ColorMatch(&Hsl,Condition))
  573. // FailCount++;
  574. // if(FailCount>(((Condition->WIDTH_MIN+Condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))
  575. // break;
  576. // }
  577. // Xmin=i;
  578. // FailCount=0;
  579. //
  580. // for(i=oldx;i<IMG_X+IMG_W;i++)
  581. // {
  582. // ReadColor(i,oldy,&Rgb);
  583. // RGBtoHSL(&Rgb,&Hsl);
  584. // if(!ColorMatch(&Hsl,Condition))
  585. // FailCount++;
  586. // if(FailCount>(((Condition->WIDTH_MIN+Condition->WIDTH_MAX)>>2)>>ALLOW_FAIL_PER))
  587. // break;
  588. // }
  589. // Xmax=i;
  590. // FailCount=0;
  591. //
  592. // for(i=oldy;i>IMG_Y;i--)
  593. // {
  594. // ReadColor(oldx,i,&Rgb);
  595. // RGBtoHSL(&Rgb,&Hsl);
  596. // if(!ColorMatch(&Hsl,Condition))
  597. // FailCount++;
  598. // if(FailCount>(((Condition->HEIGHT_MIN+Condition->HEIGHT_MIN)>>2)>>ALLOW_FAIL_PER))
  599. // break;
  600. // }
  601. // Ymin=i;
  602. // FailCount=0;
  603. //
  604. // for(i=oldy;i<IMG_Y+IMG_H;i++)
  605. // {
  606. // ReadColor(oldx,i,&Rgb);
  607. // RGBtoHSL(&Rgb,&Hsl);
  608. // if(!ColorMatch(&Hsl,Condition))
  609. // FailCount++;
  610. // if(FailCount>(((Condition->HEIGHT_MIN+Condition->HEIGHT_MIN)>>2)>>ALLOW_FAIL_PER))
  611. // break;
  612. // }
  613. // Ymax=i;
  614. // FailCount=0;
  615. //
  616. // Resu->x = (Xmin+Xmax)/2;
  617. // Resu->y = (Ymin+Ymax)/2;
  618. // Resu->w = Xmax-Xmin;
  619. // Resu->h = Ymax-Ymin;
  620. // if(((Xmax-Xmin)>(Condition->WIDTH_MIN)) && ((Ymax-Ymin)>(Condition->HEIGHT_MIN)) &&\
  621. // ((Xmax-Xmin)<(Condition->WIDTH_MAX)) && ((Ymax-Ymin)<(Condition->HEIGHT_MIN)) )
  622. // return 1;
  623. // else
  624. // return 0;
  625. //}
  626. 唯一的API,用户将识别条件写入Condition指向的结构体中,该函数将返回目标的x,y坐标和长宽
  627. 返回1识别成功,返回1识别失败
  628. //int Trace(const TARGET_CONDITION *Condition,RESULT *Resu)
  629. //{
  630. // unsigned int i;
  631. // static unsigned int x0,y0,flag=0;
  632. // static SEARCH_AREA Area={IMG_X,IMG_X+IMG_W,IMG_Y,IMG_Y+IMG_H};
  633. // RESULT Result;
  634. //
  635. // if(flag==0)
  636. // {
  637. // if(SearchCentre(&x0,&y0,Condition,&Area))
  638. // flag=1;
  639. // else
  640. // {
  641. // Area.X_Start= IMG_X ;
  642. // Area.X_End = IMG_X+IMG_W ;
  643. // Area.Y_Start= IMG_Y ;
  644. // Area.Y_End = IMG_Y+IMG_H;
  645. // if(SearchCentre(&x0,&y0,Condition,&Area))
  646. // {
  647. // flag=0;
  648. // return 0;
  649. // }
  650. // }
  651. // }
  652. // Result.x = x0;
  653. // Result.y = y0;
  654. //
  655. // for(i=0;i<ITERATER_NUM;i++)
  656. // Corrode(Result.x,Result.y,Condition,&Result);
  657. //
  658. // if(Corrode(Result.x,Result.y,Condition,&Result))
  659. // {
  660. // x0=Result.x;
  661. // y0=Result.y;
  662. // Resu->x=Result.x;
  663. // Resu->y=Result.y;
  664. // Resu->w=Result.w;
  665. // Resu->h=Result.h;
  666. // flag=1;
  667. // Area.X_Start= Result.x - ((Result.w)>>1);
  668. // Area.X_End = Result.x + ((Result.w)>>1);
  669. // Area.Y_Start= Result.y - ((Result.h)>>1);
  670. // Area.Y_End = Result.y + ((Result.h)>>1);
  671. // return 1;
  672. // }
  673. // else
  674. // {
  675. // flag=0;
  676. // return 0;
  677. // }
  678. //}
  1. #ifndef __COLORTRACER_H
  2. #define __COLORTRACER_H
  3. #include "stm32f10x.h"
  4. #define IMG_X 0 //图片x坐标
  5. #define IMG_Y 0 //图片y坐标
  6. #define IMG_W 240 //图片宽度
  7. #define IMG_H 320 //图片高度
  8. #define ALLOW_FAIL_PER 3 //容错率
  9. #define ITERATER_NUM 8 //迭代次数
  10. typedef struct //判定为目标的条件
  11. {
  12. unsigned char H_MIN; //目标最小色度
  13. unsigned char H_MAX; //目标最大色度
  14. unsigned char S_MIN; //目标最小饱和度
  15. unsigned char S_MAX; //目标最大饱和度
  16. unsigned char L_MIN; //目标最小亮度
  17. unsigned char L_MAX; //目标最大亮度
  18. unsigned int WIDTH_MIN; //目标最小宽度
  19. unsigned int HEIGHT_MIN; //目标最小高度
  20. unsigned int WIDTH_MAX; //目标最大宽度
  21. unsigned int HEIGHT_MAX; //目标最大高度
  22. }TARGET_CONDITION;
  23. typedef struct //结果
  24. {
  25. unsigned int x; //目标x坐标
  26. unsigned int y; //目标y坐标
  27. unsigned int w; //目标宽度
  28. unsigned int h; //目标高度
  29. }RESULT;
  30. extern RESULT result;
  31. extern TARGET_CONDITION condition0;
  32. extern TARGET_CONDITION condition1;
  33. extern TARGET_CONDITION condition2;
  34. extern TARGET_CONDITION condition3;
  35. extern TARGET_CONDITION condition4;
  36. extern TARGET_CONDITION condition5;
  37. extern TARGET_CONDITION condition6;
  38. extern TARGET_CONDITION condition7;
  39. extern TARGET_CONDITION condition8;
  40. int Trace(const TARGET_CONDITION* condition, RESULT* result_final);
  41. #endif

四、结语

好用 ,太好用了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/401501
推荐阅读
相关标签
  

闽ICP备14008679号