주행영역을 출력하는 OpenCV를 이용한

OpenCV를 이용해서 주행영역을 출력하는 일을 해봤어

혼자 하는 것은 쉽지 않았지만 구글링을 통해 실질적으로 도움이 되는 것은 https://gaussian37.github.io/math-algorithm-intersection_point/https://webnautes.tistory.com/1244이 두 사이트였다.

교수에게서 받은 힌트로 동작 과정은 이랬다.1. 흑백 전환 2. Edge 검출 3. 차선 영역 RoI 4. Huff Dection Line 5. 평균 직선 추정 6. 주행 영역 출력

이로써

기본 이미지를 받아와서

이런 식으로 진행했다.

소스 코드

#include<opencv.hpp>

#define PI 3.141592//파이 값 정의#define ArraySize 100//배열 크기 using namespace cv;float correctionValue1=0.6;//관심 영역 사다리꼴에서 원하는 부분만 조절하기 위한 조정치 float correctionValue2=0.07;float correctionValue3=0.37;float correctionValue4=100;float correctionValue5=100;Mat drivingArea(Mat image, Point pt1, Point pt2, Point pt3, Point pt4);//주행 영역 표시 함수 Point*aPoint1=new Point[ArraySize]*aPoint2=new Point[ArraySize]*bPoint1=new Point[ArraySize]*bPoint2=new Point[ArraySize];//몇점을 보존하기 위한 배열 int aIndex=0, bIndex=0;//배열의 인덱스 값 float get_radian(float Val);//각도 반환 함수 Mat region_of_interest(Mat img_edges);//관심 영역 출력 함수 Point IntersectionPoint1(Point p1, Point p2, Pointp3, Point p4);//것과 점으로 연결된 두 선의 교차로 출력 함수 int main(){VideoCapture capture(“lane.mp4”);while(1){Mat img;if(capture.read(img)==false)break;//이미지 입력 Mat gray;cvtColor(img, gray, COLOR_BGR2GRAY);//흑백으로 변환 Mat edged;Canny(gray, edged, 100,200);//Edge검출 edged=region_of_interest(edged);//차로 영역 RoI처리

//——Hough Line Detection~//std::vector<Vec2f>lines;HoughLines(edged, lines, 1, CV_PI/180,30,30,100);//이 사진을 허프 변환 Mat HoughLineDetected_img(edged.rows, edged.cols, CV_8U, cv;Scalar(255);// 선 벡터를 반복해서 선 그리는 std::vector<cv;Vec2f>;const_iterator it=lines.begin();while(it!=lines.end(){float rho=(*it)[0];//처음의 요소는 rho거리 float theta=(*it)[1];//두번째 요소는 델타 각도 if(theta<get_radian(85)&&theta;>get_radian(35){//각도 오른쪽 범위 35~85각도의 선에서 인지 cv;Point pt1(rho/cos(theta), 0);//첫 우츄크각에서 해당 선의 교차점 aPoint1[(aIndex)%ArraySize]=pt1;//마루데 Queue가 돌게 사이즈 내에서 값을 씌우고 꽉 cv;Point pt2(rho-HoughLineDetected_img.rows*sin(theta)/cos(theta), HoughLineDetected_img.rows);//마지막 우츄크각에서 해당 선의 교차점 aPoint2[(aIndex++%)ArraySize]=pt2;//다음 인덱스 값에 걸친 값을 넣음//cv;line(img, pt1, pt2, cv;Scalar(255), 2);//모든 직선 그리기

}else if(theta<get_radian(145)&&theta;>get_radian(95){//각도 왼쪽 범위 95~145각도의 선에서 인지 cv;Point pt1(0, rho/sin(theta);//첫 쥬와츄크각에서 해당 선의 교차점 bPoint1(bIndex)%ArraySize]=pt1;//마루데 Queue가 돌게 사이즈 내에서 값을 씌우고 꽉 cv;Point pt2(HoughLineDetected_img.cols(rho-HoughLineDetected_img.cols*cos(theta)/sin(theta);//마지막 쥬와츄크각에서 해당 선의 교차점 bPoint2[(bIndex++%)ArraySize]=pt2;//다음 인덱스 값으로 건너가서 값을 넣음//cv;line(img, pt1, pt2, cv;Scalar(255), 2);//모든 직선 그리기}++it;//반복자 증가}//—————————————–/(중략)/-평균 직선 추정—//Point aP1S(0,0), aP2S(0,0), bP1S(0,0), bP2S(0,0);//각 끝점의 평균치를 탑재하기 위한 점 for(int i=0;i<ArraySize;i++){//배열에 저장된 모든 점의 좌표화를 요구하는 것 aP1S+=aPoint1[i];aP2S+=aPoint2[i];bP1S+=bPoint1[i];bP2S+=bPoint2[i];}aP1S/=ArraySize;//배열의 저장된 모든 점의 타이라균치을 요구하는 것 aP2S/=ArraySize;bP1S/=ArraySize;bP2S/=ArraySize;//cv;line(img, aP1S, aP2S, cv;Scalar(255,0,0), 2);//추정된 평균점으로 직선 그리기//cv;line(img, bP1S, bP2S, cv;Scalar(255,0,0), 2);//추정된 평균점으로 직선 그리기//—————————————–//Mat result=drivingArea(img, bP1S, aP1S, aP2S, bP2S);//주행 영역 표시 함수와 평균 직선 추정에서 나온 선의 양끝을 전해imshow(“lane”, result);waitKey(30);}return 0;}

Mat region_of_interest(Mat img_edges){int width=img_edges.cols;int height=img_edges.rows;Point points[4];//사다리꼴 영역 좌표 조정-//points[0]=Point(width*(1-correctionValue1)/2+correctionValue5, height-correctionValue4);points[1]=Point(width*(1-correctionValue2)/2, height-height*correctionValue3);points[2]=Point(width-(width*(1-correctionValue2)/2, height-height*correctionValue3);points[3]=Point(width-(width*(1-correctionValue1)/2+correctionValue5, height-correctionValue4);//——————————–//Mat img_mask=Mat;zeros(img_edges.rows, img_edges.cols, CV_8UC1);//그림과 같은 크기의 아무것도 없는 그림 생성 const Point*ppt[1]={points}://사다리꼴 영역 좌표를 배열에 담은 int npt[]={4};//함수에 전달할 배열 크기 정의 fillPoly(img_mask, ppt, npt, 1, Scalar(255,255,255), LINE_8);//아무것도 없는 그림에 사다리꼴을 백지로 그림 Mat img_masked;bitwise_and(img_edges, img_mask, img_masked);//기존의 그림과 비트 연산을 통해서 하얗게 그려지는 부분만 남기도록 하는 것

returnimg_masked;//해당 영상 전환}

float get_radian(float Val)//각도를 계산하고 반환{return PI*Val/180;}

Mat driving Area(Matimage, Point pt1, Point pt2, Point pt4){Pointection Point1(pt2, pt1, pt4);//평균 직선의 중앙점에 약간 이하의 좌표를 추출 Pointa1o=ptint Pt14Fix=Intersection Point1(pt2, a1, a2);Points[4]={pt3, Pt23Fix};//각 점의 좌표를 함수에 전달하기 위해서 보존 const Point*ppt[1]={points}ghted(result, 0.8, img_mask, 0.2, 0, result);//전 그림과 사다리꼴 영역을 이용하여 가중치를 두고 그림을 합계 line(result, Pt14Fix, pt3, Scalar(0, 0, 255), LINE_8);//대형의 옆 부분에 적선를 끌line(result, Pt23Fix, pt

이렇게 검출된 오프라인은 다음 과정에서 어떤 평균 직선 추정에서 평균 직선의 기울기를 자주 떨어뜨리게 했다.

이를 해결하기 위해 인지 각도 범위를 좀 더 줄이고, 배열에 저장되는 하프라인 개수를 더 증가시켜 오차를 줄이는 방법으로 해결했다.

여기서 사다리꼴의 중심점을 찾아낸다면 아주 간단한 자율주행이 될 것 같다.

현재처럼 하프 직선을 특정 각도만 검출하지 않고 전체 각도로 바꾼 뒤 평균 직선 영역의 교차점이 자신에게 다가올 것으로 판단되면 속도를 낮춰 장애물도 해결할 수 있을 것으로 보인다.

다만 차로 변경이나 차로 변경해 오는 차량까지 처리하려면 새로 RoI를 취하고 하프 검출을 새로 하면 되겠지만 정해진 프레임 단위로 인식하는 프로그램을 신속하게 처리하는 CPU가 필요해 프로그래머 입장에서도 최적화를 생각해야 한다.

error: Content is protected !!