Opencv(二)形狀識別

識別形狀

有九個圖案和最外面的正方形輪廓,識別出10個輪廓形狀和每個輪廓的重心座標。
這裏寫圖片描述

#include<opencv2/opencv.hpp>
#include<opencv2\legacy\legacy.hpp>
#include<vector>
#include<iostream>
double angle(cv::Point pt1, cv::Point pt2, cv::Point pt0) //求角度
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2) / sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
int main()
{
    cv::Mat srcImg, tempImg,gary,thresh,srcImg1;
    cv::Mat dstImg; 
    int j = 0;
    double s = 0;
    srcImg = cv::imread("90.bmp");
    if (!srcImg.data)
    {
        std::cout << "no img" << std::endl;
        return -1;
    }
    //圖片處理
    resize(srcImg, srcImg, cv::Size(srcImg.cols / 2, srcImg.rows / 2), 0, 0);//縮放
    cvtColor(srcImg, gary, CV_RGB2GRAY);//灰度圖
    medianBlur(gary, gary, 3);//中值濾波
    threshold(gary, thresh, 0, 255, cv::THRESH_OTSU);//二值化
    srcImg1 = thresh.clone();
    dstImg = cv::Mat(srcImg.size(), CV_8UC3, cv::Scalar(255, 255, 255));
    //尋找輪廓
    std::vector<std::vector<cv::Point>>contours;
    findContours(srcImg1, contours, CV_RETR_TREE, CV_CHAIN_APPROX_NONE);
    std::vector<cv::Point>approx;
    //圓
    std::vector<cv::Vec3f>circles;
    HoughCircles(gary, circles, CV_HOUGH_GRADIENT, 1, srcImg.rows / 2, 100, 60, 0, 0);//單通道
    for (size_t i = 0; i < circles.size(); i++)
    {
        cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);
        circle(dstImg, center, radius, cv::Scalar(0, 255, 0), 5, 8, 0);
        circle(dstImg, center, 3, cv::Scalar(0, 255, 0), -1);
        std::cout << "圓心" << i + 1 << center << std::endl;
    }
    //菱形
    std::vector<cv::Point>squares;
    //長方形
    std::vector<cv::Point>changfang;
    //正方形
    std::vector<cv::Point>zhengfang;
    //三角形
    std::vector<cv::Point>sanjiao;
    //五角星
    std::vector<cv::Point>wujiao;
    //五邊形
    std::vector<cv::Point>wubian;
    //十字形
    std::vector<cv::Point>shizi;
    //梅花形
    std::vector<cv::Point>meihua;
    //畫四邊形
    double t;
    for (size_t i = 0; i < contours.size(); i++)
    {
        drawContours(dstImg, contours, i, cv::Scalar(100, 100, 100), 3);
        approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
        if (approx.size() == 4 && fabs(contourArea(cv::Mat(approx))) > 1000 && isContourConvex(cv::Mat(approx)))//4條邊;面積大於1000;凸多邊形
        {
            double minDist = 1e10;
            double d[5];
            double maxCosine = 0.0;
            for (int i = 0; i < 4; i++)//求最小邊
            {

                cv::Point side = approx[i] - approx[(i + 1) % 4];
                double squaredSideLength = side.dot(side);
                d[i] = squaredSideLength;
                minDist = std::min(minDist, squaredSideLength);
            }
            if (minDist<2000)
                continue;
            for (int j = 0; j < 5; j++)
            {
                if (j >= 2)
                {   
                    double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
                    maxCosine = MAX(maxCosine, cosine);
                }
            }
            //std::cout << maxCosine << " ";
            if (maxCosine < 0.1)
            {
                double sh = (d[1] / d[0]);
                if (sh> 0.8&&sh<1.2)
                {
                    for (int i = 0; i<4; i++)
                    zhengfang.push_back(cv::Point(approx[i].x, approx[i].y));
                }
                else
                {
                    for (int i = 0; i<4; i++)
                    changfang.push_back(cv::Point(approx[i].x, approx[i].y));
                }
            }
            else
            {
                for (int i = 0; i<4; i++)
                    squares.push_back(cv::Point(approx[i].x, approx[i].y));
            }
        }
    }
    for (size_t i = 0; i < squares.size(); i += 4)
    {
        cv::Point center;
        center.x = (squares[i].x + squares[i + 2].x) / 2;
        center.y = (squares[i].y + squares[i + 2].y) / 2;
        line(dstImg, squares[i], squares[i + 1], cv::Scalar(0, 0, 255), 4);
        line(dstImg, squares[i + 1], squares[i + 2], cv::Scalar(0, 0, 255), 4);
        line(dstImg, squares[i + 2], squares[i + 3], cv::Scalar(0, 0, 255), 4);
        line(dstImg, squares[i + 3], squares[i], cv::Scalar(0, 0, 255), 4);
        std::cout << "菱形中心" << (i+4)/4 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(0, 0, 255), -1);
    }
    for (size_t i = 0; i < changfang.size(); i += 4)
    {
        cv::Point center;
        center.x = (changfang[i].x + changfang[i + 2].x) / 2;
        center.y = (changfang[i].y + changfang[i + 2].y) / 2;
        line(dstImg, changfang[i], changfang[i + 1], cv::Scalar(0, 0, 80), 4);
        line(dstImg, changfang[i + 1], changfang[i + 2], cv::Scalar(0, 0, 80), 4);
        line(dstImg, changfang[i + 2], changfang[i + 3], cv::Scalar(0, 0, 80), 4);
        line(dstImg, changfang[i + 3], changfang[i], cv::Scalar(0, 0, 80), 4);
        std::cout << "長方形中心" << (i + 4) / 4 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(0, 0, 80), -1);
    }
    for (size_t i = 0; i < zhengfang.size(); i += 4)
    {
        cv::Point center;
        center.x = (zhengfang[i].x + zhengfang[i + 2].x) / 2;
        center.y = (zhengfang[i].y + zhengfang[i + 2].y) / 2;
        line(dstImg, zhengfang[i], zhengfang[i + 1], cv::Scalar(111, 0, 111), 4);
        line(dstImg, zhengfang[i + 1], zhengfang[i + 2], cv::Scalar(111, 0, 111), 4);
        line(dstImg, zhengfang[i + 2], zhengfang[i + 3], cv::Scalar(111, 0, 111), 4);
        line(dstImg, zhengfang[i + 3], zhengfang[i], cv::Scalar(111, 0, 111), 4);
        std::cout << "正方形中心" << (i + 4) / 4 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(111, 0,111), -1);
    }
    //畫三角形
    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.1, true);
        if (approx.size() == 3 && fabs(contourArea(cv::Mat(approx))) > 1000 && isContourConvex(cv::Mat(approx)))//3條邊;面積大於1000;凸多邊形
        {
            double minDist = 1e10;

            for (int i = 0; i < 3; i++)//求最小邊
            {
                cv::Point side = approx[i] - approx[(i + 1) %3];
                double squaredSideLength = side.dot(side);
                minDist = std::min(minDist, squaredSideLength);
            }
            if (minDist<1000)
                continue;
            for (int i = 0; i<3; i++)
                sanjiao.push_back(cv::Point(approx[i].x, approx[i].y));
            drawContours(dstImg, contours, i, cv::Scalar(255, 0, 0), 3);
        }
    }
    for (size_t i = 0; i < sanjiao.size(); i += 3)
    {
        cv::Point center;
        center.x = (sanjiao[i].x + sanjiao[i + 1].x + sanjiao[i + 2].x) / 3;
        center.y = (sanjiao[i].y + sanjiao[i + 1].y + sanjiao[i + 2].y) / 3;
        std::cout << "三角形中心" << (i + 1) % 3 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(255, 0, 0), -1);
    }
    //畫五邊形
    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.03, true);
        if (approx.size() == 5 && fabs(contourArea(cv::Mat(approx))) > 1000 && isContourConvex(cv::Mat(approx)))//5條邊;面積大於1000;凸多邊形
        {
            double minDist = 1e10;
            //std::cout << approx;
            for (int i = 0; i < 5; i++)//求最小邊
            {
                cv::Point side = approx[i] - approx[(i + 1) % 3];
                double squaredSideLength = side.dot(side);
                minDist = std::min(minDist, squaredSideLength);
            }
            if (minDist<1000)
                continue;
            for (int i = 0; i<5; i++)
                wubian.push_back(cv::Point(approx[i].x, approx[i].y));
        }
    }
    for (size_t i = 0; i < wubian.size(); i += 5)
    {
        cv::Point center,center1,center2,center3;
        center1.x = (wubian[i].x + wubian[i + 1].x + wubian[i + 4].x) / 3;
        center1.y = (wubian[i].y + wubian[i + 1].y + wubian[i + 4].y) / 3;
        center2.x = (wubian[i+1].x + wubian[i + 2].x + wubian[i + 3].x) / 3;
        center2.y = (wubian[i+1].y + wubian[i + 2].y + wubian[i + 3].y) / 3;
        center3.x = (wubian[i+3].x + wubian[i + 1].x + wubian[i + 4].x) / 3;
        center3.y = (wubian[i+3].y + wubian[i + 1].y + wubian[i + 4].y) / 3;
        center.x = (center1.x + center2.x + center3.x) / 3;
        center.y = (center1.y + center2.y + center3.y) / 3;
        line(dstImg, wubian[i], wubian[i + 1], cv::Scalar(255, 255, 0), 4);
        line(dstImg, wubian[i+2], wubian[i + 1], cv::Scalar(255, 255, 0), 4);
        line(dstImg, wubian[i+2], wubian[i + 3], cv::Scalar(255, 255, 0), 4);
        line(dstImg, wubian[i+3], wubian[i + 4], cv::Scalar(255, 255, 0), 4);
        line(dstImg, wubian[i], wubian[i +4], cv::Scalar(255, 255, 0), 4);
        std::cout << "五邊形中心" << (i + 1) % 5 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(255, 255, 0), -1);
    }
    //畫五角星
    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
        if (approx.size() == 10 && fabs(contourArea(cv::Mat(approx))) > 1000 )//10條邊;面積大於1000;凹多邊形
        {
            if (isContourConvex(cv::Mat(approx)))
                continue;
            double minDist = 1e10;

            for (int i = 0; i <10; i++)//求最小邊
            {
                cv::Point side = approx[i] - approx[(i + 1) % 10];
                double squaredSideLength = side.dot(side);
                minDist = std::min(minDist, squaredSideLength);
            }
            if (minDist<1000)
                continue;
            for (int i = 0; i<10; i++)
                wujiao.push_back(cv::Point(approx[i].x, approx[i].y));
        }
    }
    for (size_t i = 0; i < wujiao.size(); i += 10)
    {
        cv::Point center;
        double y1, y2, x1,x2,y3,y4,x3,x4;
        y1 = wujiao[i].y;
        y2 = wujiao[i+5].y;
        x1 = wujiao[i].x;
        x2 = wujiao[i+5].x;
        double k1, k2, b1, b2;
        k1 = (y1 - y2) / (x1- x2);
        b1 =y1 - k1*y1;
        y3 = wujiao[i+1].y;
        y4 = wujiao[i + 6].y;
        x3 = wujiao[i+1].x;
        x4 = wujiao[i + 6].x;
        k2 = (y3 - y4) / (x3 - x4);
        b2 = y3 - k2*x3;
        center.x = (b1 - b2) / (k2 - k1);
        center.y = k1*center.x + b1;
        for (size_t j = 0; j < 10; j++)
        {
            line(dstImg, wujiao[j], wujiao[(j + 1) % 10], cv::Scalar(0,255, 255), 4);
        }
        std::cout << "五角形中心" << (i + 1) % 5 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(0, 255, 255), -1);
    }
    //畫十字形
    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.02, true);
        if (approx.size() == 12 && fabs(contourArea(cv::Mat(approx))) > 1000 )//12條邊;面積大於1000;凹多邊形
        {
            if (isContourConvex(cv::Mat(approx)))
                continue;
            double minDist = 1e10;
            for (int i = 0; i < 12; i++)//求最小邊
            {
                cv::Point side = approx[i] - approx[(i + 1) % 12];
                double squaredSideLength = side.dot(side);
                minDist = std::min(minDist, squaredSideLength);
            }
            if (minDist<1000)
                continue;
            for (int i = 0; i<12; i++)
                shizi.push_back(cv::Point(approx[i].x, approx[i].y));
        }
    }
    for (size_t i = 0; i < shizi.size(); i += 12)
    {

        cv::Point center;
        center.x = (shizi[i].x+shizi[i+6].x) /2;
        center.y = (shizi[i].y + shizi[i + 6].y) / 2;
        for (size_t j = 0; j < 12; j++)
        {
            line(dstImg, shizi[j],shizi[(j + 1) % 12], cv::Scalar(122, 122, 0), 4);
        }
        std::cout << "十字形中心" << (i + 1) % 12 << center << std::endl;
        circle(dstImg, center, 3, cv::Scalar(122, 122, 0), -1);
    }
    //畫梅花形
    for (size_t i = 0; i < contours.size(); i++)
    {
        approxPolyDP(contours[i], approx, arcLength(cv::Mat(contours[i]), true)*0.01, true);
        if (approx.size()>10 && fabs(contourArea(cv::Mat(approx))) > 1000)//12條邊;面積大於1000;凹多邊形
        {
            if (isContourConvex(cv::Mat(approx)))
                continue;
            double perimeter = arcLength(contours[i], true);
            cv::Point center;
            cv::Rect rect = boundingRect(contours[i]);
            double r = (rect.width + rect.height) / 8;
            double area = contourArea(contours[i]);
            double pi = 3.1415926;
            double areajisuan = 2 * pi*r*r + r*r * 4;
            double perimeterji = 4 * pi*r;
            double perimeterDiff = abs((perimeterji - perimeter) * 2 / (perimeter + perimeterji)) * 100;
            double  areaDiff = abs((area - areajisuan) * 2 / (area + areajisuan)) * 100;
            //std::cout << areaDiff << std::endl;
            //std::cout << " " << perimeterDiff << std::endl;

            if (areaDiff < 8 && perimeterDiff<11)
            {
                //std::cout << areaDiff << std::endl;
                //std::cout << "1 " << perimeterDiff << std::endl;

                center.x = rect.x + 2 * r;
                center.y = rect.y + 2 * r;
                drawContours(dstImg, contours, i, cv::Scalar(0, 122, 122), 3);
                std::cout << "梅花形中心" << ++j << center << std::endl;
                circle(dstImg, center, 3, cv::Scalar(0, 122, 122), -1);
            }
        }
    }
    imshow("1",dstImg);
    cv::waitKey(0);
    return 0;

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