RGB转化为HSV
首先将rgb转化为hsv,代码如下图所示
READ_FIFO_PIXEL(Camera_Data); /* 从FIFO读出一个rgb565像素到Camera_Data变量 */
R = Camera_Data & 0xF800;
G = Camera_Data & 0x07E0;
B = Camera_Data & 0x001F;
if (j%10==0 && i%10==0) //rgb转换为hsv
{
float rr,gg,bb;
R=R>>11;
G=G>>5;
rr=R/(float)32;
gg=G/(float)64;
bb=B/(float)32;
float h,s,v;
float max=0;
float min=0;
max = rr;
if(max<gg)
max = gg;
if(max<bb)
max = bb;
min = rr;
if(min>gg)
min = gg;
if(min>bb)
min = bb;
v = max;
if(max == 0)
s = 0;
else
s = 1 - (min/max);
if(max == min)
h = 0;
else if(max == rr && gg>=bb)
h = 60*((gg-bb)/(max-min));
else if(max == rr && gg<bb)
h = 60*((gg-bb)/(max-min)) + 360;
else if(max == gg)
h = 60*((bb-rr)/(max-min)) + 120;
else if(max == bb)
h = 60*((rr-gg)/(max-min)) + 240;
v = v * 100;
s = s * 100;
这里每一个循环里面需要开一个窗口然后在之后需要对每一个窗口进行赋值,按道理可以在循环外面开一个240*320的窗口,但是尝试之后效果与预期不同。
计算HSV阈值
在转化为hsv之后就可以计算出中间区域的hsv值,方便后期设置物体hsv的阈值,计算代码如图
循环之内的函数
if (j>160-14&j<160+14&i>120-14&i<120+14) //计算中心处hsv的值
{
sum_h=sum_h+h;
sum_s=sum_s+s;
sum_v=sum_v+v;
size_hsv++;
}
循环外的函数(这里是打印出来,可以用自己输出函数)
sprintf(hchar,"h=%.5f",sum_h/size_hsv);
sprintf(schar,"s=%.5f",sum_s/size_hsv);
sprintf(vchar,"v=%.5f",sum_v/size_hsv);
ILI9341_DispString_EN (0,0, &hchar[0] );
ILI9341_DispString_EN (0,30, &schar[0] );
ILI9341_DispString_EN (0,60, &vchar[0] );
由于平均值是在循环结束之后计算得出,所以需要在循环结束之后打印出来。
实验效果如图:
判断HSV阈值
通过hsv的值计算出图像的上下hsv的阈值,在函数里面添加一个判断条件,只有在hsv阈值内的才显示白色的点,为了加快计算速度,函数中选择每十个点计算一次。
函数如图所示:定义阈值变量
uint16_t R, G, B, H_hi = 70, H_lo = 20, S_hi = 70, S_lo = 20, V_hi = 100, V_lo = 60;
if( (h>H_lo && h<H_hi) && (s>S_lo && s<S_hi) && (v>V_lo && v<V_hi)) //根据阈值判断目标物体,并取中心点的
{
sum_x=sum_x+j;
sum_y=sum_y+i;
size_points++;
Camera_Data = 0xffff;
}
else Camera_Data = 0x0000;
实验效果如图:
色块中心坐标提取:
循环内:
if( (h>H_lo && h<H_hi) && (s>S_lo && s<S_hi) && (v>V_lo && v<V_hi)) //根据阈值判断目标物体,并取中心点的
{
sum_x=sum_x+j;
sum_y=sum_y+i;
size_points++;
Camera_Data = 0xffff;
}
else Camera_Data = 0x0000;
循环外:
center_objx=sum_x/size_points;
center_objy=sum_y/size_points;
轨迹描画
代码如图:
if (num_cal < 5)
{
centerx[num_cal]=center_objx;
centery[num_cal]=center_objy;
}
else
{
centerx[0]=centerx[1];
centerx[1]=centerx[2];
centerx[2]=centerx[3];
centerx[3]=centerx[4];
centerx[4]=center_objx;
centery[0]=centery[1];
centery[1]=centery[2];
centery[2]=centery[3];
centery[3]=centery[4];
centery[4]=center_objy;
}
num_cal++;
if(num_cal > 5)
{
for (int i=0;i<4;i++)
{
ILI9341_DrawLine(centerx[i], centery[i], centerx[i+1], centery[i+1]);
}
}
解释:首先先记录前五个中心点位置的值,然后第六个值覆盖第五个值,第四个值覆盖第三个值,以此类推,最后将这五个值连线出来即可,这里需要注意,由于每一帧图片都要记录出目标的中心坐标,也需要记录之前帧图像的目标的中心坐标,所以这里的变量都需要设置为static,使得跳出函数时临时变量不清空。
效果如图:
总体代码如下
void ImagDisp(uint16_t sx,uint16_t sy,uint16_t width,uint16_t height)
{
uint16_t i, j;
uint16_t Camera_Data;
uint16_t R, G, B, H_hi = 70, H_lo = 20, S_hi = 70, S_lo = 20, V_hi = 100, V_lo = 60;
double sum_h=0,sum_s=0,sum_v=0,size_hsv=0;
char hchar[20],schar[20],vchar[20];
uint16_t sum_x=0,sum_y=0,size_points=0;
static uint8_t num_cal;
static float centerx[5],centery[5];
float center_objx,center_objy;
// ILI9341_OpenWindow(sx,sy,width,height);
// ILI9341_Write_Cmd ( CMD_SetPixel );
for(i = 0; i < 240; i++)
{
for(j = 0; j < 320; j++)
{
ILI9341_OpenWindow ( j, i, 1, 1 );
ILI9341_Write_Cmd ( CMD_SetPixel );
READ_FIFO_PIXEL(Camera_Data); /* 从FIFO读出一个rgb565像素到Camera_Data变量 */
R = Camera_Data & 0xF800;
G = Camera_Data & 0x07E0;
B = Camera_Data & 0x001F;
if (j%10==0 && i%10==0) //rgb转换为hsv
{
float rr,gg,bb;
R=R>>11;
G=G>>5;
rr=R/(float)32;
gg=G/(float)64;
bb=B/(float)32;
float h,s,v;
float max=0;
float min=0;
max = rr;
if(max<gg)
max = gg;
if(max<bb)
max = bb;
min = rr;
if(min>gg)
min = gg;
if(min>bb)
min = bb;
v = max;
if(max == 0)
s = 0;
else
s = 1 - (min/max);
if(max == min)
h = 0;
else if(max == rr && gg>=bb)
h = 60*((gg-bb)/(max-min));
else if(max == rr && gg<bb)
h = 60*((gg-bb)/(max-min)) + 360;
else if(max == gg)
h = 60*((bb-rr)/(max-min)) + 120;
else if(max == bb)
h = 60*((rr-gg)/(max-min)) + 240;
v = v * 100;
s = s * 100;
if( (h>H_lo && h<H_hi) && (s>S_lo && s<S_hi) && (v>V_lo && v<V_hi)) //根据阈值判断目标物体,并取中心点的
{
sum_x=sum_x+j;
sum_y=sum_y+i;
size_points++;
Camera_Data = 0xffff;
}
else Camera_Data = 0x0000;
ILI9341_Write_Data(Camera_Data);
// if (j>160-14&j<160+14&i>120-14&i<120+14) //计算中心处hsv的值
// {
// sum_h=sum_h+h;
// sum_s=sum_s+s;
// sum_v=sum_v+v;
// size_hsv++;
// }
}
}
}
center_objx=sum_x/size_points;
center_objy=sum_y/size_points;
if (num_cal < 5)
{
centerx[num_cal]=center_objx;
centery[num_cal]=center_objy;
}
else
{
centerx[0]=centerx[1];
centerx[1]=centerx[2];
centerx[2]=centerx[3];
centerx[3]=centerx[4];
centerx[4]=center_objx;
centery[0]=centery[1];
centery[1]=centery[2];
centery[2]=centery[3];
centery[3]=centery[4];
centery[4]=center_objy;
}
num_cal++;
if(num_cal > 5)
{
for (int i=0;i<4;i++)
{
ILI9341_DrawLine(centerx[i], centery[i], centerx[i+1], centery[i+1]);
}
}
// sprintf(hchar,"h=%.5f",sum_h/size_hsv);
// sprintf(schar,"s=%.5f",sum_s/size_hsv);
// sprintf(vchar,"v=%.5f",sum_v/size_hsv);
// ILI9341_DispString_EN (0,0, &hchar[0] );
// ILI9341_DispString_EN (0,30, &schar[0] );
// ILI9341_DispString_EN (0,60, &vchar[0] );
}