国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

STM32 OV7725攝像頭模塊識別顏色物體(1)--HSL二值化和腐蝕中心算法,并用串口輸出數(shù)據(jù)

這篇具有很好參考價值的文章主要介紹了STM32 OV7725攝像頭模塊識別顏色物體(1)--HSL二值化和腐蝕中心算法,并用串口輸出數(shù)據(jù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

前言

一、攝像頭采集數(shù)據(jù)流程

二、如何將圖像顯示到電腦上

?三、圖像二值化

1、什么是RGB?

2、RGB565轉(zhuǎn)RGB888

I、RGB565和RGB888的區(qū)別

II、代碼

3、RGB轉(zhuǎn)HSL

I、什么是HSL

?II、轉(zhuǎn)換公式

?III、代碼

3、輸出一張攝像頭二值化圖片

I、原理

II、代碼?

四、簡單的物體識別

1、原理參考

?2、識別代碼

3、顯示代碼

總結(jié)



前言

前陣子用STM32弄攝像頭,斷斷續(xù)續(xù)有段時間,也在網(wǎng)上翻閱了不少資料,寫篇博客記錄一下學習過程。最后成功識別單個物體,圖形和多個物體暫不支。

一、攝像頭采集數(shù)據(jù)流程

(1) 利用 SIO_C、SIO_D 引腳通過 SCCB 協(xié)議向 OV7725 的寄存器寫入初始化配置;

(2) 初始化完成后,OV7725 傳感器會使用 VGA 時序輸出圖像數(shù)據(jù),它的 VSYNC 會

首先輸出幀有效信號(低電平跳變),當外部的控制器(如 STM32)檢測到該信號

時,把 WEN 引腳設置為高電平,并且使用 WRST 引腳復位 FIFO 的寫指針到 0 地

址;

(3) 隨著 OV7725 繼續(xù)按 VGA 時序輸出圖像數(shù)據(jù),它在傳輸每行有效數(shù)據(jù)時, HREF

引腳都會持續(xù)輸出高電平,由于 WEN 和 HREF 同時為高電平輸入至與非門,使得

其連接到 FIFO WE 引腳的輸出為低電平,允許向 FIFO 寫入數(shù)據(jù),所以在這期間,

OV7725 通過它的 PCLK 和 D[0:7]信號線把圖像數(shù)據(jù)存儲到 FIFO 中,由于前面復

位了寫指針,所以圖像數(shù)據(jù)是從 FIFO 的 0 地址開始記錄的;

(4) 各行圖像數(shù)據(jù)持續(xù)傳輸至 FIFO,受 HREF 控制的 WE 引腳確保了寫入到 FIFO 中

的都是有效的圖像數(shù)據(jù),OV7725 輸出完一幀數(shù)據(jù)時,VSYNC 會再次輸出幀有效

信號,表示一幀圖像已輸出完成;

(5) 控制器檢測到上述 VSYNC 信號后,可知 FIFO 中已存儲好一幀圖像數(shù)據(jù),這時控

制 WEN 引腳為低電平,使得 FIFO 禁止寫入,防止 OV7725 持續(xù)輸出的下一幀數(shù)

據(jù)覆蓋當前 FIFO 數(shù)據(jù);

(6) 控制器使用RRST復位讀指針到FIFO的0地址,然后通過FIFO的RCLK和DO[0:7]

引腳,從 0 地址開始把 FIFO 緩存的整幀圖像數(shù)據(jù)讀取出來。在這期間,OV7725

是持續(xù)輸出它采集到的圖像數(shù)據(jù)的,但由于禁止寫入 FIFO,這些數(shù)據(jù)被丟棄了;

(7) 控制器使用 WRST 復位寫指針到 FIFO 的 0 地址,然后等待新的 VSYNC 有效信號

到來,檢測到后把 WEN 引腳設置為高電平,恢復 OV7725 向 FIFO 的寫入權(quán)限,

OV7725 輸出的新一幀圖像數(shù)據(jù)會被寫入到 FIFO 的 0 地址中,重復上述過程。

ov7725 stm32,stm32,圖像處理

網(wǎng)上也有很多現(xiàn)成的文章,分享幾個鏈接

攝像頭原理:

stm32 OV7670攝像頭模塊的介紹以及應用(SCCB的使用)_閏土小蔣的博客-CSDN博客

正點原子開發(fā)板程序:

http://www.openedv.com/docs/modules/camera/ov7725-fifo.html

二、如何將圖像顯示到電腦上

使用串口發(fā)送數(shù)據(jù)到電腦,用山外調(diào)試助手顯示,這里的波特率使用256000,因為調(diào)試助手的最大也只能是256000,圖像配置,寬:320,高:240,RGB565大端(這個是個大坑)

一副圖像的通信協(xié)議為:[0x01] [0xFE][…數(shù)據(jù)…][0xFE] [0x01]

[…數(shù)據(jù)…] 是圖像的數(shù)據(jù),一幀圖像有多少數(shù)據(jù),這里的數(shù)據(jù)長度就有多少。換句話說, […數(shù)據(jù)…]與圖像的格式,圖像的寬高有關(guān)。此處的圖像數(shù)據(jù),都是從上往下,從左往右存儲 的。 只有下位機發(fā)送的數(shù)據(jù)與上位機配置的格式的長度相同時,才可正確識別圖像格式,從 而正確顯示圖像。 下位機發(fā)送圖像時,先發(fā)送幀頭:0x01,0xFE,接著發(fā)送圖像數(shù)據(jù),最后發(fā)送幀尾: 0xFE,0x01 完成一副圖像發(fā)送。

ov7725 stm32,stm32,圖像處理

鏈接:https://pan.baidu.com/s/1eA3rhtNiocKxtH0rxvyGzg?pwd=0722?
提取碼:0722

攝像頭采集代碼如下:

?? ??? ?OV7725_RRST(0);?? ??? ??? ??? ?//開始復位讀指針?
?? ??? ?OV7725_RCK_L;
?? ??? ?OV7725_RCK_H;
?? ??? ?OV7725_RCK_L;
?? ??? ?OV7725_RRST(1);?? ??? ??? ??? ?//復位讀指針結(jié)束?
?? ??? ?OV7725_RCK_H;
? ?
? ? ? ? while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET); ? ? ?//判斷是否發(fā)送完成。
? ? ? ? USART_SendData(UART4, 0x01);
? ? ? ? while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET); ? ? ?//判斷是否發(fā)送完成。
? ? ? ? USART_SendData(UART4, 0xfe);
? ? ? ?
?? ??? ?for(x_size=0;x_size<240;x_size++)
?? ??? ?{
?? ??? ??? ?for(y_size=0;y_size<320;y_size++)
?? ??? ??? ?{
?? ??? ??? ??? ?OV7725_RCK_L;
?? ??? ??? ??? ?color=GPIOE->IDR;?? ?//讀數(shù)據(jù)
?? ??? ??? ??? ?OV7725_RCK_H;
?? ??? ??? ??? ?colorH=(color>>8) &0xff;
?? ??? ??? ??? ?OV7725_RCK_L;
?? ??? ??? ??? ?color=GPIOE->IDR ;?? ?//讀數(shù)據(jù)
?? ??? ??? ??? ?OV7725_RCK_H;?
?? ??? ??? ??? ?colorL=(color>>8) &0xff;
?? ??? ??? ??? ?
? ? ? ? ? ? ? ? while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET); ? ? ?//判斷是否發(fā)送完成。
? ? ? ? ? ? ? ? USART_SendData(UART4, colorH);
? ? ? ? ? ? ? ? while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET); ? ? ?//判斷是否發(fā)送完成。
? ? ? ? ? ? ? ? USART_SendData(UART4, colorL);
?? ??? ??? ?}
?? ??? ?}

? ? ? ? while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET); ? ? ?//判斷是否發(fā)送完成。
? ? ? ? USART_SendData(UART4, 0xfe);
? ? ? ? while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET); ? ? ?//判斷是否發(fā)送完成。
? ? ? ? USART_SendData(UART4, 0x01);

?三、圖像二值化

1、什么是RGB?

????????RGB是從顏色發(fā)光的原理來設計定的,通俗點說它的顏色混合方式就好像有紅、綠、藍三盞燈,當它們的光相互疊合的時候,色彩相混,而亮度卻等于兩者亮度之總和,越混合亮度越高,即加法混合。

????????紅、綠、藍三個顏色通道每種色各分為256階亮度,在0時“燈”最弱——是關(guān)掉的,而在255時“燈”最亮。當三色灰度數(shù)值相同時,產(chǎn)生不同灰度值的灰色調(diào),即三色灰度都為0時,是最暗的黑色調(diào);三色灰度都為255時,是最亮的白色調(diào)。

????????在電腦中,RGB的所謂“多少”就是指亮度,并使用整數(shù)來表示。通常情況下,RGB各有256級亮度,用數(shù)字表示為從0、1、2...直到255。注意雖然數(shù)字最高是255,但0也是數(shù)值之一,因此共256級。

ov7725 stm32,stm32,圖像處理

2、RGB565轉(zhuǎn)RGB888

I、RGB565和RGB888的區(qū)別

在計算機中圖像基本是以RGB888格式顯示的,24位圖每個像素保存了32bit的數(shù)據(jù),即RGB888+Alpha,Alpha就是半透明填充字節(jié)。對于真彩的圖像而言,肉眼在16bit的時候已經(jīng)難以分辨了,有些時候,可以將RGB888轉(zhuǎn)換為RGB565來存儲,減少了存儲器的容量的同時,降低了數(shù)據(jù)量;在顯示的時候,再次把RGB565轉(zhuǎn)換為RGB888,實現(xiàn)數(shù)據(jù)寬度的匹配

RGB888->RGB565

只要提取相應單色高位即可(R5 G6 B5),但會導致低位的缺失,影響精度,而且無法恢復

RGB565->RGB888

填充相應單色低位即可

ov7725 stm32,stm32,圖像處理

ov7725 stm32,stm32,圖像處理

II、代碼

typedef struct 					//RGB888
{
	unsigned char Red;			//紅色,[0,255]
	unsigned char Green;        //綠色,[0,255]
	unsigned char Blue;         //藍色,[0,255]
}COLOR_RGB;

void RGB565_To_RGB888(u16 rgb,COLOR_RGB *color_rgb)
{
	color_rgb->Red 	    = (unsigned char)( ( rgb & 0xF800 ) >> 8 );
	color_rgb->Green    = (unsigned char)( ( rgb & 0x07E0 ) >> 3 );
	color_rgb->Blue 	= (unsigned char)( ( rgb & 0x001F ) << 3 );	
}

3、RGB轉(zhuǎn)HSL

I、什么是HSL

ov7725 stm32,stm32,圖像處理

?HSL的H(hue)分量,代表的是人眼所能感知的顏色范圍,這些顏色分布在一個平面的色相環(huán)上,取值范圍是0°到360°的圓心角,每個角度可以代表一種顏色。色相值的意義在于,我們可以在不改變光感的情況下,通過旋轉(zhuǎn)色相環(huán)來改變顏色。在實際應用中,我們需要記住色相環(huán)上的六大主色,用作基本參照:360°/0°紅、60°黃、120°綠、180°青、240°藍、300°洋紅,它們在色相環(huán)上按照60°圓心角的間隔排列

ov7725 stm32,stm32,圖像處理

HSL的S(saturation)分量,指的是色彩的飽和度,它用0%至100%的值描述了相同色相、明度下色彩純度的變化。數(shù)值越大,顏色中的灰色越少,顏色越鮮艷,呈現(xiàn)一種從灰度到純色的變化。

ov7725 stm32,stm32,圖像處理

HSL的L(lightness)分量,指的是色彩的明度,作用是控制色彩的明暗變化。它同樣使用了0%至100%的取值范圍。數(shù)值越小,色彩越暗,越接近于黑色;數(shù)值越大,色彩越亮,越接近于白色。

ov7725 stm32,stm32,圖像處理

?II、轉(zhuǎn)換公式

ov7725 stm32,stm32,圖像處理

?III、代碼

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

#define maxOf3Values( v1, v2, v3 )			( (v1>v2) ? ( (v1>v3) ? (v1) : (v3) ) : ( (v2>v3) ? (v2) : (v3) ) ) //取rgb中的最大值
#define minOf3Values( v1, v2, v3 )			( (v1<v2) ? ( (v1<v3) ? (v1) : (v3) ) : ( (v2<v3) ? (v2) : (v3) ) ) //取rgb中的最小值


void RGB888_TO_HSL(COLOR_RGB* color_rgb, COLOR_HLS* color_hls)
{
	unsigned char r, g, b;
	unsigned char h, l, s;
	unsigned char max, min, dif;
	
	r = color_rgb->Red;
	g = color_rgb->Green;
	b = color_rgb->Blue;
	
	max = maxOf3Values( r, g, b );  //取rgb中的最大值
	min = minOf3Values( r, g, b );  //取rgb中的最小值
	dif = max - min;                //計算最大值和最小值的差值
    
	//計算l,亮度
	l = ( max + min ) * 240 / 255 / 2;
	//計算h,色度
	if( max == min )//無定義 RGB一樣  黑灰白
	{
		s = 0;//飽和度0
		h = 0;//色度0
	}
	else
	{
		/*計算色度h*/
		if( max == r )      //如果R值最大
		{
			if( g >= b )    //h介于0到40
			{
				h = 40 * ( g - b ) / dif;
			}
			else if( g < b )//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;
		}
		/*計算飽和度s*/
		if( l == 0 )
		{
			s = 0;
		}
		else if( l <= 120 )      /* 0<l<=1/2 */
		{
			s = dif * 240 / ( max + min );                  
		}
		else                    /* l>1/2 */
		{
			s = dif * 240 / ( 480 - ( max + min ) );        
		}		 
	}   
    color_hls->Hue = h;				//色度
	color_hls->Lightness = l;		//亮度
	color_hls->Saturation = s;		//飽和度
}

3、輸出一張攝像頭二值化圖片

I、原理

攝像頭采集到的每個像素點,先由RGB格式轉(zhuǎn)換成HSL格式,再與定義閾值進行對比,判斷顏色是否和定義顏色匹配

II、代碼?

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 short WIDTH_MIN;	//目標最小寬度
	unsigned short HEIGHT_MIN;	//目標最小高度
	
	unsigned short WIDTH_MAX;   //目標最大寬度
	unsigned short HEIGHT_MAX;	//目標最大高度
}TARGET_CONDITION;

int ColorMatch(const COLOR_HLS* color_hls, const TARGET_CONDITION* condition )
{
	if(	color_hls->Lightness >= condition->L_MIN && color_hls->Lightness <= condition->L_MAX &&
		color_hls->Saturation >= condition->S_MIN && color_hls->Saturation <= condition->S_MAX )   //比較飽和度和亮度
    {      
        if( color_hls->Hue >= condition->H_MIN && color_hls->Hue <= condition->H_MAX )   //顏色在范圍內(nèi)
        {   
            return 1;
        }       
        else if( condition->H_MAX < condition->H_MIN )  //設定的最大顏色小于最小顏色 說明有向下溢出 可能需要和高位顏色匹配            
        {
            /*0——有效——最大值——無效——最小值——有效——240*/
            if( color_hls->Hue <= condition->H_MAX )     //小于最大值
                return 1;
            if( color_hls->Hue >= condition->H_MIN )     //大于最小值
                return 1;
        } 
    }
	return 0;
}

判斷顏色是否和定義顏色匹配。

輸入變量,color_hls:COLOR_HLS結(jié)構(gòu)體,存儲HLS格式顏色數(shù)據(jù);?

? ? ? ? ? ? ? ? ?condition :TARGET_CONDITION結(jié)構(gòu)體,存放希望的顏色數(shù)據(jù)閾值。

返回數(shù)據(jù),1:像素點顏色在目標范圍內(nèi);0:像素點顏色不在目標范圍內(nèi)。

u8 Bmp_Minimize_SDRAM[240][40];  /*用于存放二值化后像素點數(shù)據(jù),Bmp_Minimize_SDRAM[X][Y]*/

TARGET_CONDITION condition0={
	40,		  //目標最小色度,H_MIN
	80,       //目標最大色度,H_MAX
	           
	0,        //目標最小飽和度,S_MIN
	240,       //目標最大飽和度,S_MAX
	           
	0,        //目標最小亮度,L_MIN
	240,       //目標最大亮度,L_MAX
	           
	40,        //目標最小寬度,WIDTH_MIN
	40,        //目標最小高度,HEIGHT_MIN
	           
	240,       //目標最大寬度,WIDTH_MAX
	320        //目標最大高度,HEIGHT_MAX
};

for(x_size=0;x_size<240;x_size++)   //此種方式可以兼容任何彩屏,但是速度很慢
{
    for(y_size=0;y_size<320;y_size++)
    {
        OV7725_RCK_L;
        color=GPIOE->IDR;	//讀數(shù)據(jù)
        OV7725_RCK_H;
        colorH=(color>>8) &0xff;
        OV7725_RCK_L;
        color=GPIOE->IDR ;	//讀數(shù)據(jù)
        OV7725_RCK_H; 
        colorL=(color>>8) &0xff;
        
        color=(colorH<<8)|colorL;

        RGB565_TO_HSL(color,&hls_value);        /*RGB565轉(zhuǎn)換為HLS*/
        
        if(y_size%8==0)
        {
            Bmp_Minimize_SDRAM[x_size][y_size/8]=color_buffer;      /*二值化后的數(shù)據(jù),存入緩存*/
        }
        color_buffer<<=1;
        color_buffer|=ColorMatch(&hls_value,&condition0);
    }
}

攝像頭采集數(shù)據(jù)二值化,由于STM32F1內(nèi)存有限,存放不了一幀320*240的彩色圖像,故將處理好后的數(shù)據(jù)存入數(shù)組

while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
USART_SendData(UART4, 0x01);
while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
USART_SendData(UART4, 0xfe);
for(y_size=0;y_size<240;y_size++)     /*數(shù)組數(shù)據(jù)串口打印到電腦*/
{
    for(x_size=0;x_size<40;x_size++)
    {
        color=Bmp_Minimize_SDRAM[y_size][x_size+1];
        for(color_buffer=0;color_buffer<8;color_buffer++)
        {
            if((color<<color_buffer) &0x80)
            {
                while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
                USART_SendData(UART4, 0xff);
                while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
                USART_SendData(UART4, 0xff);
            }
            else
            {
                while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
                USART_SendData(UART4, 0x00);
                while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
                USART_SendData(UART4, 0x00);                        
            }
        }
    }
}
while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
USART_SendData(UART4, 0xfe);
while(USART_GetFlagStatus(UART4, USART_FLAG_TC)==RESET);      //判斷是否發(fā)送完成。
USART_SendData(UART4, 0x01);

將存放在緩存中的二值化數(shù)據(jù),通過簡單位操作輸出到調(diào)試助手

ov7725 stm32,stm32,圖像處理

四、簡單的物體識別

1、原理參考

首先遍歷尋找腐蝕中心,然后在之前腐蝕中心點處進行迭代向外尋找新的腐蝕中心。腐蝕算法從該點開始分別向上下左右四個方向進行讀點,若點的顏色符合條件則往外讀,等四個方向都結(jié)束后得到四個邊緣點的坐標,記左邊緣點的x軸坐標為left,右邊緣點的x軸坐標為right,上邊緣點的y軸坐標為up,下邊緣點的y軸坐標為bottom,那么坐標( (right-left)/2 , (up-bottom)/2 ) 即為新的腐蝕中心。當確定4個點通過,澤圍繞4個點畫框,將色塊識別區(qū)域框起來。

2、腐蝕中心算法(如下圖詳解)
一個40/3=13 1313大小的色塊為單位進行識別
每次只讀取這色塊的以y的2/1 為點(也就是這個1313色塊y軸為中心點) x軸向右開始查詢識別顏色 如識別失敗個數(shù)大于6次 則認為這一個1313的色塊無效 跳出循環(huán) 繼續(xù)查詢下一個1313的色塊。

ov7725 stm32,stm32,圖像處理

如果失敗次數(shù)少于6次則改變查詢方向 查詢這色塊的以X/2 為點 對y軸進行查詢方法同上 ,如果y軸有6次失敗則,退出循環(huán)不認同這個色塊合格(因為太小了,失敗次數(shù)又多),但如果少于六次失敗,則認為這個色塊識別成功 并記錄下這個色塊的中心點,這就是腐蝕中心 /。

?

ov7725 stm32,stm32,圖像處理

?

?2、識別代碼

extern u8 Bmp_Minimize_SDRAM[240][40];

static uint8_t ReadColor( uint16_t usX, uint16_t usY)
{
    uint8_t color_value;
    usY=usY/8;
    color_value=Bmp_Minimize_SDRAM[usX][usY];
    usY=usY%8;
    return (color_value>>usY)&0x01;
}

#define IMG_X 0				//圖片x坐標
#define IMG_Y 0             //圖片y坐標
#define IMG_W 240           //圖片寬度
#define IMG_H 320           //圖片高度

#define ALLOW_FAIL_PER 10    //容錯率
#define ITERATER_NUM   8   //迭代次數(shù)

/**
 * @brief  尋找腐蝕中心
 * @param  x :腐蝕中心x坐標
 * @param  y :腐蝕中心y坐標
 * @param  condition :TARGET_CONDITION結(jié)構(gòu)體,存放希望的顏色數(shù)據(jù)閾值
 * @param  area :SEARCH_AREA結(jié)構(gòu)體,查找腐蝕中心的區(qū)域
 * @retval 1:找到了腐蝕中心,x、y為腐蝕中心的坐標;0:沒有找到腐蝕中心。
 */
static int SearchCenter(unsigned short* x, unsigned short* y, const TARGET_CONDITION* condition, SEARCH_AREA* area )
{
	unsigned short i, j, k;
	unsigned short FailCount=0;
	unsigned short SpaceX, SpaceY;
	
	SpaceX = condition->WIDTH_MIN / 3;      //以最小寬度除以3 為 橫向查詢的步進的一個單位
	SpaceY = condition->HEIGHT_MIN / 3;     //以最小高度除以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;      //失敗次數(shù)初始化
			for(k=0; k<SpaceX+SpaceY; k++)
			{
				if(k<SpaceX)    //查詢色塊中間一橫的顏色
                {   
                    if(ReadColor(j+k, i+SpaceY/2)==0)
                    {
                       FailCount++;     //顏色不匹配 失敗計數(shù)+1 
                    }
                }
				else            //查詢色塊中間一豎的顏色     
                {
					if(ReadColor( j+SpaceX/2, i+k-SpaceX)==0)
                    {
                        FailCount++;    //顏色不匹配 失敗計數(shù)+1
                    }
				}
					
				if(FailCount>( (SpaceX+SpaceY) / ALLOW_FAIL_PER ))     //失敗計數(shù)大于 色塊需要查詢的總點數(shù)/容錯率
					break;  //失敗次數(shù)太多 退出
			}
			
			if(k == SpaceX+SpaceY)  //k堅持到查詢完畢,說明基本匹配
			{
                /*記錄該色塊的中心點為腐蝕中心*/
				*x = j + SpaceX / 2;
				*y = i + SpaceY / 2;
				return 1;   //記錄到第一個腐蝕中心后退出函數(shù)
			}
		}	
	}
	return 0;	
}


/**
 * @brief  從腐蝕中心向外腐蝕,得到新的腐蝕中心
 * @param  oldX :先前的腐蝕中心x坐標
 * @param  oldX :先前的腐蝕中心y坐標
 * @param  condition :TARGET_CONDITION結(jié)構(gòu)體,存放希望的顏色數(shù)據(jù)閾值
 * @param  result :RESULT結(jié)構(gòu)體,存放檢測結(jié)果
 * @retval 1:檢測成功;0:檢測失敗。
 */
static int Corrode(unsigned short oldX, unsigned short oldY, const TARGET_CONDITION* condition, RESULT* result )
{
	unsigned short Xmin, Xmax, Ymin, Ymax;
	unsigned short i;
	unsigned short FailCount=0;
	for(i=oldX; i>IMG_X; i--)           //從中心點查到x最左側(cè)
	{
		if(!ReadColor(i, oldY))
			FailCount++;    //不匹配計數(shù)自加1
        if( FailCount> ((condition->WIDTH_MIN)/ALLOW_FAIL_PER) | i<=0)//當識別失敗點大于最小寬度/2是跳出  
			break;
	}
	Xmin=i;     //更新X軸最小坐標值
    
	FailCount=0;    //清空錯誤次數(shù)
	for(i=oldX; i<IMG_X+IMG_W; i++)     //從中心點查到x最右側(cè)
	{
		if(!ReadColor(i, oldY))
			FailCount++;    //不匹配計數(shù)自加1

        if( FailCount> ((condition->WIDTH_MIN)/ALLOW_FAIL_PER) | i>=240)
			break;
	}
	Xmax=i;     //更新X軸最大坐標值

	FailCount=0;    //清空錯誤次數(shù)
	for(i=oldY; i>IMG_Y; i--)           //從中心點查到y(tǒng)最上側(cè)
	{
		if(!ReadColor(oldX, i)) 
			FailCount++;    //不匹配計數(shù)自加1

        if( FailCount> ((condition->HEIGHT_MIN)/ALLOW_FAIL_PER) | i<=0)
			break;
	}
	Ymin=i;     //更新Y軸最小坐標值

	FailCount=0;    //清空錯誤次數(shù)
	for(i=oldY; i<IMG_Y+IMG_H; i++)     //從中心點查到y(tǒng)最下側(cè)
	{
		if(!ReadColor(oldX, i))
			FailCount++;

        if( FailCount> ((condition->HEIGHT_MIN)/ALLOW_FAIL_PER)| i>=320)
			break;
	}
	Ymax=i;     //更新Y軸最大坐標值
	
    FailCount=0;    //清空錯誤次數(shù)

    //獲得腐蝕區(qū)域的中點和xy范圍
    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;   //如果腐蝕后的區(qū)域沒有超過最大限定區(qū)域且沒有小于最小限定區(qū)域 有效?。?
        }
	return 0;
}

/**
 * @brief  用戶將識別條件寫入Condition指向的結(jié)構(gòu)體中,該函數(shù)將返回目標的x,y坐標和長寬
 * @param  condition :TARGET_CONDITION結(jié)構(gòu)體,存放希望的顏色數(shù)據(jù)閾值
 * @param  result :RESULT結(jié)構(gòu)體,存放檢測結(jié)果
 * @retval 1:檢測成功;0:檢測失敗。
 */
int Trace(const TARGET_CONDITION* condition, RESULT* result_final)
{
	unsigned char i;
	static unsigned short x0, y0;
    static unsigned char Flag=0;
	static SEARCH_AREA area = {IMG_X, IMG_X+IMG_W, IMG_Y, IMG_Y+IMG_H};//搜索區(qū)域
	RESULT result;      //RESULT識別結(jié)果
    
    if(Flag==0)     //如果首次使用或上一次腐蝕失敗
    {
        if(SearchCenter(&x0, &y0, condition, &area))    //搜索腐蝕中心并返回給x0,y0,如果成功搜索到,那么flag置1
        {
            Flag = 1;
        }
        else        //如果還沒腐蝕成功,那么把腐蝕區(qū)域再次擴大到整個圖像范圍內(nèi)進行腐蝕
        {
            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置1
            {
                Flag = 1;
                return 1;
            }
            else
            {
				Flag = 0;
				return 0;               
            }
        }      
    }
    
	//找到腐蝕中心 得到中點
	result.x = x0;      //如果flag!=0,說明上一次有腐蝕中心結(jié)果,所以直接使用上一次結(jié)果腐蝕即可,而不需要再次遍歷圖像搜索腐蝕中心
	result.y = y0;      //上一次的腐蝕中心賦值給這次的oldx,oldy
    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;
        
        //更新/返回結(jié)果值
		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,返回失敗值0
    {
        Flag=0;
        return 0;
    }
}

代碼有點多,都有寫注釋哈,就不一一講解了

3、顯示代碼

void GUI_DrawPoint(u16 x,u16 y)
{
    u8 color_value=0x80;
    color_value>>=y%8;
    Bmp_Minimize_SDRAM[x][y/8]|=color_value;
}

void GUI_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
	u16 t; 
	int xerr=0,yerr=0,delta_x,delta_y,distance; 
	int incx,incy,uRow,uCol; 

	delta_x=x2-x1; //計算坐標增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //設置單步方向 
	else if(delta_x==0)incx=0;//垂直線 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平線 
	else{incy=-1;delta_y=-delta_y;} 
	if( delta_x>delta_y)distance=delta_x; //選取基本增量坐標軸 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//畫線輸出 
	{  
		GUI_DrawPoint(uRow,uCol);//畫點 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance) 
		{ 
			xerr-=distance; 
			uRow+=incx; 
		} 
		if(yerr>distance) 
		{ 
			yerr-=distance; 
			uCol+=incy; 
		} 
	}  
} 

void GUI_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
	GUI_DrawLine(x1,y1,x2,y1);
	GUI_DrawLine(x1,y1,x1,y2);
	GUI_DrawLine(x1,y2,x2,y2);
	GUI_DrawLine(x2,y1,x2,y2);
}

在二值化數(shù)據(jù)中畫矩形

if(Trace(&condition0, &result))
{
    for(y_size=0;y_size<240;y_size++)     /*檢測到物體,清空二值化數(shù)據(jù)*/
    {
        for(x_size=0;x_size<40;x_size++)
        {
            Bmp_Minimize_SDRAM[y_size][x_size]=0;
        }
    }
    /*畫矩形,和中心點*/
    GUI_DrawRectangle ( result.x-result.w/2, result.y-result.h/2, result.x+result.w/2, result.y+result.h/2);
    GUI_DrawLine(result.x-10,result.y,result.x+10,result.y);
    GUI_DrawLine(result.x,result.y-10,result.x,result.y+10);
}

識別物體滿足顏色和大小的判斷條件,更新二值化數(shù)組,用矩形框出物體,并標出中心點?

ov7725 stm32,stm32,圖像處理


總結(jié)

第一次寫博客,有諸多不足,望多包涵,后續(xù)會更新多物體識別和圖形識別。

END...

參考文章

stm32 OV7670/攝像頭模塊顏色區(qū)域定位(腐蝕中心算法)_攝像頭模塊顏色識別_閏土小蔣的博客-CSDN博客

識別車牌-識別顏色-基于stm32f4 ov7670(無晶振,無fifo,ov7725,ov2640類似可用)_stm32f4 ov7670顏色識別_qq斯國一的博客-CSDN博客

STM32+ov7725圖像識別(HSL原理)_stm32圖像識別_大桶礦泉水的博客-CSDN博客

《STM32》EasyTrace物體追蹤 源代碼個人注釋+完整例程 - 知乎文章來源地址http://www.zghlxwxcb.cn/news/detail-675524.html

到了這里,關(guān)于STM32 OV7725攝像頭模塊識別顏色物體(1)--HSL二值化和腐蝕中心算法,并用串口輸出數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • FPGA 20個例程篇:19.OV7725攝像頭實時采集送HDMI顯示(三)

    FPGA 20個例程篇:19.OV7725攝像頭實時采集送HDMI顯示(三)

    ? ? ? ?在詳細介紹過OV7725 CMOS Sensor的相關(guān)背景知識和如何初始化其內(nèi)部寄存器達到輸出預期視頻流的目的后,就到了該例程的核心內(nèi)容即把OV7725輸出的視頻流預先緩存到外部DDR3顆粒,接著按照HDMI的視頻格式把DDR3顆粒內(nèi)存儲的一幀一幀圖像數(shù)據(jù)送顯到屏幕上顯示,如圖1所示

    2024年01月17日
    瀏覽(46)
  • 學習筆記之STM32的ov7670攝像頭實驗

    學習筆記之STM32的ov7670攝像頭實驗

    目錄 1. OV7670攝像頭模塊 1.1 OV7670 傳感器內(nèi)置功能模塊 1.2?OV7670模塊的引腳 ?1.3?OV7670的時序圖 1.4?OV7670的分辨率及其計算 2. FIFO模塊 2.1 FIFO的簡介 2.2 FIFO的信號 2.3 常用的FIFO數(shù)據(jù)存儲器 3. BMP編碼?? 3.1 BMP文件的組成 3.2 BMP編碼步驟 4.?攝像頭實驗 4.1 工作流程 4.2 主要函數(shù) 4.3

    2024年02月04日
    瀏覽(22)
  • stm32(SCCB)+ov7670攝像頭輸出圖像程序

    stm32(SCCB)+ov7670攝像頭輸出圖像程序

    一、簡介:?? OV7670一般模塊指低成本數(shù)字輸出CMOS攝像頭,其攝像頭包含30w像素的CMOS圖像感光芯片,3.6mm焦距的鏡頭和鏡頭座,板載CMOS芯片所需要的各種不同電源(電源要求詳見芯片的數(shù)據(jù)文件),板子同時引出控制管腳和數(shù)據(jù)管腳,方便操作和使用。 二、管腳定義 3V3---

    2024年02月13日
    瀏覽(28)
  • 通過stm32cubemx配置DCMI驅(qū)動ov5640攝像頭

    通過stm32cubemx配置DCMI驅(qū)動ov5640攝像頭

    打開stm32cubemx選擇芯片 選擇外部時鐘源 選擇debug方式 配置dcmi ? 打開dma 打開dcmi中斷 選擇合適的io 設置reset、pwdn、scl、sda引腳,注意scl和sda設置為開漏輸出,之前參考別人的設置為推挽輸出,導致一直沒有成功,不知道什么原因 ?配置時鐘 配置項目 最后生成代碼 系統(tǒng)初始化

    2024年02月13日
    瀏覽(20)
  • 【FPGA】攝像頭模塊OV5640

    【FPGA】攝像頭模塊OV5640

    開發(fā)板:正點原子的達芬奇開發(fā)板(或MicroPhase的Z7-Lite 7020開發(fā)板) FPGA型號:XC7A35TFGG484-2(或XC7Z020CLG400-2) Vivado版本:2020.2 參考課程鏈接:正點原子手把手教你學FPGA-基于達芬奇開發(fā)板 A7 OV5640模塊:正點原子ATK-OV5640 ??OV5640是OV(OMNIVISION)公司設計的一款CMOS圖像傳感器,

    2024年03月21日
    瀏覽(30)
  • STM32連接OV2640攝像頭串口方式在PyQt5界面上展示視頻界面 以及使用MQTT方式進行展示

    STM32連接OV2640 視頻源接入到PyQt5界面中 作為AI模型的輸入,視頻流是非常重要的。在本文中,我們將介紹如何將STM32連接到OV2640攝像頭,并將視頻流接入到PyQt5界面中。 硬件連接 首先,我們需要將OV2640攝像頭連接到STM32上。我們可以使用以下連接方式: OV2640 | STM32 ------|------

    2024年02月06日
    瀏覽(25)
  • 33、基于STM32單片機車牌識別系統(tǒng)攝像頭圖像處理系統(tǒng)設計

    33、基于STM32單片機車牌識別系統(tǒng)攝像頭圖像處理系統(tǒng)設計

    畢設幫助、開題指導、技術(shù)解答(有償)見文末。 目錄 摘要 一、硬件方案 二、設計功能 三、實物圖 四、原理圖 五、PCB圖 六、程序源碼 七、資料包括 隨著汽車工業(yè)的迅猛發(fā)展,我國汽車擁有量急劇增加。停車場作為交通設施的組成部分,隨著交通運輸?shù)姆泵筒粩喟l(fā)展,

    2024年02月15日
    瀏覽(32)
  • 76、基于STM32單片機車牌識別攝像頭圖像處理掃描設計(程序+原理圖+PCB源文件+相關(guān)資料+參考PPT+元器件清單等)

    76、基于STM32單片機車牌識別攝像頭圖像處理掃描設計(程序+原理圖+PCB源文件+相關(guān)資料+參考PPT+元器件清單等)

    單片機主芯片選擇方案 方案一:AT89C51是美國ATMEL公司生產(chǎn)的低電壓,高性能CMOS型8位單片機,器件采用ATMEL公司的高密度、非易失性存儲技術(shù)生產(chǎn),兼容標準MCS-51指令系統(tǒng),片內(nèi)置通用8位中央處理器(CPU)和Flash存儲單元,功能強大。其片內(nèi)的4K程序存儲器是FLASH工藝的,這種單

    2024年02月12日
    瀏覽(18)
  • RK3568驅(qū)動OV13850攝像頭模組調(diào)試過程

    RK3568驅(qū)動OV13850攝像頭模組調(diào)試過程

    品牌:Omnivision 型號:CMK-OV13850 接口: MIPI 像素:1320W OV13850彩色圖像傳感器是一款低電壓、高性能1/3.06英寸1320萬像素 CMOS圖像傳感器 ,使用OmniBSI+?技術(shù)提供了單-1320萬像素(4224×3136)攝像頭的功能。通過串行攝像頭控制總線(SCCB)接口的控制,它提供了全幀、下采樣、開窗的

    2023年04月27日
    瀏覽(26)
  • RK3568-android11-適配ov13850攝像頭

    參考鏈接 相關(guān)概念 相關(guān)接口 相關(guān)協(xié)議 圖像格式

    2024年02月09日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包