基于OPENCV的樹莓派按鍵自校正閾值的顏色識別

基于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)锅必。

使用步驟

  1. 將識別物體放入ROI區(qū)域事格,在示例代碼里表現(xiàn)為中心藍(lán)點(diǎn)。
  2. 再按對應(yīng)按鍵搞隐,進(jìn)行參數(shù)的確認(rèn)驹愚。
  3. 再按對應(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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末癞季,一起剝皮案震驚了整個(gè)濱河市劫瞳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绷柒,老刑警劉巖志于,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異废睦,居然都是意外死亡伺绽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來憔恳,“玉大人瓤荔,你說我怎么就攤上這事净蚤≡孔椋” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵今瀑,是天一觀的道長程梦。 經(jīng)常有香客問我,道長橘荠,這世上最難降的妖魔是什么屿附? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮哥童,結(jié)果婚禮上挺份,老公的妹妹穿的比我還像新娘。我一直安慰自己贮懈,他們只是感情好匀泊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著朵你,像睡著了一般各聘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抡医,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天躲因,我揣著相機(jī)與錄音,去河邊找鬼忌傻。 笑死大脉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的水孩。 我是一名探鬼主播镰矿,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼荷愕!你這毒婦竟也來了衡怀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤安疗,失蹤者是張志新(化名)和其女友劉穎抛杨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荐类,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怖现,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屈嗤。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡潘拨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饶号,到底是詐尸還是另有隱情铁追,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布茫船,位于F島的核電站琅束,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏算谈。R本人自食惡果不足惜涩禀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望然眼。 院中可真熱鬧艾船,春花似錦、人聲如沸高每。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽觉义。三九已至雁社,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晒骇,已是汗流浹背霉撵。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洪囤,地道東北人徒坡。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像瘤缩,于是被迫代替她去往敵國和親喇完。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345