C++opencv 차선 식별 실현
선 상세도
1、
2、
(1)현재 국내외 에서 광범 위 하 게 사용 되 고 있 는 차선 검 측 방법 은 주로 두 가지 로 나 뉜 다.
(1)도로 특징 을 바탕 으로 하 는 차선 검 측;
(2)도로 모델 을 바탕 으로 하 는 차선 검 측.
도로 특징 을 바탕 으로 하 는 차선 검 측 은 주류 검 측 방법 중 하나 로 서 주로 차선 과 도로 환경의 물리 적 특징 차 이 를 이용 하여 후속 이미지 의 분할 과 처 리 를 하여 차선 특징 을 돋 보이 게 하여 차선 의 검 측 을 실현 한다.이 방법 은 복잡 도가 비교적 낮 고 실시 간성 이 비교적 높 지만 도로 환경의 방 해 를 받 기 쉽다.
도로 모델 을 바탕 으로 하 는 차선 검 사 는 주로 서로 다른 2 차원 또는 3 차원 도로 이미지 모델(예 를 들 어 직선 형,포물선 형,견본 곡선 형,조합 모델 등)을 바탕 으로 해당 하 는 방법 으로 각 모델 의 파 라 메 터 를 확정 한 다음 에 차선 의 적합 을 실시한다.이 방법 은 특정 도로 에 대한 검 측 은 비교적 높 은 정확 도 를 가지 지만 한계 가 강하 고 연산 량 이 많 으 며 실시 성 이 비교적 떨어진다.
(2)여기 서 저 는 차선 검 측 방법 을 소개 합 니 다.효 과 는 고속도로 에서 도 괜 찮 습 니 다.파손 도로,빛 의 변화 가 너무 크 고 도로 효과 가 좋 지 않 습 니 다.후속 적 으로 계속 개선(직사 도 균형 과 다 특징 융합 등)하 겠 습 니 다.여기 기본 버 전의 인터페이스 가 있 습 니 다.큰 절 차 는 다음 과 같 습 니 다.
(1)그림 그 레이스 케 일
(2)이미지 고 스 필터
(3)테두리 검출
(4)마스크 획득,관심 분야 획득
(5)호 프 변환 검 측 직선
(6)검 측 된 차선 을 분류 하여 한도 값 을 설정 하고 이미지 중앙 선 을 좌우 양쪽 차선 으로 나 누 어 vector 에 저장 합 니 다.
(7)두 직선,즉 좌우 에 두 개의 점 을 나 누고 경사 율 방정식 을 구한다.
(8)차선 의 커 브 여 부 를 확인한다.
다음은 제 가 코드 를 붙 여 드릴 게 요.
(1)헤더 파일(LaneDetector.h)
class LaneDetector
{
private:
double img_size;
double img_center;
bool left_flag = false; // Tells us if there's left boundary of lane detected
bool right_flag = false; // Tells us if there's right boundary of lane detected
cv::Point right_b; // Members of both line equations of the lane boundaries:
double right_m; // y = m*x + b
cv::Point left_b; //
double left_m; //
public:
cv::Mat deNoise(cv::Mat inputImage); // Apply Gaussian blurring to the input Image
cv::Mat edgeDetector(cv::Mat img_noise); // Filter the image to obtain only edges
cv::Mat mask(cv::Mat img_edges); // Mask the edges image to only care about ROI
std::vector<cv::Vec4i> houghLines(cv::Mat img_mask); // Detect Hough lines in masked edges image
std::vector<std::vector<cv::Vec4i> > lineSeparation(std::vector<cv::Vec4i> lines, cv::Mat img_edges); // Sprt detected lines by their slope into right and left lines
std::vector<cv::Point> regression(std::vector<std::vector<cv::Vec4i> > left_right_lines, cv::Mat inputImage); // Get only one line for each side of the lane
std::string predictTurn(); // Determine if the lane is turning or not by calculating the position of the vanishing point
int plotLane(cv::Mat inputImage, std::vector<cv::Point> lane, std::string turn); // Plot the resultant lane and turn prediction in the frame.
};
원본 파일 LaneDetector.cpp
*@file LaneDetector.cpp
*@author Miguel Maestre Trueba
*@brief Definition of all the function that form part of the LaneDetector class.
*@brief The class will take RGB images as inputs and will output the same RGB image but
*@brief with the plot of the detected lanes and the turn prediction.
*/
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "LaneDetector.h"
// IMAGE BLURRING
/**
*@brief Apply gaussian filter to the input image to denoise it
*@param inputImage is the frame of a video in which the
*@param lane is going to be detected
*@return Blurred and denoised image
*/
cv::Mat LaneDetector::deNoise(cv::Mat inputImage) {
cv::Mat output;
cv::GaussianBlur(inputImage, output, cv::Size(3, 3), 0, 0);
return output;
}
// EDGE DETECTION
/**
*@brief Detect all the edges in the blurred frame by filtering the image
*@param img_noise is the previously blurred frame
*@return Binary image with only the edges represented in white
*/
cv::Mat LaneDetector::edgeDetector(cv::Mat img_noise) {
cv::Mat output;
cv::Mat kernel;
cv::Point anchor;
// Convert image from RGB to gray
cv::cvtColor(img_noise, output, cv::COLOR_RGB2GRAY);
// Binarize gray image
cv::threshold(output, output, 140, 255, cv::THRESH_BINARY);
// Create the kernel [-1 0 1]
// This kernel is based on the one found in the
// Lane Departure Warning System by Mathworks
anchor = cv::Point(-1, -1);
kernel = cv::Mat(1, 3, CV_32F);
kernel.at<float>(0, 0) = -1;
kernel.at<float>(0, 1) = 0;
kernel.at<float>(0, 2) = 1;
// Filter the binary image to obtain the edges
cv::filter2D(output, output, -1, kernel, anchor, 0, cv::BORDER_DEFAULT);
cv::imshow("output", output);
return output;
}
// MASK THE EDGE IMAGE
/**
*@brief Mask the image so that only the edges that form part of the lane are detected
*@param img_edges is the edges image from the previous function
*@return Binary image with only the desired edges being represented
*/
cv::Mat LaneDetector::mask(cv::Mat img_edges) {
cv::Mat output;
cv::Mat mask = cv::Mat::zeros(img_edges.size(), img_edges.type());
cv::Point pts[4] = {
cv::Point(210, 720),
cv::Point(550, 450),
cv::Point(717, 450),
cv::Point(1280, 720)
};
// Create a binary polygon mask
cv::fillConvexPoly(mask, pts, 4, cv::Scalar(255, 0, 0));
// Multiply the edges image and the mask to get the output
cv::bitwise_and(img_edges, mask, output);
return output;
}
// HOUGH LINES
/**
*@brief Obtain all the line segments in the masked images which are going to be part of the lane boundaries
*@param img_mask is the masked binary image from the previous function
*@return Vector that contains all the detected lines in the image
*/
std::vector<cv::Vec4i> LaneDetector::houghLines(cv::Mat img_mask) {
std::vector<cv::Vec4i> line;
// rho and theta are selected by trial and error
HoughLinesP(img_mask, line, 1, CV_PI / 180, 20, 20, 30);
return line;
}
// SORT RIGHT AND LEFT LINES
/**
*@brief Sort all the detected Hough lines by slope.
*@brief The lines are classified into right or left depending
*@brief on the sign of their slope and their approximate location
*@param lines is the vector that contains all the detected lines
*@param img_edges is used for determining the image center
*@return The output is a vector(2) that contains all the classified lines
*/
std::vector<std::vector<cv::Vec4i> > LaneDetector::lineSeparation(std::vector<cv::Vec4i> lines, cv::Mat img_edges) {
std::vector<std::vector<cv::Vec4i> > output(2);
size_t j = 0;
cv::Point ini;
cv::Point fini;
double slope_thresh = 0.3;
std::vector<double> slopes;
std::vector<cv::Vec4i> selected_lines;
std::vector<cv::Vec4i> right_lines, left_lines;
// Calculate the slope of all the detected lines
for (auto i : lines) {
ini = cv::Point(i[0], i[1]);
fini = cv::Point(i[2], i[3]);
// Basic algebra: slope = (y1 - y0)/(x1 - x0)
double slope = (static_cast<double>(fini.y) - static_cast<double>(ini.y)) / (static_cast<double>(fini.x) - static_cast<double>(ini.x) + 0.00001);
// If the slope is too horizontal, discard the line
// If not, save them and their respective slope
if (std::abs(slope) > slope_thresh) {
slopes.push_back(slope);
selected_lines.push_back(i);
}
}
// Split the lines into right and left lines
img_center = static_cast<double>((img_edges.cols / 2));
while (j < selected_lines.size()) {
ini = cv::Point(selected_lines[j][0], selected_lines[j][1]);
fini = cv::Point(selected_lines[j][2], selected_lines[j][3]);
// Condition to classify line as left side or right side
if (slopes[j] > 0 && fini.x > img_center && ini.x > img_center) {
right_lines.push_back(selected_lines[j]);
right_flag = true;
}
else if (slopes[j] < 0 && fini.x < img_center && ini.x < img_center) {
left_lines.push_back(selected_lines[j]);
left_flag = true;
}
j++;
}
output[0] = right_lines;
output[1] = left_lines;
return output;
}
// REGRESSION FOR LEFT AND RIGHT LINES
/**
*@brief Regression takes all the classified line segments initial and final points and fits a new lines out of them using the method of least squares.
*@brief This is done for both sides, left and right.
*@param left_right_lines is the output of the lineSeparation function
*@param inputImage is used to select where do the lines will end
*@return output contains the initial and final points of both lane boundary lines
*/
std::vector<cv::Point> LaneDetector::regression(std::vector<std::vector<cv::Vec4i> > left_right_lines, cv::Mat inputImage) {
std::vector<cv::Point> output(4);
cv::Point ini;
cv::Point fini;
cv::Point ini2;
cv::Point fini2;
cv::Vec4d right_line;
cv::Vec4d left_line;
std::vector<cv::Point> right_pts;
std::vector<cv::Point> left_pts;
// If right lines are being detected, fit a line using all the init and final points of the lines
if (right_flag == true) {
for (auto i : left_right_lines[0]) {
ini = cv::Point(i[0], i[1]);
fini = cv::Point(i[2], i[3]);
right_pts.push_back(ini);
right_pts.push_back(fini);
}
if (right_pts.size() > 0) {
// The right line is formed here
cv::fitLine(right_pts, right_line, CV_DIST_L2, 0, 0.01, 0.01);
right_m = right_line[1] / right_line[0];
right_b = cv::Point(right_line[2], right_line[3]);
}
}
// If left lines are being detected, fit a line using all the init and final points of the lines
if (left_flag == true) {
for (auto j : left_right_lines[1]) {
ini2 = cv::Point(j[0], j[1]);
fini2 = cv::Point(j[2], j[3]);
left_pts.push_back(ini2);
left_pts.push_back(fini2);
}
if (left_pts.size() > 0) {
// The left line is formed here
cv::fitLine(left_pts, left_line, CV_DIST_L2, 0, 0.01, 0.01);
left_m = left_line[1] / left_line[0];
left_b = cv::Point(left_line[2], left_line[3]);
}
}
// One the slope and offset points have been obtained, apply the line equation to obtain the line points
int ini_y = inputImage.rows;
int fin_y = 470;
double right_ini_x = ((ini_y - right_b.y) / right_m) + right_b.x;
double right_fin_x = ((fin_y - right_b.y) / right_m) + right_b.x;
double left_ini_x = ((ini_y - left_b.y) / left_m) + left_b.x;
double left_fin_x = ((fin_y - left_b.y) / left_m) + left_b.x;
output[0] = cv::Point(right_ini_x, ini_y);
output[1] = cv::Point(right_fin_x, fin_y);
output[2] = cv::Point(left_ini_x, ini_y);
output[3] = cv::Point(left_fin_x, fin_y);
return output;
}
// TURN PREDICTION
/**
*@brief Predict if the lane is turning left, right or if it is going straight
*@brief It is done by seeing where the vanishing point is with respect to the center of the image
*@return String that says if there is left or right turn or if the road is straight
*/
std::string LaneDetector::predictTurn() {
std::string output;
double vanish_x;
double thr_vp = 10;
// The vanishing point is the point where both lane boundary lines intersect
vanish_x = static_cast<double>(((right_m*right_b.x) - (left_m*left_b.x) - right_b.y + left_b.y) / (right_m - left_m));
// The vanishing points location determines where is the road turning
if (vanish_x < (img_center - thr_vp))
output = "Left Turn";
else if (vanish_x >(img_center + thr_vp))
output = "Right Turn";
else if (vanish_x >= (img_center - thr_vp) && vanish_x <= (img_center + thr_vp))
output = "Straight";
return output;
}
// PLOT RESULTS
/**
*@brief This function plots both sides of the lane, the turn prediction message and a transparent polygon that covers the area inside the lane boundaries
*@param inputImage is the original captured frame
*@param lane is the vector containing the information of both lines
*@param turn is the output string containing the turn information
*@return The function returns a 0
*/
int LaneDetector::plotLane(cv::Mat inputImage, std::vector<cv::Point> lane, std::string turn) {
std::vector<cv::Point> poly_points;
cv::Mat output;
// Create the transparent polygon for a better visualization of the lane
inputImage.copyTo(output);
poly_points.push_back(lane[2]);
poly_points.push_back(lane[0]);
poly_points.push_back(lane[1]);
poly_points.push_back(lane[3]);
cv::fillConvexPoly(output, poly_points, cv::Scalar(0, 0, 255), CV_AA, 0);
cv::addWeighted(output, 0.3, inputImage, 1.0 - 0.3, 0, inputImage);
// Plot both lines of the lane boundary
cv::line(inputImage, lane[0], lane[1], cv::Scalar(0, 255, 255), 5, CV_AA);
cv::line(inputImage, lane[2], lane[3], cv::Scalar(0, 255, 255), 5, CV_AA);
// Plot the turn message
cv::putText(inputImage, turn, cv::Point(50, 90), cv::FONT_HERSHEY_COMPLEX_SMALL, 3, cvScalar(0, 255, 0), 1, CV_AA);
// Show the final output image
cv::namedWindow("Lane", CV_WINDOW_AUTOSIZE);
cv::imshow("Lane", inputImage);
return 0;
}
주 함수
#include <iostream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "LaneDetector.h"
//#include "LaneDetector.cpp"
/**
*@brief Function main that runs the main algorithm of the lane detection.
*@brief It will read a video of a car in the highway and it will output the
*@brief same video but with the plotted detected lane
*@param argv[] is a string to the full path of the demo video
*@return flag_plot tells if the demo has sucessfully finished
*/
int main() {
// The input argument is the location of the video
cv::VideoCapture cap("challenge_video.mp4");
if (!cap.isOpened())
return -1;
LaneDetector lanedetector; // Create the class object
cv::Mat frame;
cv::Mat img_denoise;
cv::Mat img_edges;
cv::Mat img_mask;
cv::Mat img_lines;
std::vector<cv::Vec4i> lines;
std::vector<std::vector<cv::Vec4i> > left_right_lines;
std::vector<cv::Point> lane;
std::string turn;
int flag_plot = -1;
int i = 0;
// Main algorithm starts. Iterate through every frame of the video
while (i < 540) {
// Capture frame
if (!cap.read(frame))
break;
// Denoise the image using a Gaussian filter
img_denoise = lanedetector.deNoise(frame);
// Detect edges in the image
img_edges = lanedetector.edgeDetector(img_denoise);
// Mask the image so that we only get the ROI
img_mask = lanedetector.mask(img_edges);
// Obtain Hough lines in the cropped image
lines = lanedetector.houghLines(img_mask);
if (!lines.empty())
{
// Separate lines into left and right lines
left_right_lines = lanedetector.lineSeparation(lines, img_edges);
// Apply regression to obtain only one line for each side of the lane
lane = lanedetector.regression(left_right_lines, frame);
// Predict the turn by determining the vanishing point of the the lines
turn = lanedetector.predictTurn();
// Plot lane detection
flag_plot = lanedetector.plotLane(frame, lane, turn);
i += 1;
cv::waitKey(25);
}
else {
flag_plot = -1;
}
}
return flag_plot;
}
마지막 으로 결과 도 한 장 더 찍 어 주세요.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
ip camera android에 액세스하고 java를 사용하여 모니터에 표시그런 다음 PC에서 다운로드 폴더를 추출해야 합니다 그런 다음 프로젝트 폴더에 다운로드한 javacv 라이브러리를 추가해야 합니다. 먼저 라이브러리 폴더를 마우스 오른쪽 버튼으로 클릭한 다음 jar/폴더 추가를 선택...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.