opencv實現簡單手指位置識別

整體思路:

1.過濾噪聲

2.由於RGB顏色的離散性轉換爲HSV通道

3.對HSV空間進行量化,得到2值圖像,亮的部分爲手的形狀

4.去除雜點造成的僞輪廓,留下手的真實輪廓

5.對凸出點連線

6.最高點到底部中點的連線即爲手指方向

//部分代碼:
將MFC實現部分給省略了,給出了完整的opencv部分代碼,可以參考實現。
int main()
{
    cv::VideoCapture cap(0);
    if (!cap.isOpened())
    {
        return -1;
    }
    //
    cv::Mat frame;
    cv::Mat frameHSV;
    //
    std::vector< std::vector<cv::Point> > OriginalContours;//輪廓
    std::vector< cv::Vec4i > hierarchy; // 輪廓的結構信息
    //
    std::vector< std::vector<cv::Point> > FinalContours;// 篩選後的輪廓
    std::vector< cv::Point > hull;  // 凸包絡的點集
    //
    CString Str;
    int i, j;
    int Width = cap.get(CV_CAP_PROP_FRAME_WIDTH), Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
    float fHeight = ((float)2 / 3 - (float)1 / 7) * Height;
    //
    while (0 == pDlg->m_bStopFlag)
    {
        cap >> frame;
        if (frame.empty())
        {
            break;
        }
        //左右翻轉
        cv::flip(frame, frame, 1);
        //中值濾波,用了這個下面的其他濾波全部異常
        //medianBlur(frame, frame, 10);
        //高斯濾波
        cv::GaussianBlur(frame, frame, cv::Size(7, 7), 1.5, 1.5);
        //通道轉換
        cv::cvtColor(frame, frameHSV, CV_BGR2HSV);
        //imshow("frameHSV", frameHSV);
        /*
        S = 符號整型  U = 無符號整型  F = 浮點型
        E.g.:
        CV_8UC1 是指一個8位無符號整型單通道矩陣,
        CV_32FC2是指一個32位浮點型雙通道矩陣
        CV_8UC1          CV_8SC1          CV_16U C1       CV_16SC1
        CV_8UC2          CV_8SC2          CV_16UC2        CV_16SC2
        CV_8UC3          CV_8SC3          CV_16UC3        CV_16SC3
        CV_8UC4          CV_8SC4          CV_16UC4        CV_16SC4
        CV_32SC1         CV_32FC1         CV_64FC1
        CV_32SC2         CV_32FC2         CV_64FC2
        CV_32SC3         CV_32FC3         CV_64FC3
        CV_32SC4         CV_32FC4         CV_64FC4
        */
        // 對HSV空間進行量化,得到2值圖像,亮的部分爲手的形狀
        cv::Mat mask(frame.rows, frame.cols, CV_8UC1);
        //inRange(frameHSV, cv::Scalar(0, 30, 30), cv::Scalar(40, 170, 256), mask);
        inRange(frameHSV, cv::Scalar(5, 30, 30), cv::Scalar(40, 170, 256), mask);
        //
        // 腐蝕:去除小亮點 膨脹:連接區塊
        cv::erode(mask, mask, cv::Mat(5, 5, CV_8U), cv::Point(-1, -1), 1);
        //cv::dilate(mask, mask, cv::Mat(5, 5, CV_8U), cv::Point(-1, -1), 2);
        //imshow("frameHSV", frameHSV);
        //imshow("mask", mask);
        OriginalContours.clear();
        hierarchy.clear();
        FinalContours.clear();
        // 得到手的輪廓
        cv::findContours(mask, OriginalContours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
        // 去除僞輪廓
        for (i = 0; i < OriginalContours.size(); i++)
        {
            if (fabs(cv::contourArea(cv::Mat(OriginalContours[i]))) > 25000)
            {
                FinalContours.push_back(OriginalContours[i]);
            }
        }
        // 畫輪廓
        cv::drawContours(frame, FinalContours, -1, cv::Scalar(0, 0, 255), 3);
        // 得到輪廓的凸包絡
        int hullcount;
        int iNumOfContours = FinalContours.size();
        cv::Point top;
        for (j = 0; j < iNumOfContours; j++)
        {
            convexHull(cv::Mat(FinalContours[j]), hull, true);
            hullcount = (int)hull.size();
            //
            for (i = 0; i<hullcount - 1; i++)
            {
                cv::line(frame, hull[i + 1], hull[i], cv::Scalar(255, 0, 0), 2, CV_AA);
            }
            cv::line(frame, hull[hullcount - 1], hull[0], cv::Scalar(255, 0, 0), 2, CV_AA);
            //畫點
            GetTopPoint(hull, hullcount, top);
            cv::line(frame, top, top, cv::Scalar(255, 0, 255), 18, CV_AA);
            cv::line(frame, top, cv::Point(Width/2, Height), cv::Scalar(0, 255, 255), 2, CV_AA);
            //
            if (1 == iNumOfContours)
            {
                pDlg->m_FingerPosition.bChanged = 1;
                pDlg->m_FingerPosition.top = ((float)top.y - (float)Height / 7) / fHeight;
                pDlg->m_FingerPosition.left = (float)top.x / (float)Width;
            }
        }
        //
        cv::line(frame, cv::Point(0, Height / 7), cv::Point(Width, Height / 7), cv::Scalar(255, 255, 255), 2, CV_AA);
        cv::line(frame, cv::Point(0, 2 * Height / 3), cv::Point(Width, 2 * Height / 3), cv::Scalar(255, 255, 255), 2, CV_AA);
        imshow("frame", frame);
        cv::waitKey(33);
    }
    return 0;
}

實驗效果圖
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章