自動駕駛之車位線檢測(opencv,c++)

1、引言
近年來隨着對泊車輔助系統需求的快速增長,提出了多種車位定位的方法,這些方法大致可分爲4類:基於用戶界面的、基於設施的、基於空閒位的和基於車位線的方法。與其他方法相比,基於車位線的方法有以下優勢:(1)可以與基於用戶界面的方法結合使用來減少由於司機重複操作帶來的不便,而這是基於用戶界面方法的主要缺陷。(2)不同於基於空閒位的方法,它能更準確地定位停車位,因爲其定位過程不依賴於相鄰汽車的停放姿勢而僅依賴於車位線。(3)它也可以有效地應用於傾斜車位的情況。由於傳感器的侷限性,運用超聲波傳感器基於空閒位的方法在傾斜車位的情況下會失效。(4)與應用雙目或者運動聲波的基於空閒位的方法相比,它通常花費少量時間。(5)它不需要額外的傳感器,例如立體攝像頭、掃描激光雷達或者短波雷達,而是運用後視攝像頭。

基於車位線的方法可以分爲半自動和全自動的方法。與全自動的方法相比,半自動的方法可能產生更可靠的結果,而且花費更少的計算資源,因爲它有來自人的額外信息。

本文提出的方法可分爲以下幾個過程:對汽車前、後、左、右4個攝像頭採集到的圖像進行重建形成全景圖像;圖像預處理,包括直方圖均衡化,劃分感興趣區域;擬合車位線,追蹤車位線,輸出結構化數據,然後在參數空間中利用車位線特徵的先驗信息對結果進行優化,最終得出識別結果。

2、檢測步驟
圖像預處理
通過加裝在汽車車身前、後、左、右的 4 個魚眼攝像頭,同時採集車輛四周的影像,經過魚眼圖像矯正,鳥瞰變換和拼接後,形成一幅車輛 4 周的 360°全景俯視圖。原圖像不可避免地會受到光照、噪聲等的影響,因爲前期處理的質量直接影響到後期識別的效果,所以爲消除圖像中無關的信息,恢復有用的真實信息,增強有關信息的可檢測性和最大限度地簡化。

原圖效果如下:
在這裏插入圖片描述

首先將原彩色轉化爲灰度圖像,考慮到光照影響導致灰度分佈不均,需要對灰度圖像進行直方圖均衡化。直方圖均衡化的基本思想是對原始圖像中的像素作某種映射變換,使變換後的圖像灰度概率密度是均勻分佈的,即變換後圖像是一幅灰度級均勻分佈的圖像,這意味着圖像灰度的動態範圍得到了增加,從而可提高圖像的對比度。但是傳統的直方圖均衡化中灰度變換函數運算與像素所處的位置無關,這種全局性處理的算法,具有算法簡單、計算速度快等優點,但由於其對所有像素點都做同樣的處理,忽略了圖像的局部特徵,這就導致經過直方圖均衡的圖像將丟失有用信息,給圖像的去噪處理及邊緣檢測帶來損失。因此本文采用對比度受限自適應直方圖均衡法( CLAHE) ,通過限制局部直方圖的高度來限制局部對比度的增強幅度,從而限制噪聲的放大及局部對比度的過增強。本文對其做了改進,可對光照和陰影有很好得魯棒性;ROI選取與濾波圖如下:
在這裏插入圖片描述在這裏插入圖片描述

接下來爲了識別水平線,所以對水平方向做了sobel檢測;
在這裏插入圖片描述

定位滑窗車位線的的搜尋起始點:1)首先,劃分搜素區域,按照x軸方向將圖像劃分出感興趣區域,對圖像兩個部分在x方向與y方向做直方圖統計,定位峯值作爲水平與豎直兩條車位線的搜尋起點。2)搜尋過程:首先,設置搜尋窗口大小(width和height);然後,以搜尋起始點作爲當前搜尋的基點,並以當前基點爲中心,做一個網格化搜尋,由初始位置x,width爲手工設定,height爲圖片大小除以設置搜尋窗口數目計算得到,這裏窗口數目爲10;其次,對每個搜尋窗口分別做水平和垂直方向直方圖統計,統計在搜索框區域內非零像素個數,並過濾掉非零像素數目小於50的框;最後,計算非零像素座標的均值作爲當前搜索框的中心,並對這些中心點做一個二階的最小二乘法擬合,得到當前搜尋對應的車道線參數。3)更新搜尋基點:步驟2)中,多項式逼近後,會得到一個直線方程,這樣就可以得到新的搜尋基點。
按Y方向直方圖統計:
在這裏插入圖片描述

追蹤車位線
滑窗的方法通常用於第一幀或者檢測失敗重新開始的檢測,因爲對計算資源浪費過多,檢測時間長,本項目由於自動泊車時候連續幀圖像之間相差不大,之後幾幀的圖像可以只對第一幀擬合的曲線周圍檢測,設置周圍的邊框,然後在該範圍內尋找下一幀曲線的像素點從而擬合曲線。在最後處理每一幀圖像時要設置標誌位檢測是否檢測到擬合的曲線,檢測到的話用search_from_previous方法,否則的話要用滑窗的方法重新尋找車道線。

輸出結構化數據
當檢測出水平與豎直方向的車位線之後,求出兩線之間的交點,輸出到融合決策進程進行控車。

在這裏插入圖片描述代碼部分後面上傳至博客,隨時關注哦。。。。

更新時間2019.0624
部分代碼如下

//
// Created by lqx on 19-3-4.
//

#include <stdlib.h>
#include "detectslot.h"
/*
 * 用於sort()函數中降序排列
 */
bool comp(const ValueIndex &a,const ValueIndex &b)
{
    return a.value>b.value;
}
bool comp1(const Point2f &a,const Point2f &b)
{
    return a.y<b.y;
}
DetectParkingSlot::DetectParkingSlot():mSlotData("0x10014")
{}

DetectParkingSlot::~DetectParkingSlot() {

}
//4、直方圖統計
int  DetectParkingSlot::HistFromroi(cv::Mat img)
{
    Mat hist_eq(img.rows,img.cols,CV_8UC1);
    int sum_pix[256]={0};
    int gray_sum=0;
    int temp_gray[256];
    int all_pix=img.rows*img.cols;
    float n_per[256]={0.0};
    for(int i=0;i<=img.rows;i++)
    {
        uchar* data=img.ptr<uchar>(i);
        for (int j = 0; j <=img.cols ; ++j)
        {
            sum_pix[data[j]]++;

        }

    }
    for (int k = 0; k <256 ; ++k)
    {
        gray_sum+=sum_pix[k];

        temp_gray[k]=gray_sum;
    }

    //for (int l = 1; l <256 ; ++l)
    // {
    //    n_per[l]=n_per[l]+n_per[l-1];
    //}
    //int maxnum=0;
    int max_gray=0;

    //20步濾波,獲取最大差分值,找到邊緣最大值位置的灰度值
    for (int a = 20; a <256 ; ++a)
    {
        if(maxnum<temp_gray[a]-temp_gray[a-20])
        {
            maxnum=temp_gray[a]-temp_gray[a-20];
            max_gray=a-10;
        }

    }

    //imshow("eqhist",hist_eq);
    return max_gray;

}
cv::Mat DetectParkingSlot::gray_binnary(cv::Mat img,int gray_value)
{
    int tempgray=0;
    Mat dst_img(img.rows,img.cols,CV_8UC1);
    for (int i = 0; i <img.rows ; ++i)
    {
        for (int j = 0; j <img.cols ; ++j)
        {
            tempgray=img.at<uchar> (i,j);
            if (max_gray>tempgray)
            {
                dst_img.at<uchar>(i,j)=0;
            }
            else
                dst_img.at<uchar>(i,j)=tempgray-max_gray;
            //dst_img.at<uchar>(i,j)=255;
        }

    }
    //imshow("binnary",dst_img);
    return dst_img;
}

int  DetectParkingSlot::ProjectYdirect(cv::Mat img)
{
    int temp[img.cols];
    int maxpos;
    //向Y軸投影,獲取最大位置
    for (int i = 0; i <img.cols; ++i)
    {   int sumY=0;
        for (int j = 0; j <img.rows ; ++j)
        {
            sumY+=img.at<uchar>(j,i);

        }
        //最大位置像素列平均
        temp[i]=sumY/img.rows;

    }
    int tempgray=0;
    int temp_sum=0;
    int temp_sum_right=0;
    //int tempgray_right=0;
    int maxgray=0;
    int maxgray_right=0;
    int max_index=0;
    int max_index_right=0;

    //左半邊圖像獲取最大位置與像素平均值
    for (int k = 5; k <img.cols-1; ++k)
    {
        tempgray=(temp[k-1]+temp[k]+temp[k+1])/3;
        if (tempgray>maxgray)
        {
            maxgray = tempgray;
            max_index = k;

        }
    }

    if(maxgray<20)
    {
        //cout<<"no deteced"<<endl;

        maxgray=0;

        return maxgray;

    }

    maxpos=max_index;
    return maxpos;

}


/*
 *尋找波峯
 * matData:輸入的一列數據
 * minPeakDistance:峯值最小值
 * minPeakHeight:峯值之間的最小距離
 * peaks:峯值的位置和大小
 */

void DetectParkingSlot::findPeaks(Mat &matData,float minPeakDistance,float minPeakHeight,vector<ValueIndex> &peaks)
{
    int row = matData.rows;
    vector<int> Sign;
    float diff;
    for (int i = 1; i < row; i++)
    {
        /*相鄰值做差:
        *小於0,賦-1
        *大於0,賦1
        *等於0,賦0
        */
        diff = matData.at<float>(i,0)-matData.at<float>(i-1,0);
        if (diff > 0)
        {
            Sign.push_back(1);
        }
        else if (diff < 0)
        {
            Sign.push_back(-1);
        }
        else
        {
            Sign.push_back(0);
        }
    }

    //再對Sign相鄰位做差
    //保存極大值
    ValueIndex temp;
    for (int j = 1; j < Sign.size(); j++)
    {
        int diff = Sign[j] - Sign[j - 1];
        if (diff < 0)
        {
            if (matData.at<float>(j,0)>minPeakHeight)
            {
                //根據峯值最小高度進行篩選
                temp.index=j;
                temp.value=matData.at<float>(j,0);
                peaks.push_back(temp);
            }
        }
    }

    if(minPeakDistance>0)
    {
        int i = 1;
        while(i<peaks.size())
        {
            int sub = peaks[i].index - peaks[i-1].index;
            if(sub < minPeakDistance)
            {
                peaks.erase(peaks.begin()+i);
            }
            else i ++;
        }

    }
}

/*
 * 圖像灰度化函數
 */
void  DetectParkingSlot::rgbGray(Mat &srcImg,Mat &grayImg)
{
    if(srcImg.empty())
    {
        cout<<"can not load image";
        exit(1);
    }

    if (srcImg.channels()==1)
    {
        cout<<"please load a RGB image"<<endl;
        exit(1);
    }
   for (int i = 0; i < srcImg.rows; i++)
    {
        Vec3b *dataColor = srcImg.ptr<Vec3b>(i);//彩色圖
        uchar *dataGray = grayImg.ptr<uchar>(i);//灰度圖
        for (int j = 0; j < srcImg.cols; j++)
        {
            if (srcImg.channels()==3)
            {
                dataGray[j]=0.5 * dataColor[j][1] + 0.5 * dataColor[j][2];
            }
        }
    }
}
/*
 * srcImage:經預處理後的灰度圖像,數據類型爲32F
 * startLoction:爲全局的按列求和後,強度最大值的位置
 * step 滑窗步長
 * windowWidth 滑窗的寬
 * windowHeight 滑窗的高
 * linePoint:按強度最大值,檢測出垂直車位線上的點
 */

void DetectParkingSlot::VerticalProjectionW(Mat &srcImage,Point &startLoction,int step,int windowWidth,
                                     int windowHeight, vector<Point> &linePoint)
{
    int halfWidth=windowWidth/2;
    int halfHeight=windowHeight/2;
    //類似卷積後求圖像大小
    int windowsnum=(srcImage.rows-windowHeight)/step+1;
    Mat windowimage;
    Mat sumwindowcol=Mat::zeros(1,windowWidth,CV_32F);
    double maxValue = 0;
    Point maxloction;
    linePoint.push_back(startLoction);
    for (int i=0;i<windowsnum;i++)
    {
        if(linePoint.back().x < halfWidth)
        {
            Rect roi(0, step * i, windowWidth, windowHeight);
            windowimage = srcImage(roi);
            reduce(windowimage, sumwindowcol, 0, CV_REDUCE_SUM, CV_32F);
            minMaxLoc(sumwindowcol, 0, &maxValue, 0, &maxloction);
            if (maxValue > 5)
            {
                Point temp=Point(maxloction.x, step * i + halfHeight);
                linePoint.push_back(temp);
            }
        }
            else if(linePoint.back().x+halfWidth>srcImage.cols)
        {
            Rect roi(srcImage.cols-windowWidth,step*i,windowWidth,windowHeight);
            windowimage=srcImage(roi);
            reduce(windowimage,sumwindowcol,0,CV_REDUCE_SUM,CV_32F);
            if (maxValue > 5)
            {
                Point temp=Point(srcImage.cols-windowWidth + maxloction.x, step * i + halfHeight);
                linePoint.push_back(temp);
            }
        }
        else
        {
            Rect roi(linePoint.back().x - halfWidth, step * i, windowWidth, windowHeight);
            windowimage = srcImage(roi);
            reduce(windowimage, sumwindowcol, 0, CV_REDUCE_SUM, CV_32F);
            minMaxLoc(sumwindowcol, 0, &maxValue, 0, &maxloction);
            if (maxValue > 5) {

                Point temp=Point(linePoint.back().x - halfWidth + maxloction.x, step * i + halfHeight);
                linePoint.push_back(temp);
            }
        }
    }
    linePoint.erase(linePoint.begin());

}

/*
 * srcImage:經預處理後的灰度圖像,數據類型爲32F
 * startLoction:全局的按列求和和按行求和後最大值的交點位置
 * linePoint:按強度最大值,檢測出水平車位線上的點
 */
int DetectParkingSlot::HorizonProjectionW(Mat &srcImage,Point &startLoction, int step,int windowWidth,
                                    int windowHeight,vector<Point> &linePoint)
{
    int halfWidth=windowWidth/2;
    int halfHeight=windowHeight/2;
    //類似卷積後求圖像大小
    int windowsnum=(srcImage.cols-startLoction.x-windowWidth)/step+1;
    if(windowsnum<2)
    {
        return 0;
    }
    Mat windowimage;
    Mat sumwindowrow=Mat::zeros(windowHeight,1,CV_32F);
    double maxValue = 0;
    Point maxloction;
    linePoint.push_back(startLoction);
    //暫時沒有考慮垂直線極其靠近邊緣的情況,即startloction.y-100<0
    for(int i=0;i<windowsnum;i++)
    {
        if(linePoint.back().y-halfHeight<0)
        {
            Rect roi(startLoction.x+step*i,0,windowWidth,windowHeight);
            windowimage=srcImage(roi);
            reduce(windowimage, sumwindowrow, 1, CV_REDUCE_SUM,CV_32F);
            minMaxLoc(sumwindowrow,0,&maxValue, 0, &maxloction);
            if (maxValue>20)
            {
                Point temp=Point(startLoction.x+step*i+halfWidth,maxloction.y);
                linePoint.push_back(temp);
            }
        }
        else if(linePoint.back().y+halfHeight>srcImage.rows)
        {
            Rect roi(startLoction.x+step*i,srcImage.rows-windowHeight,windowWidth,windowHeight);
            windowimage=srcImage(roi);
            reduce(windowimage, sumwindowrow, 1, CV_REDUCE_SUM,CV_32F);
            minMaxLoc(sumwindowrow,0,&maxValue, 0, &maxloction);
            if (maxValue>20)
            {
                Point temp=Point(startLoction.x+step*i+halfWidth,srcImage.rows-windowHeight+maxloction.y);
                linePoint.push_back(temp);
            }
        }
        else
        {
            Rect roi(startLoction.x+step*i,linePoint.back().y-halfHeight,windowWidth,windowHeight);
            windowimage=srcImage(roi);
            reduce(windowimage, sumwindowrow, 1, CV_REDUCE_SUM,CV_32F);
            minMaxLoc(sumwindowrow,0,&maxValue, 0, &maxloction);
            if (maxValue>0)
            {
                Point temp=Point(startLoction.x+step*i+halfWidth,linePoint.back().y-halfHeight+maxloction.y);
                linePoint.push_back(temp);
            }
        }
    }
    linePoint.erase(linePoint.begin());
    return 1;
}
/*
 * lineA 擬合出的垂直車位線的參數
 * lineB 擬合出的水平車位線的參數
 */
Point2f DetectParkingSlot::getCrossPoint(Vec4f &lineA, Vec4f &lineB)
{
    Point2f crossPoint;
    if(lineA[1]==1)
    {
        double kb = lineB[1]/lineB[0];
        crossPoint.x=lineA[2];
        crossPoint.y=kb*(crossPoint.x-lineB[2])+lineB[3];
    }
    else{
        double ka,kb;
        ka = lineA[1]/lineA[0]; //求出LineA斜率
        kb = lineB[1]/lineB[0]; //求出LineB斜率
        crossPoint.x = (ka*lineA[2] - lineA[3] - kb*lineB[2] + lineB[3]) / (ka - kb);
        crossPoint.y = (ka*kb*(lineA[2] - lineB[2]) + ka*lineB[3] - kb*lineA[3]) / (ka - kb);
    }
    return crossPoint;
}

/*
 * 檢測車位線函數
 * srcImage:原始圖像
 * srcRoi:在原圖像上截取的感興趣區域
 * frangiRoi:frangi濾波後去掉四周的白色區域
 * parkingSpacePoint:檢測出的車位線交點的位置,順序爲按照y軸從小到大。
 */
int DetectParkingSlot::detecSlot(Mat &srcImage,Rect &srcRoi,Slot_Point &parkingSlotPoint)
{
    Mat roi_image0=srcImage(srcRoi);
    Mat gray(roi_image0.rows,roi_image0.cols,CV_8UC1);
    rgbGray(roi_image0,gray);
    Point roistart(srcRoi.x,srcRoi.y);
    Size roisize(srcRoi.width,srcRoi.height);
    //分別按列累加和按行累加
//獲取最大合適值
    int maxvalue=HistFromroi(gray);
    Mat grad_y,abs_grad_y;
    Mat gray_image=gray_binnary(gray,maxvalue);
    imshow("gray",gray_image);
    Sobel(gray_image, grad_y,CV_16S,0, 1,3, 1, 1, BORDER_DEFAULT);
    convertScaleAbs(grad_y,abs_grad_y);
    imshow("y向soble", abs_grad_y);
// 按行投影到Y軸
    Mat sumcol=Mat::zeros(1,roisize.width,CV_32F);
    Mat sumrow=Mat::zeros(roisize.height,1,CV_32F);
    reduce(gray_image, sumcol, 0, CV_REDUCE_SUM,CV_32F);
    reduce(abs_grad_y, sumrow, 1, CV_REDUCE_SUM,CV_32F);
    //垂直車位線粗略檢測,累加強度最大值的位置
    double maxValue_x = 0;
    Point maxloction_x;
    minMaxLoc(sumcol,0,&maxValue_x, 0, &maxloction_x);
    //垂直車位線精確檢測,滑窗檢測
    vector<Point>linepointcol;
    VerticalProjectionW(gray_image,maxloction_x,50,50,50,linepointcol);
    if(linepointcol.size()<2)
    {
        //cout<<"未檢測到車位線"<<endl;
        namedWindow("image",WINDOW_NORMAL);
        imshow("image",srcImage);
        return 0;
    }
    //將檢測出的點轉換到原圖上
    for(int i=0;i<linepointcol.size();i++)
    {
        linepointcol[i]=linepointcol[i]+roistart;
    }
    Vec4f line_paracol;
    fitLine(linepointcol, line_paracol, cv::DIST_L2, 0, 1e-2, 1e-2);
    //畫出檢測出的點和擬合出的垂直線

    if(line_paracol[0]>0.001)
    {
        Point point1;
        point1.x = line_paracol[2];
        point1.y = line_paracol[3];
        double k1 = line_paracol[1] / line_paracol[0];
        //計算直線的端點(y = k(x - x0) + y0)
        Point point11, point12;
        point11.x = 0;
        point11.y = k1 * ( point11.x - point1.x) + point1.y;
        point12.x = srcImage.cols-1;
        point12.y = k1 * (point12.x  - point1.x) + point1.y;

        cout<<"the point11.y is "<<point11.y<<endl;
        cout<<"the point12.y is "<<point12.y<<endl;



        cv::line(srcImage, point11, point12, cv::Scalar(0, 255, 0), 2,CV_AA);
        for (int i = 0; i < linepointcol.size(); i++)
        {
            circle(srcImage, linepointcol[i], 3, cv::Scalar(0, 0, 255), 2, 8, 0);
        }
    }
    else
    {
        cv::line(srcImage, Point(line_paracol[2],0), Point(line_paracol[2],srcImage.rows), cv::Scalar(0, 255, 0), 2,CV_AA);
        for (int i = 0; i < linepointcol.size(); i++)
        {
            circle(srcImage, linepointcol[i], 3, cv::Scalar(0, 0, 255), 2, 8, 0);
        }
    }

    //通過求sumrow前兩個最大的波峯,粗略找到水平車位線的位置
    //將灰度累加強度值歸一化到0~255
    double maxValue_y=0;
    double minValue_y=0;
    minMaxLoc(sumrow,&minValue_y, &maxValue_y, 0, 0);
    sumrow=(sumrow-minValue_y)*255/(maxValue_y-minValue_y);
    vector<ValueIndex>peaks;
    findPeaks(sumrow,100,100,peaks); //設置峯值的最小閾值爲100
    sort(peaks.begin(), peaks.end(),comp);//將峯值降序排列
    Point startloction; //水平滑窗開始的位置
    vector<Point2f>parkingSpacePoint;
    if(peaks.size()>1)
    {

        for(int i=0;i<2;i++)
        {
            startloction=Point(maxloction_x.x,peaks[i].index);
            vector<Point>linepointrow0;
            //cout<<startloction<<endl;
            HorizonProjectionW(abs_grad_y,startloction,20,40,30,linepointrow0);
            Point2f crossPoint0;
            Vec4f line_pararow0;
            if (linepointrow0.size()>1)
            {
                //將所有點轉換到原圖座標中
                for(int i=0;i<linepointrow0.size();i++)
                {
                    linepointrow0[i]=linepointrow0[i]+roistart;
                }
                //將檢測出的點畫到原圖上
                for (int i = 0; i < linepointrow0.size(); i++)
                {
                    circle(srcImage, linepointrow0[i], 3, cv::Scalar(0, 0, 255), 2, 8, 0);
                }
                fitLine(linepointrow0, line_pararow0, cv::DIST_L2, 0, 1e-2, 1e-2);
                //求交點
                crossPoint0=getCrossPoint(line_paracol,line_pararow0);


                //畫出擬合的水平線
                Point point2;
                point2.x = line_pararow0[2];
                point2.y = line_pararow0[3];
                double k2 = line_pararow0[1] / line_pararow0[0];
                //計算直線的終點(y = k(x - x0) + y0),起點爲交點
                Point point21;
                point21.x = srcImage.cols-1;
                point21.y = k2 * (point21.x  - point2.x) + point2.y;
                cv::line(srcImage, crossPoint0, point21, cv::Scalar(0, 255, 0), 2,CV_AA);

            }
            else
            {

                if(line_paracol[0]>0.001)
                {
                    double k=line_paracol[1]/line_paracol[0];
                    double b=line_paracol[3]-k*line_paracol[2];
                    crossPoint0.y=peaks[i].index+roistart.y; //轉換到原圖座標
                    crossPoint0.x=(crossPoint0.y-b)/k;
                    //畫出垂直於垂直車位線的水平線
                    double k1 = 1/k;
                    Point point21;
                    point21.x = srcImage.cols-1;
                    point21.y = k1 * (point21.x  - crossPoint0.x) + crossPoint0.y;
                    cv::line(srcImage, crossPoint0, point21, cv::Scalar(0, 255, 0), 2,CV_AA);
                }
                else
                {
                    crossPoint0.y=peaks[i].index+roistart.y; //轉換到原圖座標
                    crossPoint0.x=line_paracol[2];
                    //畫出垂直於垂直車位線的水平線
                    line(srcImage, crossPoint0, Point(srcImage.cols-1,crossPoint0.y), cv::Scalar(0, 255, 0), 2,CV_AA);
                }
            }
            parkingSpacePoint.push_back(crossPoint0);
        }
    }
        //只有一個波峯的時候,暫時考慮尋找水平車位線
    else if(peaks.size()==1)
    {
        startloction=Point(maxloction_x.x,peaks[0].index);
        vector<Point>linepointrow0;
        HorizonProjectionW(gray_image,startloction,50,50,50,linepointrow0);
        Point2f crossPoint0;
        Vec4f line_pararow0;
        if (linepointrow0.size()>1)
        {
            //將所有點轉換到原圖座標中
            for(int i=0;i<linepointrow0.size();i++)
            {
                linepointrow0[i]=linepointrow0[i]+roistart;
            }
            //將檢測出的點畫到原圖上
            for (int i = 0; i < linepointrow0.size(); i++)
            {
                circle(srcImage, linepointrow0[i], 5, cv::Scalar(0, 0, 255), 2, 8, 0);
            }
            fitLine(linepointrow0, line_pararow0, cv::DIST_L2, 0, 1e-2, 1e-2);
            //求交點
            crossPoint0=getCrossPoint(line_paracol,line_pararow0);

            //畫出擬合的水平線
            Point point2;
            point2.x = line_pararow0[2];
            point2.y = line_pararow0[3];
            double k2 = line_pararow0[1] / line_pararow0[0];
            //計算直線的終點(y = k(x - x0) + y0),起點爲交點
            Point point21;
            point21.x = srcImage.cols-1;
            point21.y = k2 * (point21.x  - point2.x) + point2.y;
            cv::line(srcImage, crossPoint0, point21, cv::Scalar(0, 255, 0), 2,CV_AA);
        }
        else
        {
            double k=line_paracol[1]/line_paracol[0];
            double b=line_paracol[3]-k*line_paracol[2];
            crossPoint0.y=peaks[0].index+roistart.y;
            crossPoint0.x=(crossPoint0.y-b)/k;
            //畫出垂直於垂直車位線的水平線
            double k1 = 1/k;
            Point point21;
            point21.x = srcImage.cols-1;
            point21.y = k1 * (point21.x  - crossPoint0.x) + crossPoint0.y;
            cv::line(srcImage, crossPoint0, point21, cv::Scalar(0, 255, 0), 2,CV_AA);
        }
        parkingSpacePoint.push_back(crossPoint0);

    }
    else
    {
        //cout<<"未檢測到車位線"<<endl;
        namedWindow("image",WINDOW_NORMAL);
        imshow("image",srcImage);
        return 0;
    }

    if(parkingSpacePoint.size()>0)
    {
        SlotPoint temp;
        sort(parkingSpacePoint.begin(),parkingSpacePoint.end(),comp1);
        for (int i = 0; i < parkingSpacePoint.size(); i++)
        {
            temp.x=int(parkingSpacePoint[i].x);
            temp.y=int(parkingSpacePoint[i].y);
            parkingSlotPoint.push_back(temp);
            circle(srcImage, parkingSpacePoint[i], 2, cv::Scalar(0, 255, 255), 2, 8, 0);
        }

    }


    //向共享內存傳送數據
    if (!mSlotData.sendData(parkingSlotPoint))
    {
        std::cerr << "RadarAnalysis send esr to share memory buf error !!" << std::endl;
    }

    namedWindow("image",WINDOW_NORMAL);
    imshow("image",srcImage);
    return 1;
}



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