OpenCV Line detection cpp code

2022. 4. 28. 20:22·자율주행/[2022] 1-tenth AA EV
#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이용

 

 

'자율주행 > [2022] 1-tenth AA EV' 카테고리의 다른 글

[ROS-melodic]Jetson nano alias 축약어 설정하기  (0) 2022.04.24
'자율주행/[2022] 1-tenth AA EV' 카테고리의 다른 글
  • [ROS-melodic]Jetson nano alias 축약어 설정하기
뚱이, not a starfish
뚱이, not a starfish
M.S. Student,. Mainly interested in computer vision and autonomous cars
  • 뚱이, not a starfish
    Wilbur-Babo
    뚱이, not a starfish
  • 전체
    오늘
    어제
    • 분류 전체보기 (194)
      • 통신 및 네트워크 (12)
      • Embedded Projects (2)
      • 3D Reconstruction (1)
        • Gaussian Splatting (0)
        • 3D-GS (1)
        • Multi-view Geometry (0)
        • VSLAM (0)
        • Computer Graphics (0)
      • LLM(VLM) (0)
      • AI-Study (28)
        • Mono-Depth (7)
        • Base (2)
        • Computer Vision (1)
        • Image Processing (3)
        • Tiny Object Detection (3)
      • 자율주행 (20)
        • [2023] 1-fifth AA EV (4)
        • [2022] 1-tenth AA EV (2)
        • ROS 1,2 (4)
        • 이론 (7)
        • 실습 (3)
      • Pointcloud (0)
      • sw (16)
        • 정보보안 (1)
        • Android_develop (3)
      • [학부] 전기전자공학 (12)
        • 반도체 (2)
        • 마이크로프로세서 (6)
      • 코딩테스트 (22)
        • BOJ (21)
      • 취준 (21)
        • EVS37 Ambassador (5)
        • 차량 제어 플랫폼 (5)
        • 영어 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자율주행경진대회
    정렬
    우분투터미널
    자율주행시험
    현대자동차 자율주행 서류 합격 후기
    현대자동차최종불합
    현대자동차 자율주행
    현대차3월신입후기
    오픽후기
    자율주행
    자율주행작품
    현차 3월 신입 서류
    rc카
    evs37sdv
    tar 파일
    심포지움
    헤네스유아용자동차
    EVS37
    헤네스
    현대자동차최종면접결과
    현차떨
    tar압축풀기
    현차 3월 자율주행
    현차 자율주행
    현대자동차 연구개발
    evs37 sdv
    현대자동차 서류합격후기
    software defined vehicle
    오블완챌린지
    자율주행자동차
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
뚱이, not a starfish
OpenCV Line detection cpp code
상단으로

티스토리툴바