基于OPENCV的樹莓派按鍵自校正閾值的顏色識別
前言:通過在選定區(qū)域內(nèi)進(jìn)行色彩的HSV參數(shù)識別,可利用按鍵進(jìn)行自動的顏色識別的閾值選定,進(jìn)而通過圖形矩的計(jì)算得到目標(biāo)圖形的中心點(diǎn)坐標(biāo)。
本人才疏學(xué)淺,還請多多指正,如有更好想法可通過郵箱hanckh@foxmail.com進(jìn)行交流.
原理:
在OPENCV中圖像的顏色識別一般是基于inRange()
函數(shù)進(jìn)行目標(biāo)閾值的限定,通過將圖像轉(zhuǎn)換為二值化圖像犯犁,從而進(jìn)行目標(biāo)物體的識別和追蹤。inRange()
函數(shù)中的參數(shù)是由HSV三個(gè)色彩參數(shù)決定钠乏,因此為了能自動的選定識別閾值栖秕,就必須要知道目標(biāo)的色彩參數(shù)范圍。通過對目標(biāo)物體所處的ROI區(qū)域的HSV三層顏色直方圖的分析晓避,可得到當(dāng)前目標(biāo)的HSV參數(shù)簇捍,并通過人為選擇的顏色拓展范圍,再通過對該HSV參數(shù)進(jìn)行記錄俏拱,即可實(shí)現(xiàn)對目標(biāo)的動態(tài)識別暑塑。
之后再通過目標(biāo)物體二值化圖像的邊緣檢測,對圖像矩進(jìn)行計(jì)算得到目標(biāo)圖像的中心點(diǎn)锅必。
使用步驟
- 將識別物體放入ROI區(qū)域事格,在示例代碼里表現(xiàn)為中心藍(lán)點(diǎn)。
- 再按對應(yīng)按鍵搞隐,進(jìn)行參數(shù)的確認(rèn)驹愚。
- 再按對應(yīng)模式按鍵,進(jìn)行識別模式的切換劣纲,進(jìn)入動態(tài)識別模式
示例代碼
/*
MIT License
Copyright (c) [2019] [HAN]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <wiringPi.h>
#include <wiringSerial.h>
using namespace cv;
using namespace std;
int H,S,V;
int max_value=0;
int flag=0,Step=1,affirm=0;
int fd;
Mat srcimageHSV;
class object
{
public:
int H,S,V;
Mat Mask;
Mat srcimageHSV;
Mat Origin_image;
void get_minmax(){
//*****人工設(shè)定HSV參數(shù)擴(kuò)展范圍******//
H_max=H+10;
S_max=S+75;
V_max=V+80;
H_min=H-10;
S_min=S-75;
V_min=V-80;
//********************************//
if(H_max>255){
H_max=255;
}
if(S_max>255){
S_max=255;
}
if(V_max>255){
V_max=255;
}
if(H_min<0){
H_min=0;
}
if(S_min<0){
S_min=0;
}
if(V_min<0){
V_min=0;
}
}
void tobe_threhold(){//進(jìn)行二值化
inRange(srcimageHSV,Scalar(H_min,S_min,V_min),Scalar(H_max,S_max,V_max),Mask);
}
void show_image(){
imshow("Object_Mask",Mask);
}
void Get_TrackBar(){//回顯識別出的HSV參數(shù)
namedWindow("Object", 1);
createTrackbar("H_min","Object",&H_min,255);
createTrackbar("S_min","Object",&S_min,255);
createTrackbar("V_min","Object",&V_min,255);
createTrackbar("H_max","Object",&H_max,255);
createTrackbar("S_max","Object",&S_max,255);
createTrackbar("V_max","Object",&V_max,255);
}
void calculate_Point(){//計(jì)算中心點(diǎn)
vector<vector<Point>> Object;
findContours(Mask,Object,CV_RETR_EXTERNAL,CV_RETR_TREE);
double maxArea = 0;//Find maxArea
vector<Point> maxContours;
for(uint i = 0 ; i < Object.size(); i++){
double area = contourArea(Object[i]);
if(area > maxArea){
maxArea = area;
maxContours = Object[i];
}
}
if(maxContours.size()>0){
vector<Moments> mu(maxContours.size());//計(jì)算圖形矩
for (uint i = 0; i < maxContours.size(); i++)
{
mu[i] = moments(maxContours, false);
}
vector<Point2f> circle_center(maxContours.size());
for (uint i = 0; i < maxContours.size(); i++)
{
circle_center[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
// vector<Moments> mu(Object.size());
// for (uint i = 0; i < Object.size(); i++)
// {
// mu[i] = moments(Object[i], false);
// }
// vector<Point2f> circle_center(Object.size());
// for (uint i = 0; i < Object.size(); i++)
// {
// circle_center[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
// }
for (uint i = 0; i < Object.size(); i++)//畫出中心點(diǎn)
{
circle(Origin_image,circle_center[i],4,Scalar(255,100,255),-1,8,0);
}
}
}
void show_Point(){
imshow("Result",Origin_image);
}
private:
int H_min,S_min,V_min;
int H_max,S_max,V_max;
};
object red;
int main(){
//------------GPIO-----------//
//在此示例中GPIO3為確認(rèn)鍵逢捺,GPIO0為切換識別參數(shù)鍵,GPIO2為返回捕捉HSV參數(shù)模式鍵
if(wiringPiSetup()==-1){
return -1;
}
pinMode(0,INPUT);
pinMode(2,INPUT);
pinMode(3,INPUT);
//---------------------------//
Mat srcimage;
VideoCapture capture(0);
while(1){
if(digitalRead(3)==HIGH){ //識別按鍵
affirm=1;
}
if(digitalRead(0)==HIGH&&affirm==1){
Step=Step+1;
// printf("affirm:%d",affirm);
// printf("Step:%d\n",Step);
affirm=0;
}
if(digitalRead(2)==HIGH&&affirm==1){
if(flag==1){
flag=0;
}else{
flag=1;
}
affirm=0;
};
capture >> srcimage;
resize(srcimage,srcimage,Size(255,255));
cvtColor(srcimage, srcimageHSV, COLOR_BGR2HSV);
if(flag==0){ //HSV參數(shù)識別模式
// printf("%d\n",flag);
Mat imageROI=srcimageHSV(Rect(128,128,5,5));//ROI區(qū)域的設(shè)定
int histsize[] = { 256 };
float midranges[] = { 0,255 };
const float *ranges[] = { midranges };
MatND dsthist;
//*******進(jìn)行HSV三層直方圖的繪制*********//
int channels = 0;
calcHist(&imageROI, 1, &channels, Mat(), dsthist, 1, histsize, ranges, true, false);
double g_dhistmaxvalue;
minMaxLoc(dsthist, 0, &g_dhistmaxvalue, 0, 0);
for (int i = 0;i < 256;i++) {
int value = cvRound(256 * 0.9 *(dsthist.at<float>(i) / g_dhistmaxvalue));
if(value>max_value){
max_value=value;
H=i;
}
}
max_value=0;
channels = 1;
calcHist(&imageROI, 1, &channels, Mat(), dsthist, 1, histsize, ranges, true, false);
for (int i = 0;i < 256;i++) {
int value = cvRound(256 * 0.9 *(dsthist.at<float>(i) / g_dhistmaxvalue));
if(value>max_value){
max_value=value;
S=i;
}
}
max_value=0;
channels = 2;
calcHist(&imageROI, 1, &channels, Mat(), dsthist, 1, histsize, ranges, true, false);
for (int i = 0;i < 256;i++) {
int value = cvRound(256 * 0.9 *(dsthist.at<float>(i) / g_dhistmaxvalue));
if(value>max_value){
max_value=value;
V=i;
}
}
max_value=0;
//*********************************//
switch(Step){
case 1:
red.H=H;
red.S=S;
red.V=V;
red.srcimageHSV=srcimageHSV;
red.get_minmax();
red.tobe_threhold();
// red.show_image();
break;
}
rectangle(srcimage,Point(128,128),Point(134,134),Scalar(255,0,0),-1); //框出ROI區(qū)域范圍
}
if(flag==1){ //動態(tài)目標(biāo)識別模式
// printf("%d\n",flag);
red.tobe_threhold();
imshow("red",red.Mask);
red.Origin_image=srcimage;
red.calculate_Point();
// red.show_Point();
// red.Put_message();
}
imshow("origin", srcimage);
if(waitKey(10)==27){
break;
}
}
return 0;
}