opencv 图像识别程序

1.头文件

#pragma once

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
using namespace std;
using namespace cv;

enum DiColor{RED = 0,BLUE = 1};

class ZhuangJia
{
public:
    ZhuangJia();   

    //二值化
    void erZhiHua(const Mat &src, Mat &dst, uchar yz);

    //亮度调整
    void liangDuTiaoZheng(const Mat &src, Mat &dst, double k, double b);

    //寻找目标区域
    vector<RotatedRect> xunZhaoJuXing(const Mat &img);

    //拟合可能区域
    vector<RotatedRect> niHeMuBiao(vector<RotatedRect> vr);

    //寻找最佳目标区域
    RotatedRect xunZhaoZuiJia(vector<RotatedRect> vr);

    //画出目标区域
    void huaChuMuBiao(Mat img, RotatedRect vr);

    //计算距离,返回值越大,距离越大
    int jiSuanjuLi(const Mat &imgroi, int &yuzhi);
public:
    uchar huiDu;
    uchar diColor;//地方颜色标志
    int juLiYuZhi;
    int imgwidth;
    int imgheight;
    int liangDu;
    int jianCeBianChang;
    Mat erZhiTu;
    Mat imgG;//绿色通道图像
    Mat imgD;//敌方颜色通道图像
    Mat imgTemplate;
    Mat imgTemplateSmall;
    bool isFar;

};

2.源文件

#include "zhuangjia.hpp"

#ifndef DEBUG
//#define DEBUG
#endif

ZhuangJia::ZhuangJia()
{
    huiDu = 210;
    diColor = RED;
    imgwidth = 640;
    imgheight = 480;
    juLiYuZhi = 15;
    jianCeBianChang = 2;
    isFar = false;

    //读取模板图片
    Mat img = imread("template.bmp");
    vector<Mat> vimg;
    split(img,vimg);
    threshold(vimg[1],imgTemplate,210,255,THRESH_BINARY);
//    imshow("aa",imgTemplate);
}

void ZhuangJia::erZhiHua(const Mat &src, Mat &dst, uchar yz)
{
    vector<Mat> bgr;
    Mat m;
    //亮度调整
    liangDuTiaoZheng(src,m,1,-120);
    split(m, bgr);
    dst.create(src.size(),CV_8UC1);
    imgG = bgr[1];
    imgD = diColor == RED ? bgr[2] : bgr[0];

    //二值化
    uchar *ptrg = imgG.data, *ptrd = imgD.data, *ptrer = dst.data;
    const uchar *ptrend = imgG.data + imgG.rows*imgG.cols;
    for(; ptrg != ptrend; ptrg++,ptrd++,ptrer++)
    {
        *ptrer = (*ptrd - *ptrg) > yz ? 255 : 0;
    }
//    imshow("huidu",dst);
}

void ZhuangJia::liangDuTiaoZheng(const Mat &src, Mat &dst, double k, double b)
{
    liangDu = b;
    dst.create(src.size(),src.type());
    uchar *ptrsrc = src.data, *ptrdst = dst.data;
    const uchar *ptrend = src.data + src.cols*src.rows *3;
    for(; ptrsrc != ptrend; ptrsrc++, ptrdst++)
    {
        int val =(int)(k * (*ptrsrc) + b);
        if(val < 0)
            val = 0;
        if(val > 255)
        {
            val = 255;
            cout<<val;
        }
        (*ptrdst) = val;
    }
}

vector<RotatedRect> ZhuangJia::xunZhaoJuXing(const Mat &img)
{
    vector<RotatedRect> vr;
    Mat temp,cz;
    vector<vector<Point> > contour;
    bool bflag = false;
    RotatedRect rect;

    Mat ele(5,5,CV_8U,Scalar(1));
    dilate(img,temp,ele);//膨胀
    erode(temp,cz,ele);//腐蚀
//    imshow("cz",cz);

    //查找轮廓
    findContours(cz,contour,RETR_CCOMP , CHAIN_APPROX_SIMPLE);

    //如果轮廓过小,表明装甲距离过远,多做几次闭运算
    int sum = 0,count = 0;
    for(int  i = 0; i < (int)contour.size(); i++){
        if(contour[i].size() > 5){
            sum += contour[i].size();
            count++;
        }
    }
    if(sum / count < 15){
//        cout<<sum / (int)contour.size();
        for(int i = 0; i < 10; i++){
            dilate(cz,temp,ele);//膨胀
            erode(temp,cz,ele);//腐蚀
        }
        findContours(cz,contour,RETR_CCOMP , CHAIN_APPROX_SIMPLE);
        juLiYuZhi = 70;
        jianCeBianChang = 0;
        isFar = true;//距离过远标志
    }else{
        isFar = false;
    }

//    imshow("cz",cz);
//    cout<<contour.size()<<endl;
//    Mat tt = Mat::zeros(cz.rows, cz.cols, CV_8UC3);
//    tt.create(cz.size(),CV_8UC3);
//    drawContours(tt,contour,-1,Scalar(0,0,255));
//    imshow("tt",tt);
//    for(int  i = 0; i < (int)contour.size(); i++){
//        cout<<contour[i].size()<<" ";
//    }

    for(int i = 0; i < (int)contour.size();i++){
//        cout<<contour[i].size()<<endl;
        if(contour[i].size() > 5){
            bflag = true;

            //寻找符合条件的轮廓
            rect = fitEllipse(contour[i]);
//            cout<< rect.center<<" ";
            int rc = rect.center.x, rr = rect.center.y;
            if(rc-1>0 && rc+1<imgwidth && rr-1>0 && rr+1<imgheight){
                for(int ri = -1; ri < jianCeBianChang; ri++){
                    for(int rj = -1; rj < jianCeBianChang; rj++){
//                        cout<<(int)imgD.at<uchar>(rr+ri,rc+rj)<<endl;
                        if(imgD.at<uchar>(rr+ri,rc+rj) < (255+liangDu-juLiYuZhi)){
//                            cout<<(int)imgD.at<uchar>(rr+ri,rc+rj)<<" ";
                            bflag = false;
                            break;
                        }
                    }
                    if(!bflag)
                        break;
                }
                if(bflag){
//                    cout<<endl<<i<<"; ";
                    vr.push_back(rect);
//                    Mat tt;
//                    for(int i = 0; i < vr.size();i++){
//                        tt.create(cz.size(),CV_8UC3);
//                        huaChuMuBiao(tt,rect);
//                        imshow("tt",tt);
//                    }
                    bflag = false;
                }
            }
        }
    }
#ifdef DEBUG
    cout<<"轮廓个数"<<vr.size()<<endl;
#endif
    if(isFar){
        juLiYuZhi = 15;
        jianCeBianChang = 2;
    }
//    cout<<isFar<<endl;
    return vr;
}

vector<RotatedRect> ZhuangJia::niHeMuBiao(vector<RotatedRect> vr)
{
    vector<RotatedRect> vrect;
    RotatedRect rect;
    int nL, nW;
    const double tAngleThre = 15, tSizeThre = 3;
    double dAngle;
    vrect.clear();
    if (vr.size() < 2) //如果检测到的旋转矩形个数小于2,则直接返回
        return vrect;

    //寻找目标
    for (int ni = 0; ni < (int)vr.size() - 1; ni++) //求任意两个旋转矩形的夹角
    {
        for (int nj = ni + 1; nj < (int)vr.size(); nj++)
        {
            dAngle = abs(vr[ni].angle - vr[nj].angle);
            while (dAngle > 180)
                dAngle -= 180;
            //判断这两个旋转矩形是否是一个装甲的两个LED等条
//            cout<<dAngle;
            if ((dAngle < tAngleThre || 180 - dAngle < tAngleThre)
                    && abs(vr[ni].size.height - vr[nj].size.height)
                    < (vr[ni].size.height + vr[nj].size.height) / tSizeThre
                    && abs(vr[ni].size.width - vr[nj].size.width)
                    < (vr[ni].size.width + vr[nj].size.width) / tSizeThre)
            {
//cout<<"here";
                rect.center.x = (vr[ni].center.x + vr[nj].center.x) / 2; //装甲中心的x坐标
                rect.center.y = (vr[ni].center.y + vr[nj].center.y) / 2; //装甲中心的y坐标
                rect.angle = (vr[ni].angle + vr[nj].angle) / 2;   //装甲所在旋转矩形的旋转角度
                if (180 - dAngle < tAngleThre)
                    rect.angle += 90;
                nL = (vr[ni].size.height + vr[nj].size.height) / 2; //装甲的高度
                nW = sqrt((vr[ni].center.x - vr[nj].center.x)
                          * (vr[ni].center.x - vr[nj].center.x)
                          + (vr[ni].center.y - vr[nj].center.y)
                          * (vr[ni].center.y - vr[nj].center.y)); //装甲的宽度等于两侧LED所在旋转矩形中心坐标的距离
//                if (nL < nW)
//                {
                    rect.size.height = nL;
                    rect.size.width = nW;
//                }
//                else
//                {
//                    rect.size.height = nW;
//                    rect.size.width = nL;
//                }
                if(rect.size.width/rect.size.height < 4 && rect.size.width/rect.size.height > 2){
//                    cout<<"宽高比"<<rect.size.width/rect.size.height<<endl;
                    vrect.push_back(rect); //将找出的装甲的旋转矩形保存到vector
                }
            }
        }
    }
#ifdef DEBUG
    cout<<"目标个数"<<vrect.size()<<endl;
#endif
    return vrect;
}

RotatedRect ZhuangJia::xunZhaoZuiJia(vector<RotatedRect> vr)
{
    RotatedRect rect;
    if(vr.size() < 1)
        return rect;
    if(vr.size() == 1){
        rect = vr[0];
        return rect;
    }
    //利用模板寻找最佳目标
    Mat roi;
    int dist = imgTemplate.cols * imgTemplate.rows;
    const double pi = 3.1415926;

    if(imgTemplate.cols < 5 && imgTemplate.rows < 5){
        cout<<"no template"<<endl;
        return rect;
    }

    double dangle, a, l;
    int ic1,ic2,ir1,ir2;

    int yuZhi = isFar ? 70 : 15;

    //模板与目标根据最小距离得到最佳
    for(int i = 0; i < (int)vr.size(); i++){
//        cout<<i<<endl;
        //选出目标区域
        dangle = vr[i].angle;
        while(dangle > 90)
            dangle -= 180;

        a = dangle*pi/180;
        l = vr[i].size.width / (cos(a) * 2);
//        cout<<"yizu"<<vr[i].size.width<<endl<<vr[i].size.height<<endl<<vr[i].angle<<endl;
//        cout<<vr[i].size.width<<endl<<a<<endl<<cos(a)<<endl<<l<<endl<<endl;
        ic1 = vr[i].center.x - l;
        ic2 = vr[i].center.x + l;
        ir1 = vr[i].center.y - vr[i].size.height/4;
        ir2 = vr[i].center.y + vr[i].size.height/4;

        if(ic1 < 0 || ic2 > imgwidth || ir1 < 0 || ir2 > imgheight){
            continue;
        }
        roi = imgG(Range(ir1,ir2),Range(ic1,ic2));
//        imshow("roi",roi);

        //计算距离
        int d = jiSuanjuLi(roi,yuZhi);
        if(dist > d){
            rect = vr[i];
            dist = d;
        }
    }
#ifdef DEBUG
    cout<<"找到最佳"<<endl;
#endif
    return rect;
}

void ZhuangJia::huaChuMuBiao(Mat img, RotatedRect vr)
{
    Point2f pt[4];
    vr.points(pt); //计算二维盒子顶点
    line(img, pt[0], pt[1], CV_RGB(0, 0, 255), 2, 8, 0);
    line(img, pt[1], pt[2], CV_RGB(0, 0, 255), 2, 8, 0);
    line(img, pt[2], pt[3], CV_RGB(0, 0, 255), 2, 8, 0);
    line(img, pt[3], pt[0], CV_RGB(0, 0, 255), 2, 8, 0);
}

int ZhuangJia::jiSuanjuLi(const Mat &imgroi, int &yuzhi)
{
    int dist = 0;
    Mat roi,binary;
    //大小设置为模板大小
    resize(imgroi,roi,Size(imgTemplate.cols,imgTemplate.rows));
    threshold(roi,binary,255-yuzhi+liangDu,255,THRESH_BINARY);
//    imshow("ss",binary);
    uchar *ptrtemp = imgTemplate.data, *ptrb = binary.data;
    const uchar *ptrend = imgTemplate.data + imgTemplate.cols*imgTemplate.rows;
    for(; ptrtemp != ptrend; ptrtemp++,ptrb++){
        //对应点不同距离加1
        dist += *ptrtemp == *ptrb ? 0 : 1;
    }
    return dist;
}

3.main文件

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <iostream>
#include "zhuangjia.hpp"
#include "jiaodujiesuan.hpp"

using namespace std;
using namespace cv;

int main()
{
    Mat img = imread("2.jpg");
//    VideoCapture cap("RedCar.avi");
//    VideoCapture cap("1.avi");
//    Mat img;
//    while(1){
//        cap >> img;
//        imshow("aa",img);
//        imwrite("2.jpg",img);
//        if(waitKey(20));
////            break;
//    }
    Mat imggray;
    ZhuangJia zj;
//    int num = 0;
//    while(1){
//        cap >> img;
        zj.erZhiHua(img,imggray,15);
        //imshow("aa",imggray);
        vector<RotatedRect> vr;
        vr = zj.xunZhaoJuXing(imggray);
        vr = zj.niHeMuBiao(vr);
        //    cout<<vr.size();
//        for(int i = 0; i < vr.size(); i++){
//            zj.huaChuMuBiao(img,vr[i]);
//            cout<<num++;
//        }
        RotatedRect rr;
        JiaoDuJieSuan jdjs;
        float pitch, yaw;
        if(vr.size()>0){
            rr = zj.xunZhaoZuiJia(vr);
//            zj.huaChuMuBiao(img,rr);
            jdjs.huoDeJuXingJiaoDian(rr,img);
            jdjs.qiuJieJiaoDu(pitch,yaw);
            jdjs.drawPoints(img);
            cout<<pitch<<" "<<yaw<<endl;
        }

        imshow("main",img);

//        waitKey(50);
//    }
    waitKey(0);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34359028/article/details/78784972
今日推荐