November 18, 2018

디바이스마트 미디어:

[47호]졸음운전 방지 시스템

Cap 2017-10-18 13-15-49-260

2017 ICT 융합 프로젝트 공모전 참가상

졸음운전 방지 시스템

글 | 성결대학교 김성중, 오태식, 여규성, 이정희

1. 심사평
칩센 자동차 주행 시의 안전은 무엇보다 운전자와 타인의 생명과 직결되는 문제이고, 이를 기반으로 기획이 이루어진 것이라 생각됩니다. 이를 각 기술의 단계별로 검토가 이루어진 내용이 좋아 보입니다. 하지만, 실제 작품을 제작 및 시연이 이루어 지지 않았습니다. 차선 검출시에 중요한 요소인 소실점 등이 추출되지 않은 경우와 같은 변수가 전혀 고려되지 않아 예상되는 상황만으로 작품 개발이 이루어졌고, 눈 깜빡임 등과 같은 상수에 가까운 사항을 검증하지 않은 점이 아쉬움이 듭니다.
뉴티씨 낮은비용으로 졸음운전을 방지하려는 노력이 좋습니다. 사람들이 이 기능을 활용하여 안전운전을 할 수 있도록 되었으면 좋겠습니다. 많은 오류 등의 처리 등에 많은 개선점이 보이며, 앞으로 연구할 것이 많은 분야로 많은 업그레이드를 예상합니다.
위드로봇 완성이 된 작품인지 보고서만으론 판단하기 어렵습니다.

2. 작품 개요

47 feature 졸음운전 (1)
졸음운전 방지 시스템
블랙박스에 졸음운전을 방지하는 기능을 더한다 .

47 feature 졸음운전 (2)

3. 작품 설명

47 feature 졸음운전 (3)
졸음운전으로 인한 사고는 잊을만하면 언론의 구설수에 오른다. 특히 큰 사고가 일어나기 쉬운 고속도로에서는 졸음운전으로 인한 사고가 많이 일어나고 있다. 고속도로는 도로 상태가 좋고 차량들의 속도가 빠르고 운전하는 시간이 길기 때문에 운전자가 졸기 쉽다.

47 feature 졸음운전 (4)
사고가 나면 대형 사고일 확률이 높은 대형차량에는 졸음운전을 방지하는 여러 가지 시스템이 갖춰져서 출시되고 고급 승용차에는 최신 기술을 사용한 졸음운전 방지 시스템이 있어 옵션으로 선택할 수 있다.
하지만 저가형 승용차에는 최근에서야 졸음운전을 방지하는 LDWS가 달린 몇몇 기종이 출시되는 등 졸음운전에 대해 많이 취약하다.
그래서 고가의 차가 아니더라도 오늘날 차량에 대다수에 설치되는 블랙박스와 보편적 기기인 스마트폰을 가지고 그와 비슷한 시스템을 구현하기로 하였다.

옵션을 추가하지 않아도 졸음운전을 방지

47 feature 졸음운전 (5)

 

아이작 IF520LD (블랙박스)

47 feature 졸음운전 (6)
· 40만원대 블랙박스
· 기본 블랙박스 기능인 상시/주차/충격 녹화 등 여러 가지 기능 제공
·  전방 추돌 경보 시스템(FCWS : Forward Collision Warning System)
▶ 전방에 있는 차량과의 거리를 측정하고 일정거리 이하가 되면 알림을 계속 울리는 시스템

·  차선 이탈 경보 시스템(LDWS : Lane Departure Warning System)
▶ 블랙박스 영상에서 차선을 인식하여 사용자의 차량이 차선을 벗어나면 알림이 울리는 시스템
▶  사용자의 차선 변경 여부를 차량의 방향지시등 점등을 통하여 알수있고 방향지시등이 점등 되었을 때는 알림을 울리지 않음
▶  방향지시등 점등 여부를 알기 위하여 별도로 차량과의 Signal 케이블 필요

· 장점 :  여러 가지 고급 기능이 들어있는 블랙박스. 졸음운전뿐만 아니라 안전 운전에 도움이 되는 기능을 원하는 사용자에게 유용하다.
· 단점 : 제품 가격이 상당히(보급형 제품의 4배) 비싸다.

뷰메이트 DL330A (졸음 방지 알림기)

47 feature 졸음운전 (1)
·  15만원대 제품
·  차량의 핸들/계기판에 설치하는 제품
·  시선 추적기술(Eye-Tracking)
▶  사용자의 안면을 촬영하는 도중 시선을 추적하여 졸음상태를 감지하는 기술

·  졸음운전이 판단 되었을시에 소리로 알림을 준다.
·  장점
: 1)  차량의 상태를 확인하는 타 제품과는 다르게 직접 사용자의 상태를 확인하는 방식으로 졸음을 감지하여 정보의 신뢰도가 높다.
: 2) 차량에 설치하는 형태라서 관리가 쉽다.

·  단점 : 제품 가격이 비싸다.

3.1. 주요 동작 및 특징

47 feature 졸음운전 (7)

47 feature 졸음운전 (8)

사용한 도구

47 feature 졸음운전 (9)

필요한 방법

47 feature 졸음운전 (10)

3.2. 전체 시스템 구성

47 feature 졸음운전 (11)
기본 기능
블랙박스(RaspberryPi)
· 차선 이탈 감지 시스템
· 차간 거리 측정 시스템
· 내부 온도 측정 센서
· 측정값을 Bluetooth를 이용하여 스마트폰에 전송

차량 ECU
· 차량의 정보를 블랙박스로 전송

스마트폰(Android Application)
· 눈꺼풀 개폐(눈 깜빡임) 감지 시스템
· 졸음 알림(스마트폰 H/W 사용)
· 블랙박스 환경설정 인터페이스

추가 기능
스마트폰(Android Application)
· 운전습관 케어(과거 주행 기록정보) 시스템
· 졸음여부를 서버에 전송
서버
· 인근에 있는 차량에 졸음운전 차량 유무를 전송
NFC 태그(스마트폰 거치대)
· 블랙박스와 스마트폰 간의 Bluetooth 페어링 보조

눈깜빡임 감지 시스템 구현 방법

47 feature 졸음운전 (12)
0. 감지 과정
① : 얼굴 인식 ② : 눈 지역 추출 ③ : 눈 깜빡임 검출 ④ : 눈 깜빡임 분류

47 feature 졸음운전 (2)

 1. 얼굴 인식
사각형 안의 픽셀 강도의 합과 주변을 비교하여 결정. 정확하게 감지하기 위해 부스팅 알고리즘 – 아다부스트 알고리즘(조사필요)가 효과적이다.

2. 눈 영역 추출
눈 위치는 기하학적으로 발견한다. 얼굴을 h라 보았을 때 보통 눈은 0.2h ~ 0.6h 사이에 있고 평균적으로 0.4h에 존재한다.

47 feature 졸음운전 (3)

3. 눈깜빡임 검출
눈은 정규화된 상호상관 방법(조사 필요)에 의해 검출된다.

47 feature 졸음운전 (4)

4. 눈깜빡임 분류
자발적으로 눈을 깜빡인 것을 분류하기 위해 분석한다. 눈 깜빡임이 250밀리초 ~ 2초 사이일 때 자발적인 컨트롤로 간주한다.

47 feature 졸음운전 (13)

눈깜빡임 검출
1. 준비사항
· 사용 기기 : 스마트폰 (SM-G930S 삼성 갤럭시S7)
· 프로그래밍 언어 : 자바
· 영상처리 api : OpenCV 3.0.0_android

2. 개요

47 feature 졸음운전 (5)
위와 같은 사진에서, 얼굴과 눈을 검출하고 깜빡임을 체크
· 얼굴로서의 특징을 모두 가지고 있다.
· 처음부터 종료시까지 계속 눈을 감고 있지 않는다.

3. 설계과정

47 feature 졸음운전 (14)
47 feature 졸음운전 (15)

눈깜빡임 검출 구현

47 feature 졸음운전 (16)

눈 깜빡임 검출 실험 Source Code
1. 흑백 변환

mGray = inputFrame.gray();
2. lbp cascade를 이용하여 얼굴 검출

mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2,
// TODO: objdetect. CV_HAAR_SCALE_IMAGE
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());

 3. 눈 영역 추출

Rect r = facesArray[i]:
eyearea_right = new Rect(r.x + r.width / 16,
(int) (r.y + (r.height / 4.5)),
(r.width – 2 + r.width / 16) / 2,
(int) (r.height / 3.0));
eyearea_left = new Rect (r.x + r.width / 16 + (r.width – 2 + r.width / 16) / 2,
(int) (r.y + (r,height / 4.5)),
(r.width – 2 + r.width / 16) / 2,
(int) (r.height / 3.0));

 4. harr cascade를 이용하여 눈 검출

clasificator.detectMulti Scale(mROI, eyes, 1,15, 2,
Objdetect.CASCADE_FIND_BIGGEST_OBJECT
Objdetect .CASCADE_SCALE IMAGE, new Size(30, 30),
new Size());

 

눈의 위치 저장

lastEyes_L[lastEyes_num] = new Point(
(((matchLoc_tx_L.X + matchLoc_ty_L.x) / 2.0) – eyearea_left.x)/ facesArray[0] .width
(((matchLoc_tx_L.y + matchLoc_ty_L.y) / 2.0) – eyearea_left.y / facesArray[0] . height
}; // 눈 가운데의 좌표에서 두 영역 좌표를 깨고 얼굴 크기로 나누어서 상대좌표가 아닌 절대좌표로 만듬
lastEyes_R[ lastEyes_num] = new Point(
(((matchLoc_tx_R.x + matchLoc_ty_R.x) / 2.0) – ewearea_right.x )/ facesArray[0] .width ( (matchLoc_tx_R.y + matchLoc_ty_R.y) / 2.0 – eyearea_right.y / facesArray[0] . height
};
lastEyes_num++;
if(lastEyes_num == MAX_EYE_LEARN){
두 눈 모두 지정한 횟수 이상 높은 검출 했을 경우
insortionSort (lastEyes_L, 0);
insortionSort( lastEyes_R, 1);
}

삽입정렬로 정렬 후 오검출 제외

private void insortionSort (Point lastEyes[], int lef tRight) {
int i, j;
double ce;
for (i = 1; i <= NAX_EYE_LEARN -1; i++){
ce = lastEyes[i].x:
j =i – 1;
while( i >= 0){
if (lastEyes[J].x > ce){
lastEyes[j + 1].x = lastEyes[J].x:
j– ;
} else break;
lastEyes[] + 1].x = ce: }
// 삽입정렬
if (leftRight == 0) {
double tempX = 0, tempY = 0;
for (int k = 4; k< 16 : k++)
{ 오차라 판단하는데 0~3, 16~20을 제외하고 평균을 구함
Temp X = tempX + lastEyes[k].x;
Temp Y = tempy + lastEyes[k].y;
}
Temp X = Temp X / 12.0;
Temp Y = Temp Y/ 12.0;
eyeTemplete_L = new Point(temp X, temp Y);
abc_l= eyelenplete_L;
}

다음 프레임에서 옵티컬 플로우로 추적

Video, oalooptionlFlowPyrLK(tmp_last, frame, mat_last, tempMat, Status, err); //포티컬 플로우로 추적
Point[] parray2 = tempMat toArray():
리턴되어 저장될 변수

4. canny 변환

Imgproc.Canny(temp, temp, 50, 100);

5. 허프변환으로 기울기 계산

// 얼굴의 너비에 따라서 최소 선분 길이 지정
if (facesArray[0] .width > 700) line = 1;
else if (facesArray(0) ,width <700 && facesArray[0] .width > 650) Line = 0.92;
else if (facesArray(0).width <650 && facesArray(0).width > 600) Line = 0.84;
else if(facesArray[O).width <600 && facesArray[O).width > 550) Line = 0.76;
else if(facesArray(0) .width <550 && facesArray[0] .width > 500) Line =0.68;
else if (facesArray(0) .width <500 && facesArray[0] .width > 450) Line = 0.60;
else if(facesArray[0] .width <450 && facesArray[0] .width > 400) Line = 0.52;
else if(facesArray[O).width <400 && facesArray[0] .width > 350) Line = 0.44;
else if (facesArray[0] .width <350 && facesArray[0] .width > 300) Line = 0.36;
else if (facesArray[0] .width <300 && facesArray[0] .width > 250) Line = 0.28;
else if (facesArray[0] .width <250) line = 0.20;
Imgproc.HoughLines(temp, mLines, line, Math.PI/ 180.0,facesArray[0] .width/30);

기울기에 따라 다른 값 저장

private void insortionSort (Point lastEyes[], int lef tRight) {
int i, j;
double ce;
for (i = 1; i <= NAX_EYE_LEARN -1; i++){
ce = lastEyes[i].x:
j =i – 1;
while( i >= 0){
if (lastEyes[J].x > ce){
lastEyes[j + 1].x = lastEyes[J].x:
j– ;
} else break;
lastEyes[] + 1].x = ce: }
// 삽입정렬
if (leftRight == 0) {
double tempX = 0, tempY = 0;
for (int k = 4; k< 16 : k++)
{ 오차라 판단하는데 0~3, 16~20을 제외하고 평균을 구함
Temp X = tempX + lastEyes[k].x;
Temp Y = tempy + lastEyes[k].y;
}
Temp X = Temp X / 12.0;
Temp Y = Temp Y/ 12.0;
eyeTemplete_L = new Point(temp X, temp Y);
abc_l= eyelenplete_L;
}

눈 깜빡임 체크

if (blinkFlag == true){
if (nn > -9.5) blinkNotNum++; // 일정 수치 이상으로 올라가면 눈떴음 체크 변수 ++
if (blinkNotNum >= 3){ // 1.7초 안에 3프레임 이상 눈을 뜬게 발견될 경우
blinkFlag = false; // 눈떴음
blinkNotNum = 0; // 체크변수 = 0
blinkFlagTime = 0; // 시간 초기화
}
Long tmepTime = System. current Timellillis();
if (tmepTime – blinkFlagTime > 1700) { //1.7초 이상 눈 감고있으면
Vibrator vb=(Vibrator)getSystemService(VIBRATOR_SERVICE); // 진동을 줄 변수
vb. vibrate(100); // 진동
blinkNotNum = 2;
}
}
if(nn < -12.5 && blinkFlag == false) { // 일정수치 이하(눈감았다 판단)
blinkFlag = true; // 감았다고 판단
blinkFlagTime = System.ourrent Timelillis(); // 그때부터 시간을 잰다.
blinkNotNum = 0; 체크변수 = 0
}

눈 깜박임 검출 실험 결과

47 feature 졸음운전 (17)

문제점 분석 및 해결방안

47 feature 졸음운전 (18)

4. 단계별 제작 과정
4.1. 차선 인식

47 feature 졸음운전 (6)
차선을 인식하기 위해서는 먼저 차선의 특징을 알 필요가 있다. 졸음운전이 일어나기 쉬운 고속도로에 존재하는 차선은 흰색/황색/청색이 있다. 이 3가지 종류의 차선을 특정하기 위하여 영상에서 흰색, 황색, 청색 영역을 추출한다. 차선의 종류는 ① : 흰색 차선(일반), ② : 황색 차선(중앙/끝), ③ : 청색 차선(버스전용) (*경부고속도로 상부) 이다.

47 feature 졸음운전 (19)

흰색영역 추출 : 흰색영역을 추출하였을 때 차선이 아닌 다른 부분도 추출됨을 볼 수 있다.

47 feature 졸음운전 (20)

차선 특정 : 색영역을 추출하여 얻어낸 데이터를 바탕으로 차선으로 추정되는 객체를 특정한다.

4.2. 차선 이탈 감지

47 feature 졸음운전 (21)
차선 내부에서 잘못된 방향
운전자가 졸음으로 인하여 차량의 진행 방향이 차선과 동일하지 않을 경우. 차선 객체들의 연장선(빨강선)이 차량의 중심(파랑선)과 크게 어긋나 있어 이를 이용하여 차선 이탈을 판단할 수 있다.

47 feature 졸음운전 (22)

차선을 밟은 경우
차량의 제어가 불가능하여 차선을 밟은 경우. 차선객체가 차량의 중심(파랑선)에 걸쳐 있음으로 이를 이용하여 차선 이탈을 판단할 수 있다.

4.3. 차선 검출
준비사항 :
사용 기기 : RaspberryPi 3, Logitech Webcam C270
프로그래밍 언어 : C++
영상처리 api : OpenCV 3.1.0

개요

47 feature 졸음운전 (23)
풍경이 펼쳐지고 있을 때, 차선만을 검출하는 방법에 대하여 일반적인 도로의 모습에서 차선의 특징을 정의 한다.
· 차선의 색은 흰색, 노란색 등이고, 도로의 색과 큰 차이가 난다.
· 차선은 일정한 두께가 있다.
· 차선들은 하나의 소실점에서 만난다.

설계 과정

47 feature 졸음운전 (24)

47 feature 졸음운전 (25)

47 feature 졸음운전 (26)

차선 검출 구현
1. Gray Scale 변환
· cv::cvtColor 함수를 사용하여 Gray Scale 변환
· 0. ~ 1. (float) scale로 변환하기 위해
· cv::Mat.convertTo 함수 사용

2. edge의 크기, 방향을 검출
· cv::Sobel 함수를 사용하여 x축, y축으로 미분
· cv::cartToPolar 함수에 x/y축으로 미분한 값을 넣어 edge의 크기(magnitude)와 방향(orientation)을 구한다.

3.edge가 각 구역에서 최대치가 되는 영역 검출
· magnitude의 정보가 담긴 객체의 값 중에 left < middle > right 가 되는 middle 값만 추출

4. 차선 후보 검출
· 영상의 아래쪽으로 갈수록 커지고 위로 갈수록 작아지는 최저 차선폭을 지정
· 같은 y값을 가지는 인접한 두 지점간 거리와 해당되는 y축의 최저 차선폭을 비교한다.
· 두 지점의 magnitude 값이 유사한지 검사한다.
· 위의 조건을 만족하였을 시에 두 지점의 orientation 값이 160 ~ 200도 차이가 나는지 비교한다.
· 모든 조건을 만족하면 두 지점의 중심점을 차선후보점으로 지정한다.

5. 선 검출
· cv::HoughLinesP 함수에 이전 연산의 결과로 나온 객체를 입력하여 직선 좌표값을 뽑아낸다.

6. 소실점 계산
· RANSAC 알고리즘을 이용하여 소실점을 찾아낸다.
· 소실점으로 향하는 직선만 차선으로 인정한다.

차선 검출 실험 Source Code
1. Gray Scale 변환

// 0 ~ 255 그래미 스케일로 변환한다.
Mat gray = Mat(source.rows, source.cols, CV_BUC1);
cvt color( source, gray, CV-BGR2GRAY);

// 0. ~1. 그래미 스케일로 변환한다.
Mat gray32 = Mat::Oness source.ros, source.cols, CV-32FC1).
gray. convert Tof gray32, CV_32F, 1.01 255.0);

// 이미지를 부드럽게 만든다.
Mat smooth = Mat:; ones( source, rows, source.cols, CV-32FC1);
GaussianBlurgray32, smooth, Size(5,5), 2.0.2.0);

2. edge의 크기, 방향을 검출

// Sobel 연산자로 이미지를 x, y방향으로 미분한다. 즉, edge 검출.
Mat sobei x, sobel y:
Sobel( smooth, sobe X, CV_32F, 1, 0);
Sobel( smooth, sobe Y, CV_32F, 0, 1);
// Edge의 magnitude와 orientation을 계산한다.
Mat mag = Mat::ones( source.rows, source.cols, CV_32FC1);
Mat ori – Mat::ones( source.rows, source.cols, CV_32FC1);
cartToPolar( sobe IX, sobely, mag, ori);

3. 차선 후보 검출

for(int j = i + 1 ; j < (int)tmp.size(); j++)
{
int width = tmp[j].x – tmp[i].x;
if(lane_width)lo <= width && width <= lane_width_hi)
{
float mag_err = (tmp[j].mag – tmp[i].mag) / (tmp[j].mag + tmp[i].mag); //크기 차
float ori_err = DeltaRad(DeltaRad(tmp[j].ori, tmp[i].ori, M_Plf);// 방향 차

if((-mag_threshold < mag_err && mag_err < +mag_threshold) && (-ori_threshold < ori_err && ori_err < +ori_threshold))
{
int x_mid = (tmp[j].x + tmp[i].x / 2;
float mag_avg = (tmp[j].mag + tmp[i].mag) / 2.f;
// 평균을 낼 때 edge에 수직인 각을 pi/2를 더해 edge에 평행하게 바꾼다.
float ori_avg = (tmp[j].ori + tmp[i].ori / 2.f + M_Plf;

if(mag_avg <= 1.)
dst.at (h, x_mid) = 255;
//d[x_mid] = (mag_avg <= 1.) ? (int)(mag_avg+255) ; 255;

// For Debugging : 이미지 상에 Lane 후보들을 표시한다.
circle(source, Point(x_mid. h), 2, CV_RGB(0,0,255));
}
}

4. 선 검출

//Lnae 후보 점들을 기록할 이미지를 만든다.
Mat lane = Mat::zeros(source, rows, source.cols, CV_BUC1);

//Lane의 후보가 될 점들을 찾는다.
LaneCandidate(mag, ori, lane);

//Lane 후보 점들을 저장할 공간 확보
vector(sLine> cand;
cand. reserve(1000);

//http://doce.opencv.org/2.4/modules/imgproc/doc/feature_detection.html
vector lines;
HoughLinesP(lane, lines, 1, CV_PI/180,5,2,10);

//Mat hought = Mat::zeros(source, rows, source.cols, CV_BUC1);
for(int i = 0; i < lines. size(); i++)
{
Point start = Point(lines[i][0], lines[i][1]);
Point end = Point(lines[i][2], lines[i][3]);

cand.push_back(sLine(start.x, start.y, end.x, end.y));

// For Debugging
line(source, start, end, CV_RGB(255,0,0),3,8);
line(hough, start, end, CV_RGB(255,255,255),3,8);

4. 소실점 찾기

double ransac_Vanishing-point( vector &data, sPoint &model, double distance_threshold)
Const int no_samples = 2;
if (data.size() < no_samples) {
return 0..
Vectors samples:
Vectors sPoint est imated_model: double max_cost = 0..
int max_iteration = (int )1 + log(1. – 0.99) log(1. – pow(0.5, no_samples)));
for (int i = 0; i<max_iteration: j++){<br=”"> if(i==0){
//처음 한 번은 미전 스탭의 모델로 알고리즘을 수행한다.
est imated_model = model:
else {
//1. Hypothesis

// 원본 데 미터 에서 임의로 N개의 샘플 데이터를 고른다.
Samples = get_samples (no_samples, data);

//이 데이터를 정상적인 데이터로 보고 모델 파라미터를 예측한다. estinated_model = Compute_model-parameter (samples):

// 2. Verification
//원본 데이터가 예측된 모델에 잘 맞는지 검사한다.
inliers.clear( ) double Cost = model-Verification(inliers, estimated_model, datadistance_threshold}}
만일 예측된 모델이 잘 맞는다면, 이 모델에 대한 유효한 데이터로 새로운 모델을 구한다.
if (max_cost < cost) {
max_cost = Costs;
model = compute_model-parameter (inliers):
}
}
return maX_Cost:
}

차선 검출 실험 Source Code

1. 차선 후보점 검출

47 feature 졸음운전 (7)

2. 직선 검출

47 feature 졸음운전 (8)

3. 소실점 계산, 최종 결과

47 feature 졸음운전 (9)

4. 실제 Webcam을 사용한 실험 결과
- 직선 도로 상황

47 feature 졸음운전 (27)

- 곡선 도로 상황

Cap 2018-07-11 15-50-23-792

네트워크 통신
준비사항
사용 기기 : 스마트폰
프로그래밍 언어 : 자바
통신 방식 : FCM (FireBase Cloud Message)

47 feature 졸음운전 (28)

개요
위와 같이 라즈베라파이와 안드로이드 스마트폰 사이의 통신을 조사하여 FCM이라는 클라우드 메시지 방식을 테스트해본다. FCM이란 메시지를 무료로 안정적으로 전송해줄 수 있는 메시지 전송 시스템이다.

설계과정
1. 안드로이드 app에 firebase를 추가한다. (패키지 이름, 앱 닉네임, 빈칸)
2. 자동적으로 google-services.json이 다운로드되면 프로젝트의 메니페스트가 있는 경로에 복사한다.
3. 서버에 프로젝트를 등록하고 sener ID와 server KEY를 얻는다. (Project>Settins>Cloud Messaging에서 체크
프로젝트수준 build.gradle 설정
앱 수준 build.gradle 설정
4. 프로젝트 수준과 앱 수준에서의 gradle을 전부 설정해준다.
5. 각 기기가 서버에 접속할 수 있게 토큰을 생성해준다.
6. 메시지 수신 시 이벤트로 노티피케이션과 진동을 준다.
7. 메시지 송신 시 서버로 메시지를 전송한다.

FCM 구현 및 소스코드
1. 토큰 생성
서버에서 해당 프로젝트의 어플 사용자임을 인증하고 토큰을 받는다. FirebaseInstanceId.getInstance().getToken() 메소드를 이용하여 해당 기기의 토큰을 생성한다. okhttp3의 Request 메소드를 이용하여 토큰을 서버에 전송한다.

// [START refresh_token] @Override public
void onTokenRefresh () {
// Get updated Instance ID token.
String token = FirebaseInstanceId.getInstance().getToken();
// 생성등록된 토크를 개인 앱서버에 보내 저장해 두었다가 뭔가를 하고 싶으면 할 수 있도록 하다.
sendRegistrationToServer (token);
}

private void sendRegistrationToServer (String token) {
// Add custom implementation, as needed.
OkHttpClient client = new OkHttpClient ();
RequestBody body = new FormBody.Builder ()
.add(“Token”, token) .build();
//request Request request = new Request. Builder (0)
. url(“http://https://lastproject-c8250.firebaseio.com”) -post (body)
.build();
try {
client.newCall (request) .execute();
} catch (IOException e) {
e.printStackTrace();
}
}

2. 메시지 수신 시

// [START receive_message] @Override
public void onMessageReceived (RemoteMessage remoteMessage) {
sendNotification (remoteMessage.getData().get (“message”)); vibrator vide;
vide = (vibrator) qetSystemService (Context.VIBRATOR SERVICE) ; vide.vibrate (1000);
}
private void sendNotification (String messageBody) {
Intent intent = new Intent (this, MainActivity.class); intent.addFlags (Intent. FLAG_ACTIVITY CLEAR TOP); PendingIntent pendingIntent = PendingIntent.getActivity (this, 0 /* Request code */, intent,
Pending Intent. FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri (RingtoneManager.TYPE_NOTIFICATION) ; NotificationCompat. Builder notificationBuilder = new NotificationCompat. Builder (this)
.setSmallIcon (R. mipmap.ic_launcher) .setContentTitle (“FCM Push Test”) .setContentText (messageBody) .setAutoCancel(true) .setSound (defaultSoundUri) .setContentIntent (pending Intent);
NotificationManager notificationManager =
(NotificationManager) getSystemService (Context. NOTIFICATION_SERVICE);
notificationManager.notify (0 /* ID of notification */, notificationBuilder.build(0);

notificationManager. 메소드를 이용하여 받은 메시지를 띄운다. Vibrator로 진동을 준다.

3. 메시지 송신 시
databaseReference.메소드를 이용하여 서버의 데이터 베이스에 메시지를 쓴다.

final DatabaseReference database Reference = firebaseDatabase.getReference (); sendButton.setOnClickListener(new view.OnClickListener() {
@Override public void onClick(View v) { Chatpata chatData = new ChatData (editID.getText().toString(),
editText.getText().toString());
// 유저 이름과 메세지로 chatdata 만들기
databaseReference.child (“message”).push().setValue (chatData);
// 기본 database 하위 message라는 child에 chatdata를 list로 만들기
editText.setText (” “);
String a = editText.getText().toString(); if (a.equals(“”)) {
editText.setText(“”);
else
editText.setText (“”); listview.setTranscriptMode (AbsListView. TRANSCRIPT_MODE ALWAYS SCROLL);
// 메시지를 보낼때 제일 상단에 출력이 되게끔 한다.
}
});
databaseReference.child (“message”).addChildEventListener(new ChildEventListener() {
// message는 child의 이벤트를 수신합니다.
@Override public void onChildAdded (DataSnapshot data Snapshot, String s) {
Chatpata chatData = datasnapshot.getValue (ChatData.class);
} chatData를 가져오고
adapter.add (chatData.getUserName () + “:” + chatData.getMessage ());
// adapter에 추가합니다.
}
});
FirebaseMessaging.getInstance().subscribeToTopic (“news”); FirebaseInstance(d.getInstance().getToken();

FCM 실험 결과

47 feature 졸음운전 (29)

제품 모형 제작
1. 준비 사항
제작 툴 : 스케치업, Creator K, 3DS Max
사용한 제작도구 : 3D 프린터
3D 프린터등을 이용하여 모형이나 외관 제작에 대해 조사한다. 여러 제작 툴을 사용해보고 가장 알맞은 제작 툴을 결정한다. 결정된 제작 툴로 테스트 모형을 출력해본다.

2. 제작 과정
1. 레이아웃 설계 및 제작 – STP
2. Creator K 호환 가능한 파일로 변환한다. – OBJ
3. Creator K를 통해 G-Code를 생성하고 프린팅을 시작한다.

3. 모형 제작 실험 결과

47 feature 졸음운전 (30)

문제점 분석 및 해결방안
뭉침으로 인한 쓰레기 값 출력 : 내부 구조까지 정확한 설계를 해야한다고 판단

4. 진행상황

47 feature 졸음운전 (31)
5. 향후 계획
라즈베리파이 – 고해상도에서 빠르게 검출할 수 있도록 최적화
스마트폰 – 눈 깜빡임 검출 부분 상세 조사
네트워크 – 라즈베리파이와 스마트폰 간의 블루투스 통신을 조사
외관 – 3ds max 프로그램을 더 공부하여 모형 제작

5. 참고문헌
옵티컬플로우 예제 : http://me10.sblo.jp/article/88289624.html
옵티컬플로우 함수 설명 : http://mycpp.blog.me/120110317337
opencv에서 옵티컬플로우 : http://blog.naver.com/hms4913/220126252051
옵티컬플로우 사용예제 : http://cafe.naver.com/opencv/38181
canny edge 기초설명 : http://carstart.tistory.com/188
자바에서 canny edge 사용 : http://stackoverflow.com/questions/24174868/edge-detection-using-opencv-canny
허프변환 기초설명 : http://blog.naver.com/dusrb2003/220290145675
허프변환 사용예제 : https://blog.zaven.co/opencv-advanced-android-development-edge-detection/
허프변환 사용예제 : http://stackoverflow.com/questions/7925698/android-opencv-drawing-hough-lines
설계/구현 과정 : http://blog.daum.net/pg365/200
환경 구축 : http://webnautes.tistory.com/916
언어간 함수변환 : http://lispro06.woweb.net/?mid=app&page=21
구글 firebase : https://console.firebase.google.com/
파이썬 채팅 앱 to firebase : https://corikachu.github.io/
안드로이드 UDP이용 메시지 전송예제 :

http://blog.naver.com/PostView.nhn?blogId=chandong83&logNo=220931445463&categoryNo=22&parentCategoryNo=0&viewDate=&currentPage=1&postListTopCurrentPage=1&from=postView

FCM으로 메시지 전송 구현 :

http://blog.naver.com/PostView.nhn?blogId=cosmosjs&logNo=220739141098&categoryNo=0&parentCategoryNo=56&viewDate=&currentPage=1&postListTopCurrentPage=1&from=search

안드로이드 FCM 샘플 : http://blog.naver.com/zic325/220719729251
Fire Base DataBase 기초 :

http://blog.naver.com/yoonhok_524/220918425133

스케치업 위키백과 : https://ko.wikipedia.org/wiki/%EC%8A%A4%EC%BC%80%EC%B9%98%EC%97%85
Creator K 사용자 가이드 http://print3dison.cafe24.com/board/free/read.html?no=816&board_no=1
3ds 맥스 위키백과 :

https://ko.wikipedia.org/wiki/3ds_%EB%A7%A5%EC%8A%A4

눈 깜빡임 관련 알고리즘 :

http://link.springer.com/article/10.1007/s10209-011-0256-6

안드로이드 눈깜빡임 감지 :

http://romanhosek.cz/android-eye-detection-and-tracking-with-opencv/

 

 

 

 

 

Leave A Comment

*