YU

#include<opencv2/opencv.hpp>
#include<iostream>
#include <thread>
//#include "Serial.hpp"
#define USESERPORT
#define DEVICE "/dev/ttyUSB0" 
#define FIRSPEED 31.0//子弹速度33m/s最好
#define DISTANCE 7//距离

#define h0 1.4//车与大R相对高度差

using namespace cv;
using namespace std;

const int color = 0;//0红   1蓝
const int type = 0;//0小符前两位+大符后两位   1大符(不用改,勿动)
const int shizhen = 1;//0顺时针   1逆时针
double rot_speed = 10.0;//风车转速
double PI = 3.1415926535;
double fcradius; //扇叶半径(定义的全局变量)
Point pROI;//扇叶上大装甲重心
Point fcp;//风车中心点符
Point2f pre_beat_center;//大符预测点
double Y, P, xuanwu, Y_big, P_big;
double seita;

double dx;//dx单位mm/pi、像素与实际坐标的转换、距离一定的情况下是一个定值
double ox;//图像坐标系\单位m、ox、oy
double oy;
double ox_big, oy_big;//大符时图像坐标系

double buff[4] = { 0,0,0,0 };
int fd = -1;


//void send()
//{
//  while (1)
//  {
//      sendXYZ(fd, buff);
//      cout << buff[0] << "***" << buff[1] << "***" << buff[2] << "***" << buff[3] << endl;
//      usleep(__useconds_t(1e6 / 50)); /** 1e6/100 每秒100次*/
//  }
//}


void armor_dete(const char *cap_id)
{
//#ifdef USESERPORT
//  fd = openPort(DEVICE);
//  if (fd != -1)
//  {
//      configurePort(fd);
//      printf("open port /dev/ttyUSB0 done.\n");
//  }
//  else
//      printf("open_port fail: Unable to open port. \n");
//#endif

    cout << "图形处理线程即将开始" << endl;
    //摄像头读取视频
    VideoCapture capture;
    capture = VideoCapture(CV_CAP_DSHOW);
    //capture.open(1);
    capture.open("E:\\vsproject\\Project2\\Project2\\a2.mp4");
    capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    Mat frame;
    if (!capture.isOpened())

    {

        cout << "Cannot open the  cam" << endl;

        //return -1;

    }



    while (true)
    {
        capture >> frame;
        //circle(frame, Point(320, 240), 15, Scalar(0, 0, 255), 1, 8);//画出(320,240)点*************************************
        if (!frame.data)
        {
            break;
        }

        Mat imgHSV;
        medianBlur(frame, frame, 7);

        cvtColor(frame, imgHSV, COLOR_BGR2HSV);//rgb转为HSV


        Mat imgdst, imgdst1, imgdst2, imgdst3, imgdst4, imgdst5;
        if (color == 0)
        {
            //红色装甲版
            inRange(imgHSV, Scalar(0, 96, 46), Scalar(6, 255, 255), imgdst1);
            inRange(imgHSV, Scalar(174, 96, 46), Scalar(180, 255, 255), imgdst2);
            imgdst = imgdst1 | imgdst2;
            //imshow("hsv红色", imgdst);//******************
        }
        else if (color == 1)
        {
            //蓝色装甲版
            inRange(imgHSV, Scalar(100, 43, 46), Scalar(124, 255, 255), imgdst1);//蓝色100.124   青色78.99   可能会掺杂灰色饱和度s
            inRange(imgHSV, Scalar(78, 43, 46), Scalar(99, 255, 255), imgdst2);
            inRange(imgHSV, Scalar(35, 43, 46), Scalar(77, 255, 255), imgdst3);
            imgdst = imgdst1 | imgdst2 | imgdst3;
            //imshow("hsv蓝色", imgdst);//******************
        }

        Mat element1 = getStructuringElement(MORPH_RECT, Size(3, 3));
        Mat element = getStructuringElement(MORPH_RECT, Size(2, 2));

        //进行滤波操作
        dilate(imgdst, imgdst, element);
        erode(imgdst, imgdst, element);
    
        

        //******开始找ROI******
        vector<vector<Point>> contours;
        vector<Vec4i>hierarchy;

        Mat threshold_output;
        threshold(imgdst, threshold_output, 50, 255, THRESH_BINARY);

        findContours(threshold_output, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));

        vector<vector<Point> > contours_poly(contours.size());//******
        vector<Rect> boundRect(contours.size());//******

        Mat drawing = Mat::zeros(imgdst.size(), CV_8UC3);


        bool one = true;
        bool two = true;
        bool three = true;
        int zdy = 0;

        vector<Moments> mu(contours.size());
        for (int i = 0; i < contours.size(); i++)
        {
            //计算轮廓的面积
            double Area = contourArea(contours[i]);
            
            //找击打点(pROI.x,pROI.y)
            if (Area > 1000 && Area < 16560)
            {
                if (one)
                {
                    zdy++;
                    one = false;
                }


                drawContours(drawing, contours, i, Scalar(0, 0, 255), 2);
                


                //包围矩形
                approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//******
                boundRect[i] = boundingRect(Mat(contours[i]));//******
                rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), Scalar(0, 255, 0), 2, 8, 0);//******


                //******最小包围圆******
                Point2f center;//变量圆心坐标
                float radius = 0;//初始化扇叶最小包围圆半径
                minEnclosingCircle(contours[i], center, radius);//寻找最小包围圆
                circle(drawing, center, cvRound(radius), Scalar(0, 255, 0), 1, 8);//绘制最小包围圆,cvRound对半径进行四舍五入
                circle(drawing, center, 1, Scalar(0, 255, 0), 3, 8);//圆心
                double mianji = 3.14*radius*radius;//最小包围圆面积
                
                double bizhi = mianji / Area;//模拟6.0左右   官方4.2
                



                //最小包围矩形
                RotatedRect minRect = minAreaRect(Mat(contours[i]));
                Point2f vertex[4];//用于存放最小矩形的四个顶点
                minRect.points(vertex);//返回矩形的四个顶点给vertex
                //绘制最小面积包围矩形
                vector<Point>min_rectangle;
                for (int i = 0; i < 4; i++)
                {
                    line(drawing, vertex[i], vertex[(i + 1) % 4], Scalar(255, 0, 0), 1, 8);//非常巧妙的表达式
                    min_rectangle.push_back(vertex[i]);//将最小矩形的四个顶点以Point的形式放置在vector容器中
                }
                double recArea = contourArea(min_rectangle);//最小包围矩形面积
                double bizhi2 = recArea / Area;//最小包围矩形面积/轮廓面积
                



                //找轮廓重心

                mu[i] = moments(contours[i], false);
                double a = mu[i].m10 / mu[i].m00;
                double b = mu[i].m01 / mu[i].m00;
                
                Point p = Point(a, b);
                circle(drawing, p, 1, Scalar(0, 0, 255), 3, 8);//重心


                if (bizhi >= 3.5 && bizhi <= 7 && bizhi2 >= 2 && bizhi2 <= 3.3)//扇叶最小包围圆与扇叶轮廓比值
                {
                    if (two)
                    {
                        zdy++;
                        two = false;
                    }

                    //切割ROI
                    Mat ROI = threshold_output(Rect(boundRect[i].tl(), boundRect[i].br()));
                    //定义轮廓和层次结构
                    vector<vector<Point>> contoursROI;
                    vector<Vec4i> hierarchyROI;
                    //查找轮廓ROI
                    findContours(ROI, contoursROI, hierarchyROI, CV_RETR_TREE, CHAIN_APPROX_SIMPLE);
                    Mat drawingROI = Mat::zeros(ROI.size(), CV_8UC3);

                    for (int j = 0; j < contoursROI.size(); j++)
                    {
                        //计算轮廓的面积ROI
                        double AreaROI = contourArea(contoursROI[j]);
                        if (Area / AreaROI < 6 && Area / AreaROI >1.5)//模拟2.3   官方2.85轮廓面积与ROI轮廓面积比值,找到ROI全部轮廓中的矩形的那个
                        {
                            if (three)
                            {
                                zdy++;
                                three = false;
                            }

                            drawContours(drawingROI, contoursROI, j, Scalar(0, 0, 255), 2);
                            
                            //找轮廓重心ROI
                            vector<Moments> muROI(contoursROI.size());
                            muROI[j] = moments(contoursROI[j], false);
                            double aROI = muROI[j].m10 / muROI[j].m00;
                            double bROI = muROI[j].m01 / muROI[j].m00;
                            pROI = Point(aROI + boundRect[i].tl().x, bROI + boundRect[i].tl().y);
                            circle(frame, pROI, 1, Scalar(0, 255, 0), 3, 8);//重心roi
                            putText(frame, "(" + to_string(pROI.x) + "," + to_string(pROI.y) + ")", Point(pROI.x + 11, pROI.y + 11), 2, 0.8, Scalar(0, 255, 0));
                            

                            fcradius = radius;//扇叶半径是否存入全局变量

                            //测距改
                            dx = 600 / (2 * radius);

                            double yu = DISTANCE / dx;
                            cout << "7m虚拟像素距离yu为" << yu << endl;
                            
                            xuanwu = 1230 * dx;
                            cout << "当前实际距离" << xuanwu << endl;
                            
                            ox = (pROI.x - 320)*dx;//图像坐标系\单位mm、ox、oy
                            oy = (240 - pROI.y)*dx;
                            
                        }
                    }
                }
            }






            //找风车中心点(fcx,fcy)
    
            if (Area > ((fcradius / 11 * 2)*(fcradius / 11 * 2)) && Area < ((fcradius / 5.5 * 2)*(fcradius / 5.5 * 2)))//约束找出大R(圈1.扇叶半径/大R半径大约为9[guanfang]5.5[moni])******10-3
            
            {
                
                drawContours(drawing, contours, i, Scalar(0, 0, 255), 2);


        
                //包围矩形---2
                approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);//******大R
                boundRect[i] = boundingRect(Mat(contours[i]));//******大R
                //最小包围圆---2
                Point2f center;//大R圆心坐标
                float radius = 0;//初始大R最小包围圆半径
                minEnclosingCircle(contours[i], center, radius);//寻找大R最小包围圆
                circle(drawing, center, radius, Scalar(0, 255, 0), 1, 8);
                double quan2 = (PI * radius * radius) / Area;//官方视频1.39~1.46```模拟神符1.5
                

                //进一步约束(有杂点日后加强) 
                if (quan2 < 2)
                {
                    //找轮廓重心
                    vector<Moments> mu(contours.size());
                    mu[i] = moments(contours[i], false);
                    double fcx = mu[i].m10 / mu[i].m00;
                    double fcy = mu[i].m01 / mu[i].m00;
                    fcp = Point(fcx, fcy);//风车中心点


                    circle(drawing, fcp, 1, Scalar(0, 255, 0), 3, 8);//风车中心点
                    circle(frame, fcp, 1, Scalar(0, 255, 0), 3, 8);//风车中心点
                    


                    //跟随预测******参数shizhen:0顺时针1逆时针
                    seita = atan2((pROI.y - fcp.y), (pROI.x - fcp.x));//相位角弧度制
                    double fly_time = DISTANCE / FIRSPEED;//子弹飞的时间
                    double pre_seita;
                    if (shizhen == 0)
                    {
                        pre_seita = seita + (fly_time * (rot_speed / 60)) * PI * 2 + 0.2;//预测位置的相位角
                    }
                    else if (shizhen == 1)
                    {
                        pre_seita = seita - (fly_time * (rot_speed / 60)) * PI * 2 + 0.0;//预测位置的相位角
                    }

                    double rou = sqrt(pow(fcp.x - pROI.x, 2) + pow(fcp.y - pROI.y, 2));//极径
                    pre_beat_center = Point2f((rou - 0)*cos(pre_seita) + fcp.x, (rou - 0)*sin(pre_seita) + fcp.y);
                    line(frame, pre_beat_center, fcp, Scalar(148, 0, 211));
                    circle(frame, pre_beat_center, 1, Scalar(0, 0, 255), 3, 8);//pre_beat_center

                    //返角度******以光心为图像坐标系、相机坐标系圆点
                    ox_big = (pre_beat_center.x - 320)*dx;//图像坐标系\单位m、ox、oy
                    oy_big = (240 - pre_beat_center.y)*dx;
                    //cout << "相机坐标系(" << ox << "," << oy << "," << xuanwu << ")mm" << endl;//关心为原点、单位mm

                    
                }
            }






        }

        //******弹道补偿******
        double h1 = (pROI.y - fcp.y) * dx / 1000.0;//大R相对于打击的高度差m
        double h = h0 - h1;//车与打击点相对高度差m
        double beita = atan(h / DISTANCE);//P轴枪口与水平夹角 
        double t = DISTANCE / (FIRSPEED*cos(beita));//子弹飞行时间s
        double deerta_H = 9.8*t*t / 2.0;//子弹下落高度me
        double deerta_pROIy = deerta_H * 1000 / dx;//子弹下落高度pi

        circle(frame, Point(pre_beat_center.x, pre_beat_center.y - deerta_pROIy), 1, Scalar(255, 0, 0), 3, 8);//枪口补偿后打击点
        //弹道补偿后结算角度(小符)
        Y = atan(ox / xuanwu);
        P = atan((oy - deerta_H * 1000) / xuanwu);//枪口补偿后
        
        //弹道补偿后结算角度(大符)
        Y_big = atan(ox_big / xuanwu);
        //P_big = atan(oy_big / xuanwu);
        P_big = atan((oy_big - deerta_H * 1000) / xuanwu);//枪口补偿后



        
        //串口通信
        if (zdy == 3)
        {
            if (type == 0)//小符角度+大符角度
            {
                buff[0] = (Y / PI * 180 - 0) * 1000;//*1000发出小符Y******
                buff[1] = P / PI * 180 * 1000;//小符P******
                // buff[2]=xuanwu;
                // buff[3]=seita / PI * 180;
                buff[2] = (Y_big / PI * 180 - 0) * 1000;//大符Y******预测角加减调rou
                buff[3] = P_big / PI * 180 * 1000;//大符P******
                //cout<<"xiaofu"<<buff[0]<<endl;
            }
            else if (type == 1)//大符角度(舍弃)
            {
                buff[0] = (Y_big / PI * 180 - 0) * 1000;//*1000发出
                buff[1] = P_big / PI * 180 * 1000;
                buff[2] = xuanwu;
                buff[3] = seita / PI * 180;
                //cout<<"dafu"<<buff[0]<<endl;
            }
        }
        else
        {
            buff[0] = 0;
            buff[1] = 0;
            buff[2] = 0;
            buff[3] = 0;
        }


        //cout << "角度Y=" << buff[0] / 1000 << "   P=" << buff[1] / 1000 << "   大符Y=" << buff[2] / 1000 << "   大符P=" << buff[3] / 1000 << endl;
        cout << buff[0] << "***" << buff[1] << "***" << buff[2] << "***" << buff[3] << endl;

        //imshow("轮廓", drawing);//******************
        imshow("原图", frame);//原图
        waitKey(1);
    }
}

int main()
{
    //armor_dete();
    fd = 0;

    std::thread armor_dec_th0(armor_dete, "/dev/video1");
    armor_dec_th0.join();

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xingkongcanghai/p/11973112.html
YU