자율주행/[2022] 1-tenth AA EV
OpenCV Line detection cpp code
뚱이, not a starfish
2022. 4. 28. 20:22
728x90
#include <opencv2/opencv.hpp>
#include <stdio.h>
using namespace cv;
using namespace std;
#define IMG_Width 1280
#define IMG_Height 720
#define USE_DEBUG 1 // 1 Debug 사용
#define USE_CAMERA 0 // 1 CAMERA 사용 0 CAMERA 미사용
#define ROI_CENTER_Y 100 //300
#define ROI_WIDTH 100 //60
#define NO_LINE 20
std::string gstreamer_pipeline (int capture_width, int capture_height, int display_width, int display_height, int framerate, int flip_method) {
return "nvarguscamerasrc ! video/x-raw(memory:NVMM), width=(int)" + std::to_string(capture_width) + ", height=(int)" +
std::to_string(capture_height) + ", format=(string)NV12, framerate=(fraction)" + std::to_string(framerate) +
"/1 ! nvvidconv flip-method=" + std::to_string(flip_method) + " ! video/x-raw, width=(int)" + std::to_string(display_width) + ", height=(int)" +
std::to_string(display_height) + ", format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR ! appsink";
}
Mat Canny_Edge_Detection(Mat img) //Canny 연산자 함수
{
Mat mat_blur_img, mat_canny_img;
blur(img, mat_blur_img, Size(3,3)); // ³ëÀÌÁî Á¦°Å
Canny(mat_blur_img,mat_canny_img, 100,200,3); // canney edge ¿¬»ê
return mat_canny_img;
}
Mat Region_of_Interest(Mat image, Point *points)
{
Mat img_mask =Mat::zeros(image.rows,image.cols,CV_8UC1);
Scalar mask_color = Scalar(255,255,255);
const Point* pt[1]={ points };
int npt[] = { 4 };
fillPoly(img_mask,pt,npt,1,Scalar(255,255,255),LINE_8);
Mat masked_img;
bitwise_and(image,img_mask,masked_img);
return masked_img;
}
Mat Region_of_Interest_crop(Mat image, Point *points)
{
Mat img_roi_crop;
Rect bounds(0,0,image.cols,image.rows);
Rect r(points[0].x,points[0].y,image.cols, points[2].y-points[0].y);
//printf("%d %d %d %d\n",points[0].x,points[0].y,points[2].x, points[2].y-points[0].y);
//printf("%d %d\n", image.cols, points[2].y-points[0].y);
img_roi_crop = image(r & bounds);
return img_roi_crop;
}
int main(void)
{
///////////////////////////////// 영상 변수 선언 ////////////////////////////////////
int img_width, img_height;
Mat mat_image_org_color(IMG_Height,IMG_Width,CV_8UC3);
Mat mat_image_org_gray;
Mat mat_image_roi;
Mat mat_image_canny_edge;
Point points[4];
int capture_width = 1280 ;
int capture_height = 720 ;
int display_width = 640 ;
int display_height = 360 ;
int framerate = 60 ;
int flip_method = 2 ;
img_width = 640;
img_height = 360;
if(USE_CAMERA == 0) img_height = 480;
float c[NO_LINE] = {0.0, };
float d[NO_LINE] = {0.0, };
float line_center_x = 0.0;
std::string pipeline = gstreamer_pipeline(capture_width,
capture_height,
display_width,
display_height,
framerate,
flip_method);
std::cout << "Using pipeline: \n\t" << pipeline << "\n";
cv::VideoCapture cap(pipeline, cv::CAP_GSTREAMER);
// cap.set(CV_CAP_PROP_FRAME_WIDTH, img_width);
//cap.set(CV_CAP_PROP_FRAME_HEIGHT, img_height);
if(!cap.isOpened()) //카메라 열기
{
cerr <<"Error , 카메라를 열 수 없습니다. \n";
mat_image_org_color = imread("./img/line_1.jpg", IMREAD_COLOR);
img_height = mat_image_org_color.rows;
img_width = mat_image_org_color.cols;
//return -1;
}
else
{
printf("카메라가 잘 작동 됩니다.\n");
cap.read(mat_image_org_color);
}
if(USE_CAMERA == 0) mat_image_org_color = imread("./img/line_2.jpg", IMREAD_COLOR);
if(mat_image_org_color.empty())
{
cerr << "image file error!";
}
Scalar GREEN(0,255,0);
Scalar RED(0,0,255);
Scalar BLUE(255,0,0);
Scalar YELLOW(0,255,255);
//////////////////////////////////////////////////////////////////////////////////////
printf("Image size[%3d,%3d]\n", img_width,img_height);
namedWindow("Display Window", cv::WINDOW_NORMAL);
resizeWindow("Display Window", img_width,img_height);
moveWindow("Display Window", 10, 10);
namedWindow("Gray Image Window", cv::WINDOW_NORMAL);
resizeWindow("Gray Image Window", img_width,img_height);
moveWindow("Gray Image Window", 700, 10);
namedWindow("Gray ROI Image Window", cv::WINDOW_AUTOSIZE);
moveWindow("Gray ROI Image Window", 10, 600);
namedWindow("Canny Edge Image Window", cv::WINDOW_AUTOSIZE);
moveWindow("Canny Edge Image Window", 700, 600);
//ROI지정
points[0] = Point(0,ROI_CENTER_Y-ROI_WIDTH);
points[1] = Point(0,ROI_CENTER_Y+ROI_WIDTH);
points[2] = Point(img_width,ROI_CENTER_Y+ROI_WIDTH);
points[3] = Point(img_width,ROI_CENTER_Y-ROI_WIDTH);
// imshow("Display Window", mat_image_org_color);
while(1)
{
if(USE_CAMERA == 1) cap.read(mat_image_org_color);
else mat_image_org_color = imread("./img/line_1.jpg", IMREAD_COLOR);
cvtColor(mat_image_org_color, mat_image_org_gray, CV_RGB2GRAY); // color to gray conversion
mat_image_roi = Region_of_Interest_crop(mat_image_org_gray,points); //흑백
mat_image_canny_edge = Canny_Edge_Detection(mat_image_roi); //Canny edge detection
vector<Vec4i> linesP; //HoughTransform OpenCV code'확률 허프 변환'
// threshold: 만나는 점의 기준, 숫자가 작으면 많은 선 검출,정확도가 떨어빔,,숫자가 크면 정확도가 올라감
HoughLinesP(mat_image_canny_edge, linesP, 1, CV_PI/180,30,30,40);
// 매개변수 설명(위의 매개변수들의 값을 변경하면서 최상의 값 찾기)
// mat_image_canny_edge : 타겟이미지(matrix 형태의 이진화된 이미지)
// linesP : 직선 속성 변수 vector<Vec4i> 타입의 어레이 변수, 검출된 직선의 양끝 점좌표를 반환
// 1 : 픽셀 r방향의 변위값,경계값, 지정한 범위 내의 픽셀에서 직선 찾음
// CV_PI/180 : 회전방향각도, 경계값
// 30 : 최소픽셀수, 경계값
// 30 : 직선 최소 길이
// 40 : 픽셀간허용최대값(동일직선상)
printf("Line Number : %3d\n", linesP.size());
line_center_x = 0.0;
for(int i=0; i<linesP.size();i++)
{
float intersect = 0.0;
if(i>=NO_LINE) break;
Vec4i L= linesP[i];
//int cx1 = linesP[i][0];
//int cy1 = linesP[i][1];
//int cx2 = linesP[i][2];
//int cy2 = linesP[i][3];
c[i] = (L[2]-L[0])/(L[3]-L[1]); //이 c,d배열을 통해 직선의 방정식을 만들었다.
d[i] = L[0]-c[i] *L[1] ;
intersect = c[i]*(float)ROI_CENTER_Y +d[i];
line_center_x += intersect;
line(mat_image_org_color,Point(L[0],L[1]+ROI_CENTER_Y-ROI_WIDTH),Point(L[2],L[3]+ROI_CENTER_Y-ROI_WIDTH), Scalar(0,0,255), 3, LINE_AA);
//라인함수
if(USE_DEBUG ==1)
{ //라인의 시작점과 끝점
printf("L[%d] :[%3d, %3d] , [%3d , %3d] \n",i, L[0],L[1], L[2],L[3]);
//printf("x[%d] = [%6.3f] *y + [%6.3f] \n",i, c[i],d[i]);
printf("x[%d] = [%f] *y + [%f] \n", i,c[i],d[i]);
printf("intersect =[%f] [%f]\n", intersect, line_center_x);
//printf("H :[%3d , %3d] , [%3d , %3d] \n", cx1,cy1, cx2,cy2);
}
}
line_center_x = line_center_x / (float)linesP.size() - img_width/2;
if(USE_DEBUG ==1)
{
printf("Line Center=[%lf]\n",line_center_x);
printf("\n\n\n");
}
line(mat_image_org_color,Point(0,ROI_CENTER_Y),Point(640,ROI_CENTER_Y), Scalar(0,255,0), 1, LINE_AA);
line(mat_image_org_color,Point((int)line_center_x+img_width/2,ROI_CENTER_Y-ROI_WIDTH),Point((int)line_center_x+img_width/2,ROI_CENTER_Y+ROI_WIDTH), Scalar(255,255,0), 1, LINE_AA);
imshow("Display Window", mat_image_org_color);
imshow("Gray Image Window", mat_image_org_gray);
imshow("Gray ROI Image Window",mat_image_roi);
imshow("Canny Edge Image Window",mat_image_canny_edge);
// ESC 키를 입력하면 루프가 종료됩니다.
if (waitKey(25) >= 0)
{
break;
}
}
if(USE_CAMERA == 1) cap.release();
destroyAllWindows();
return 0;
}
~/ / /opencv_line_detection $make
$ ./test
Hough Transform 직선의 방정식(a,b)를 변환
이 녹색 직사각형이 ROI이며 노란색 선은 ROI의 중심선이다. 라인의 중심 추출하는 거...
급격하게 색상이 바뀌는 구간houghline 도면에서 20cm 이상 떨어져있다
노이즈에 의해서 직선이 3~4개가 인식될 경우 라인의 중심을 정확하게 추출하는 것이 어려워짐=>
SOL) 교점들의 중심 거리를 계산해서 라인이냐 아니냐 어떻게 판별할까??
라인의 추출 성능이 크게 달라질 수 있다.
imgshow함수...
esc누르면 카메라 종료됨
파라미터 변경해야하는 부분!!:
edge추출
경기장에는 검정색 바탕에 흰색임
CAMERA ROTATION
GStreamer Parameter
flip-method중에서 2번 활용:-> rotate180이용
728x90