내맘대로 공부기록.

[ C++ ]

[ openCV | C++ ] ( 3 / 6 ) 차선검출. 이미지 전 처리. Color Filtering(HLS, LAB color space)

fwanggus 2021. 8. 22. 18:10

차선 검출을 위한 이미지 전 처리해보기 🛣


⚙️  기본 설명  ⚙️

 

  1. 왜곡 제거(카메라 보정) 👍
  2. Perspective Transform(원본 이미지 ⏩  2D)
  3. Color Filtering(HLS, LAB color space)
  4. 픽셀 값 정규화(feat. 최대값) 및 이미지 픽셀(HLS 1개, LAB 1개)  합치기.
  5. Window Search
  6. Show Detected Lines and Info.

개념  🧐

차선을 잡아주기 위해서, 원본 이미지의 색 채널을 조작합니다. 우리가 통상 보고 있는 화면의 색은 BGR채널(Blue, Green, Red)의 조합으로 표현할 수 있습니다. 고맙게도 opencv 에서는 BGR 채널을 변환시켜서 빛의 요소 및 색의 명암, 채도, 포화도 등등의 섬세한 요소로 분리하여 표현할 수 있게 해 줍니다. 차선 검출 전처리 작업에서는 이런 변환 과정을 통해서, 노란색 차선 또는 흰색 차선만 픽셀 요소로 남겨두고(필터링), 남겨진 픽셀 데이터의 인덱스(위치) 값을 활용하여 차선 검출에 좋은 소스로서 활용할 수 있게 됩니다.

 

왼: bird view 변환 이미지, 우 : LAB 채널 중 B채널 표시(L,A채널은 필터링)

 

방법  + DEMO. 🛠🚀

 

순서는 다음과 같습니다.

 

1. 컬러 채널 변경.

2. 남겨둘 채널의 픽셀값만 가져오기.(전체 3개 중 1개의 채널 값만 입력함. 예) L, A, B 중 B 채널 값만 가져오기)


1. 컬러 채널 변경.

cvtColor 함수를 사용합니다. 함수의 사용법에 대해서는 다음 글의 "이미지 이진화 하기" 부분을 참고하시면 좋을 것 같네요.

 

 

[ openCV | C++ ] findContours 함수 사용법, 입력 출력(포인트) 값의 이해

🔗 함수와 매개변수 : findContours(매개변수입력) 🔗 DEMO.  🖼 이미지 이진화 하기  😷 HSV 이미지 마스킹 하기  📏 컨투어 찾기 이진화(Binary) 이미지 소스로 부터 사물의 외곽 형상을 검출하여,

fwanggu-lee.tistory.com

 

컬러 채널 중 HLS, LAB 채널을 선택해서 변환한 이유는 흰색 라인, 노란색 라인(중앙선)을 구별할 수 있는 가장 좋은 컬러 채널로 판단되어 사용했습니다. 그 외 채널에 대해서 검증한 내용은 다음 글을 참고해서 적용했습니다.

 

 

GitHub - snandasena/advanced-lane-finding: Udacity Self-Driving Car Engineer.

Udacity Self-Driving Car Engineer. . Contribute to snandasena/advanced-lane-finding development by creating an account on GitHub.

github.com

 

BGR  ⏩  HLS(Hue, Lightness, Saturation) 의 경우.

        cvtColor(imgUnwarp, imgConverted, COLOR_BGR2HLS);

 

BGR  ⏩  LAB(Lightness, a, b) 의 경우.

        cvtColor(imgUnwarp, imgConverted, COLOR_BGR2Lab);

 

LAB Color Space(https://expertphotography.com/lab-color-photoshop/)

 

2. 남겨둘 채널의 픽셀값만 가져오기. (전체 3개중 1개의 채널 값만 정의하기. 예) L, A, B 중 B 채널 값만 가져오기)

1️⃣  zero Mat 변수 정의

컬러 채널 필터링 후 사용하게 될 Mat 변수를 정의합니다. 이때, 1개 채널만 핸들링하기 때문에 Mat 타입은 CV_8UC1(8비트 Unsigned, Channel 1개)로 정의합니다.

 

	Mat imgOUT = Mat::zeros(img.rows, img.cols, CV_8UC1);

 

2️⃣  이미지의 특정 채널 픽셀값을 zero Mat에 할당(포인터 개념으로 할당)

이미지의 컬러 채널을 변경 후, 변경된 이미지의 픽셀 데이터를 포인터 개념으로 접근합니다. 이미지의 포인터 데이터는 아래와 같이 초기화 할 수 있습니다. 우리가 알고 있듯이 포인터는 어레이와 같은 개념이므로, 인덱스를 부여해서 해당 인덱스의 요소(픽셀 값) 에 접근할 수 있습니다. 

 

[ 준비 : 포인터 변수 정의 ]

        cvtColor(imgUnwarp, imgConverted, COLOR_BGR2Lab);
        uint8_t *pixelPtr = (uint8_t *)imgConverted.data;

 

다음으로 원본 이미지에서 B채널의 픽셀 값만(필터링 B채널) zero Mat 변수(모든 픽셀 값 0 인 이미지이며, row column 크기는 원본과 같다.) 를 타겟으로 할당해줍니다. 이때, 원본 이미지의 컬러 채널은 픽셀의 위치 별로 [L, A, B]의 어레이 형태와 순서로 픽셀 값을 갖게 됩니다. 그렇기 때문에 B 채널의 픽셀 값인 인덱스 2 값을 이용해서 B 채널의 픽셀 값을 할당해줄 수 있습니다.

 

[ 할당 : 필터링 컬러 채널 값 ]

	// 이미지의 채널 수 
	int cn = imgConverted.channels();
    
	// L,A,B 채널 중 B 채널 값만 imgOUT 이미지에 각 픽셀에 할당
	for (int i = 0; i < imgConverted.rows; i++)
	{
		for (int j = 0; j < imgConverted.cols; j++)
		{
			imgOUT.at<uint8_t>(i, j) = pixelPtr[i * imgConverted.cols * cn + j * cn + 2];
		}
	}

 

함수를 사용해서 구현해주었기 때문에 imgOUT 변수를 리턴 해주는 것으로 마무리 할 수 있었습니다. 끝.


깃헙 링크 🔗 

    Mat filterImg(Mat imgUnwarp, int toColorChannel, int mode)
반응형