OPENCV实现色带检测
今天在家無聊,終于有時(shí)間寫下我的第一篇CSDN博客啦,前段時(shí)間幫一個(gè)老師做一個(gè)項(xiàng)目,用攝像頭檢測(cè)地上的色帶,輸出角度幫助機(jī)器人尋跡。就想到用opencv來做,可以我不會(huì)啊,怎么辦?看唄。這里對(duì)opencv點(diǎn)個(gè)贊!函數(shù)通俗易懂,環(huán)境配置也比較簡(jiǎn)單,英語(yǔ)閱讀能力好的人都不用買書的,看文檔就可以用得飛起啊~~
看了幾天就把程序?qū)懞昧?#xff0c;用得不好大家不喜勿碰,思路如下:
程序如下:
// camera.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//
#include "stdafx.h"
#include<iostream> ?
#include <opencv2/opencv.hpp> ?
#include <opencv2/core/core.hpp> ?
#include <opencv2/highgui/highgui.hpp> ?
#include "stdio.h"
#include "findtape.h"
using namespace cv;
using namespace std;
int minVotenum=50;
int _tmain(int argc, _TCHAR* argv[])
{
VideoCapture cap0(0);//打開一個(gè)攝像頭 ?
VideoCapture cap1(1);//打開一個(gè)攝像頭 筆記本必須要兩個(gè),否則打不開外置攝像頭
vector<Vec4i> lines,resultlines;//存儲(chǔ)視頻中直線的起點(diǎn)和終點(diǎn)
Mat source_frame,source_frame1,gray_frame;//新建兩幀圖像?
int frame_width,frame_height;
namedWindow("視頻",WINDOW_AUTOSIZE);//新建一個(gè)圖像窗口
? ? if(!cap0.isOpened()) //判斷是否打開?
? ? { ?
cerr<<"Can not open a camera or file."<<endl;
? ? ? ? return -1; ?
? ? }
//獲取視頻的寬和高
frame_height=(int)cap0.get(CV_CAP_PROP_FRAME_HEIGHT);
frame_width=(int)cap0.get(CV_CAP_PROP_FRAME_WIDTH);
? ??
//namedWindow("灰度視頻",WINDOW_AUTOSIZE);//新建一個(gè)圖像窗口
? ? bool stop = false; ?
? ? while(!stop) ?
? ? { ?
? ? ? ? cap0>>source_frame;//從視頻一副圖片?
cap1>>source_frame1;//從視頻一副圖片 ?這句沒用的,為了打開外置攝像頭而已
cvtColor(source_frame, gray_frame, CV_BGR2GRAY);//轉(zhuǎn)換成灰度圖像 ?
? ? ? ? GaussianBlur(gray_frame, gray_frame, Size(7,7), 1.5, 1.5,BORDER_DEFAULT); //高斯濾波?
Canny(gray_frame, gray_frame, 50, 150, 3); //邊緣檢測(cè) 內(nèi)部用到sobel計(jì)算梯度 可以調(diào)整閾值 想想怎么弄成自動(dòng)閾值
//Hough變換
//檢測(cè)直線,最小投票為50,線條不短于50,間隙不小于20
HoughLinesP( gray_frame, lines,1,CV_PI/360,minVotenum,50,20);
//找出目標(biāo)直線 并計(jì)算角度 距離
if(findColoredTape(lines,resultlines))
{
drawDetectLines(source_frame,resultlines,Scalar(0,0,255));//畫線
if((lines.size()>10)&&(minVotenum<200))
{
minVotenum++;
}
}
else
{
if(minVotenum>20)
{
minVotenum--;
}
//drawDetectLines(source_frame,lines,Scalar(0,255,0));//畫線
}
display_information(source_frame,frame_width,frame_height, lines.size(),countAngel(resultlines),countLocation(resultlines));
? ? ? ? imshow("視頻",source_frame);
//imshow("灰度視頻",gray_frame);?
? ? ? ? if(waitKey(30) >=0) ?
? ? ? ? ? ? stop = true; ?
? ? } ?
return 0;
}
findtape.h
#ifndef _FINDTAPE_H
#define _FINDTAPE_H
?
#include <opencv2/core/core.hpp> ?
using namespace cv;
using namespace std;
void drawDetectLines(Mat& image,const vector<Vec4i>& lines,Scalar & color);//畫線
float countAngel(vector<Vec4i>& resultlines);
Point countLocation(vector<Vec4i>& resultlines);
uchar findColoredTape(vector<Vec4i>& sourcelines,vector<Vec4i>& resultlines);
void display_information(Mat Frame,int width,int height,int linesnum,float angle,Point location);//在視頻里顯示信息
#endif
findtape.cpp
#include "stdafx.h"
#include "findtape.h"
#include<iostream> ?
#include <opencv2/opencv.hpp> ?
#include <opencv2/core/core.hpp> ?
#include <opencv2/highgui/highgui.hpp> ?
#include "stdio.h"
#include "math.h"
double ParallelThreshold=0.2;//平行閾值,小于這個(gè)值認(rèn)為是平行 0-1 越小要求越高
double intersectThreshold=0.3;//相交閾值,大于這個(gè)值認(rèn)為是相交 0-1 越大要求越高
//畫直線,將目標(biāo)的兩條直線用紅色。其余用綠色
void drawDetectLines( Mat& image,const vector<Vec4i>& lines,Scalar & color)
{
? ??
// 將檢測(cè)到的直線在圖上畫出來
vector<Vec4i>::const_iterator it=lines.begin();
while(it!=lines.end())
{
Point pt1((*it)[0],(*it)[1]);
Point pt2((*it)[2],(*it)[3]);
line(image,pt1,pt2,color,2);?
// ?線條寬度設(shè)置為2
++it;
}
}
//比較兩條直線的長(zhǎng)度
bool compareLine(Vec4i line1,Vec4i line2)
{
long int length1,length2;
length1= (line1[0]-line1[2])*(line1[0]-line1[2])+(line1[1]-line1[3])*(line1[1]-line1[3]);
length2= (line2[0]-line2[2])*(line2[0]-line2[2])+(line2[1]-line2[3])*(line2[1]-line2[3]);
if(length1>length2)
return 1;
else
return 0;
}
//判斷兩條直線是否平行
bool judgeParallel(Vec4i line1,Vec4i line2)
{
double slope1,slope2,slope3;//斜率
slope1=abs(line1[0]-line1[2]) / (abs(line1[1]-line1[3])+1);//兩條直線的斜率
slope2=abs(line2[0]-line2[2]) / (abs(line2[1]-line2[3])+1);
slope3=abs(line1[0]-line2[0]) / (abs(line1[1]-line2[1])+1);//第一條直線的第一個(gè)點(diǎn)和第二條直線的第一個(gè)點(diǎn),判斷是否在延長(zhǎng)線上
if((abs(slope1-slope2)<ParallelThreshold)&&(abs(slope1-slope3)>intersectThreshold))//這兩個(gè)閾值可以改變
{
return 1;
}
else
{
return 0;
}
}
//找出色帶
uchar findColoredTape(vector<Vec4i>& sourcelines,vector<Vec4i>& resultlines)
{
Vec4i temp;
int compare_lines;//進(jìn)行比較的線的條數(shù)
//進(jìn)行比較的直線數(shù) 最多為 compare_lines條
if(sourcelines.size()>=2)
{
compare_lines=sourcelines.size();
}
else
{
return 0;
}
//冒泡排序
//將所有直線按長(zhǎng)度排序
for(int i=0;i<compare_lines-1;++i)
{
for(int j=i+1;j<compare_lines;++j)
{
//判斷長(zhǎng)度
if(compareLine(sourcelines[j],sourcelines[i])==1)
{
//容器類型的賦值
temp=sourcelines[i];
sourcelines[i] = sourcelines[j];
sourcelines[j]=temp;
}
}
}
//若檢測(cè)到的直線數(shù)大于等于2,則取長(zhǎng)度最長(zhǎng)的compare_lines條兩兩進(jìn)行匹配
//找出最接近平行,不是延長(zhǎng)線,總長(zhǎng)度最長(zhǎng)的兩條直線
for(int i=0;i<compare_lines-1;++i)
{
for(int j=i+1;j<compare_lines;++j)
{
if(judgeParallel(sourcelines[i],sourcelines[j]))
{
resultlines.clear();
resultlines.push_back(sourcelines[i]);
resultlines.push_back(sourcelines[j]);
return 1;
}
}
}
return 0;
}
float countAngel(vector<Vec4i>& resultlines)
{
float angle;
if(resultlines.size()==2)
{
Vec4i line;
float x,y;
line[0]=(resultlines[0][0]+resultlines[1][0])/2;
line[1]=(resultlines[0][1]+resultlines[1][1])/2;
line[2]=(resultlines[0][2]+resultlines[1][2])/2;
line[3]=(resultlines[0][3]+resultlines[1][3])/2;
x=line[0]-line[2];
y=line[1]-line[3];
angle=atan2f(y,x)*180/CV_PI-90;
if(angle<-180)
{
angle+=180;
}
else if(angle>180)
{
angle-=180;
}
return angle;
}
else
{
return 0;
}
}
//計(jì)算位置
Point countLocation(vector<Vec4i>& resultlines)
{
Point location;
if(resultlines.size()==2)
{
location.x=(resultlines[0][0]+resultlines[0][2]+resultlines[1][0]+resultlines[1][2])/4;
location.y=(resultlines[0][1]+resultlines[0][3]+resultlines[1][1]+resultlines[1][3])/4;
return location;
}
else
{
location.x=0;
location.y=0;
return location;
}
}
//在視頻里顯示信息
void display_information(Mat Frame,int width,int height,int linesnum,float angle,Point location)
{
? ? char strFrameSize[30],strLineNum[20],Angle[20];
//顯示直線 信息
sprintf_s(strLineNum, "strLineNum: %0d",linesnum);
putText(Frame,strLineNum,Point(0,20),2,1,CV_RGB(25,200,25));
sprintf_s(Angle, "Angle: %.2f ",angle);
? ? putText(Frame,Angle,Point(0,50),2,1,CV_RGB(25,200,25));
if(location.x>width/2)
{
putText(Frame,"Right",Point(0,80),2,1,CV_RGB(25,200,25));
}
else
{
putText(Frame,"left",Point(0,80),2,1,CV_RGB(25,200,25));
}
}
效果如下:
檢測(cè)的效果還可以,不足有以下幾個(gè):
1.沒有進(jìn)行顏色檢測(cè),所以遇到多條平行線的時(shí)候會(huì)檢測(cè)錯(cuò)誤
2.雖然閾值選擇會(huì)自動(dòng)改變,但是有時(shí)候還是會(huì)檢測(cè)不出邊緣
3. 對(duì)光線要求較強(qiáng),在房間里比較暗效果不好
總結(jié)
以上是生活随笔為你收集整理的OPENCV实现色带检测的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于我了解5G后对5G的认识
- 下一篇: 自动化控制行业常见面试问题分析