-
Notifications
You must be signed in to change notification settings - Fork 3
Milal_ProjectBlog
- 소외된 휠체어 사용자
- 휠체어 사용자를 위한 정보는 어디에?
- 왜 네이티브 앱 일까?
- Android 플랫폼의 변화: 이젠 Kotlin
- Json, Jsoup
- Tensorflow란
- Inception V3
- Android와 Tensorflow 연동
- 이미지 분류 알고리즘
- 안드로이드 & 데이터 베이스 연동방법
- 주요 코드
2017년, 대한민국의 도시 문화는 이미 눈부시게 발전하였다. 세계 어디를 보아도, 우리나라처럼 버스와 지하철로 도시 어디든 누빌 수 있고, 늦은 시간에도 즐길 거리 먹을거리가 즐비하고, 치안 또한 훌륭한 이런 곳은 흔치 않다.
하지만 이러한 멋진 도시를 누릴 권리를 박탈당한 사람들이 있다. 바로 휠체어 사용자들이다. 무겁고 큰 바퀴를 몸에 달고 움직여야 하는 휠체어 사용자들에게 이 도시는 여전히 너무도 불친절하다. 그 이유는 두 가지인데
첫째는 계단 등의 물리적인 이유로 출입이 불가능한 시설이 많기 때문이고, 둘째는 출입이 가능한 시설이라도 그 사실을 파악할 수 있는 방법이 제한적이기 때문이다.
휠체어 사용자들이 어떤 시설을 이용하기 위해서는 시설의 입구의 형태(문턱이나 경사로가 있는지, 계단이 없는지, 휠체어가 들어갈 만큼 넓은지 등)와 주차장, 장애인용 화장실의 여부 등의 정보가 필요하다. 휠체어 사용자는 일상에서 가볍게 외식을 하고 싶은 순간에도 이러한 시설 정보들이 확인되지 않는 한, 새로운 식당을 찾아갈 수 없다.
2016년 10월, UN은 ‘주거 및 지속가능한 도시발전에 관한 유엔회의’에서 빈민과 약자를 위한 도시인 ‘포용도시’라는 의제를 던졌다. 지속가능한 도시개발은 물론이요, 도시에 사는 어떠한 시민도 도시 서비스에 대한 접근에서 배제가 되어서는 안 된다는 개념이다. 하지만 휠체어 사용자들은 ‘정보’가 없다는 이유로, 많은 도시 서비스 앞에서 문전박대 당하고 있다.
휠체어 사용자들은 결국 어떠한 시설이 ‘휠체어가 들어갈 수 있는지 없는지에 대한 정보’가 필요하다. 이러한 정보를 제공하고자 하는 다음과 같은 다양한 노력들이 있지만, 모두 큰 한계점들이 있다.
휠체어 사용자들 스스로 만든 정보 공유 커뮤니티(포털사이트 카페, 밴드 등)들이 이미 대부분 각 지역마다 있다. 하지만 어느 하나도 제대로 활성화된 곳이 없다. 왜냐하면 어떤 지역에 있는 시설에 대한 정보가 이미 많이 쌓여있지 않은 이상, 그곳에 가서 검색해봤자 자료가 없을 가능성이 높기에 결국 지속적으로 사용자가 오도록 할 수 없다. 하나의 지속적인 플랫폼이 없기에, 휠체어 사용자들은 시설을 이용한 후 후기를 공유하고 싶더라도 공유할 수 없다.
위와 같이 휠체어 사용자를 위한 정보제공을 하는 서비스들이 허술하기에 많은 휠체어 사용자들은 그냥 블로그나 포털사이트들을 검색하며 자신들이 원하는 정보를 찾는 경우가 많다. 하지만 수많은 글 중 어느 글에 입구사진이 있는지, 주차장 여부에 대한 정보가 있는지 알 수 없으므로 검색 시간이 많이 소요된다. 또한 글을 쓴 글쓴이는 대부분 휠체어 사용자가 아니기에 그들의 입장을 고려한 상세한 정보를 알 길이 없다. 가령, 어느 포스팅에서 식당의 입구사진을 보고 들어갈 수 있겠다고 판단을 하고 방문을 하더라도, 내부 문에 있는 또 다른 문턱을 발견할 수도 있다.
서울, 부산, 대구와 같은 대도시들은 지자체에서(또는 외부 단체를 지원함으로써) 휠체어 사용자를 위한 시설정보 제공 사이트가 있다.
하지만 이런 사이트들은 운영하는 몇몇에 의해서만 시설정보가 제공되기에 그 수가 턱없이 부족하다. 대구시의 웹사이트만 보더라도, 대구시 내에 등록된 전체 일식 음식점 수가 1531개 인데(대구광역시 공공데이터 포털 제공), 사이트에 등록된 식당 수는 고작 18개뿐이다. 또한 식당은 하루에도 수백 개가 망하고 또 새로 생기는데, 공공사이트는 꾸준하게 업데이트를 하고 있지 않기에 정보의 신뢰도가 많이 떨어진다. 지자체는 또한 도시 내 대부분 시설에 대한 정보를 DB화하여 가지고 있는데, 이는 일반 사용자가 접근하기 어렵고, 휠체어 이용성에 대한 정보가 없다.
위의 3가지의 방안의 한계에서 알 수 있듯이 휠체어 사용자들을 위한 정보는 어딘가 있더라도 찾기가 어렵고, 또 그들만의 정보가 모여드는 지속적인 플랫폼이 없다.
각 도시의 휠체어 사용자들이 다 함께 공유하는 플랫폼이 필요하다. 왜냐하면, 휠체어 사용자들에게 가장 좋고 믿을 만한 정보는 ‘휠체어 사용자, 또는 휠체어 사용자의 이웃’이 스스로 생산한 정보이기 때문이다.
분산된 커뮤니티에서 활동하거나, 아직 활동하지 않는 휠체어 사용자들을 하나로 모을만한 ‘유인책’이 있는 플랫폼이 필요하다.
기존에 포털사이트를 돌며 입구 사진, 내부 모습, 주차장 위치를 찾느라 소요하고 있는 검색 시간을 파격적으로 단축시켜야 한다.
지자체가 시설에 대한 정보를 받을 때, 휠체어 이용성에 대한 정보도 제공받고, 그 정보에 쉽게 접근할 수 있다면 휠체어 사용자들에게 매우 유용할 것이다.
우리가 흔히 사용하는 스마트폰의 어플리케이션에는 개발 방식에는 크게 3가지가 있습니다. 바로 네이티브 앱, 웹 앱, 하이브리드 앱 방식인데요, 이 3가지 방식의 장단점 및 특징 들은 가스리 프로젝트 블로그 에서 잘 설명하고 있으니 여기서는 넘어가도록 하겠습니다.
이 중 저희가 택한 개발 방식은 바로 네이티브 앱이고요, 가장 대표적인 스마트폰 OS인 Android와 iOS 중 Android 기반의 네이티브 앱입니다. 네이티브앱의 장점은
- 빠른 로딩 속도
- 인터넷 연결 없이도 기능 작동 가능
- 스마트폰의 하드웨어의 효과적 활용
을 들 수 있습니다.
저희 프로젝트의 대표적 기능인 '입구 이미지 분석'과 '리뷰 남기기'를 구현하기 위해서는 빠른 반응 속도가 필요했고, 리뷰기능을 구현하기 위해 스마트폰의 하드웨어인 카메라와 연동하여 사진을 가져올 수 있게 하는 것이 필수적이었습니다. 또한 인터넷 연결이 없을 때에도 user가 미리 저장한 정보 정도는 제공할 수 있으면 좋겠다는 의견도 있었죠.
물론, 아이폰을 호환하기 위해서는 iOS 버전의 앱을 따로 만들어야 한다는 번거로움이 있지만, 저희는 네이티브 앱이 가진 장점이 이 프로젝트에 가장 적합하다고 판단하였습니다.
이 자료는 시장 조사 업체 가트너가 발표한 자료로 2017년 기준, 스마트폰 운영체제의 시장 점유율을 보여줍니다. 보시다시피 현재, Android가 86%, iOS가 14%로 스마트폰 운영체제는 사실상 이 두 가지로 양분되었습니다. 저희는 그리하여 스마트폰 시장의 가장 큰 부분을 차지하고 있는 Android 플랫폼 기반의 네이티브 앱으로 접근하게 되었습니다.
Android 어플리케이션을 개발하는 언어를 JAVA로 알고계시는 분이 아직 많으실텐데요, 2017년 5월 18일, 구글은 Android의 공식 언어는 이제 Kotlin 이라는 중대 발표를 합니다.
Kotlin은 JetBrains사에서 만든 오픈소스 개발 언어입니다. Kotlin의 장점은 간결함, 안전함, 다재다능함, 호환성등을 들 수 있습니다. Java로 개발하는 것보다 코드의 양이 줄어들고, 널 포인트 예외(NullPointerExceptions)에 대한 안전성이 증가합니다. 또한 Java와 함께 사용할 수 있고, JVM이 실행할 수 있는 바이트 코드로 컴파일이 됩니다.
Kotlin의 장점에 대해 코드를 통해 간단히 살펴보겠습니다.
Java에서는 Click시에 doSomething()을 하는 버튼을 구현할 때, 다음과 같이 썼다면
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
doSomething();
}
});
(생성자 new를 이용하여 리스너를 만들고, 그 안에 메소드를 정의하는 방식)
button.setOnClickListener {
doSomething()
}
Kotlin에서는 이렇게 바뀝니다. 훨씬 직관적이고 간결하죠!
또한 Kotlin에서는 ?를 통해 nullable 조건을 달 수 있도록 함으로써 null안정성을 증가시켰습니다.
val maybeString: String? = “Hello"
maybeString?.length
(출처: https://academy.realm.io/kr/posts/kotlin-does-java-droidcon-boston-2017-gonda)
물음표는 바로 'null일 수 있다' 는 것을 말합니다. 이렇게 쓸 경우 객체가 null이 아닌 경우 .length를 호출하고, 아니면 null을 반환합니다.
Java와의 호환도 완벽합니다. 아래와 같이 Kotlin의 메소드를 그대로 Java에서 call하거나, 그 반대도 가능합니다.
// Calling Java code from Kotlin
class KotlinClass {
fun kotlinDoSomething() {
val javaClass = JavaClass()
javaClass.javaDoSomething()
println(JavaClass().prop)
}
}
==================================
// Calling Kotlin code from Java
public class JavaClass {
public String getProp() { return "Hello"; }
public void javaDoSomething() {
new KotlinClass().kotlinDoSomething();
}
}
Kotlin 공식 블로그에 의하면, Kotlin의 목표는 풀스택 웹 개발, Android와 iOS앱, 그리고 임베디드와 IoT등 모든 개발을 다양한 플랫폼에서 Kotlin으로만 개발할 수 있도록 하는 것이라고 한만큼 Kotlin은 꾸준히 영역을 넓혀가며 발전해가고있는 추세입니다.
저희가 Android 개발을 들어간 시점에는 Kotlin이 발표되지 않았었고, 얼마 전까지만 해도 참고할만한 소스가 많지 않았기에 저희 프로젝트에는 적용하지 않았지만, 앞으로 Android를 다루는 개발자라면 Kotlin의 사용법을 익히는 것은 필수라 할 수 있겠습니다!
웹 크롤링이란 컴퓨터 소프트웨어 기술로 웹 사이트들에서 원하는 정보를 추출하는 것을 의미합니다.
웹은 기본적으로 HTML 형태로 되어 있습니다. 그렇기에 태그를 이용하여 정형화 되어있고, 규칙성이 있습니다. 이러한 규칙을 분석하여 우리가 원하는 정보만을 뽑아오는 것입니다.
저희 프로젝트에서는 공공사이트를 크롤링 하여, 휠체어 사용자들이 필요로 하는 정보만을 어플리케이션에 나타내어 주기 위해 이 기술을 사용하였습니다. 광역시 같은 대도시에서는 지방자치단체에서 휠체어 사용자들을 위한 시설정보를 제공하는 웹페이지를 운영하는 곳이 있는데요, (대표적으로 서울특별시의 ‘함께 서울(http://disability.seoul.go.kr)’, 대한민국 관광공사의 ‘대한민국 구석구석(http://korean.visitkorea.or.kr)’, 대구광역시의 ‘휠체어로 즐기는 대구관광(http://wheeltour.or.kr)’, 울산시의 ‘장애인편의시설 정보 검색(http://usbf.kr)’ 등)
이러한 사이트를 뒤져 사용자가 원하는 시설에 대한 정보가 있을 시, 정보를 Json형태로 크롤링하여 가져와서 파싱하고, 필요한 정보만을 가공하여 제공하는 것입니다.
간단한 예시를 통해 어떻게 웹에서 정보를 가져오는 지를 살펴볼게요.
Java에는 Jsoup라는 파싱 라이브러리를 제공합니다.
// 간략화된 GET, POST
Document google1 = Jsoup.connect("http://www.google.com").get();
Document google2 = Jsoup.connect("http://www.google.com").post();
// Response로부터 Document 얻어오기
Connection.Response response = Jsoup.connect("http://www.google.com")
.method(Connection.Method.GET)
.execute();
Document google3 = response.parse();
Connect를 이용하여 URL에 접속하고 정보를 Get이나 Post 메소드를 사용하여 Document를 얻어옵니다. 이렇게 하지 않고 Response를 사용하여 받아올 수도 있지요.
Document document = response.parse();
String html = document.html();
String text = document.text();
Document는 text()나 html()이라는 메소드를 이용하여 쉽게 String으로 가져올 수 있습니다.
html()을 사용하면 개발자 모드에서 볼 수 있는 것과 같은 페이지의 html 태그와 그 안의 content를 그대로 가져오게 되고요, text()를 사용하면 태그 사이의 문자열만을 가져옵니다.
특정한 html요소를 얻어오려면, select("query") 메소드를 사용합니다.
Document googleDocument = response.parse();
Element btnK = googleDocument.select("input[name=btnK]").first();
String btnKValue = btnK.attr("value");
(출처: http://partnerjun.tistory.com/42)
구글에서 제공하는 Deep Learning 라이브러리인 Tensorflow 한번쯤은 다들 들어보셨을 거라 생각해요! Tensorflow는 구글 브레인팀에서 만든 오픈소스 소프트웨어 라이브러리로 머신러닝을 위해 만들어졌어요. Tensorflow는 안드로이드와 iOS 같은 모바일 환경은 물론 리눅스, MacOS의 데스크탑이나 서버 시스템에도 구동될 수 있어요. 데이터 플로우 그래프(Data Flow Graph) 방식을 사용했는데, 데이터 플로우 그래프는 수학 계산과 데이터의 흐름을 노드(Node) 와 엣지(Edge)를 사용한 방향 그래프(Directed Graph)로 표현해요. 노드는 수학적 계산, 데이터 입출력, 그리고 데이터의 읽기 저장 등의 작업을 수행하고 엣지는 노드들 간 데이터의 입출력 관계를 나타냅니다. 엣지는 동적 사이즈의 다차원 데이터 배열을 실어나르는데, 이 다차원 데이터 배열을 텐서(Tensor)라고 합니다. 여기서 Tensorflow라는 이름이 지어졌습니다.
- 데이터 플로우 그래프를 통한 풍부한 표현력
- 코드 수정 없이 CPU/GPU 모드로 동장
- 아이디어 테스트에서 서비스 단계까지 이용 가능
- 계산 구조와 목표 함수만 정의하면 자동으로 미분 계산을 처리
- Python/C++를 지원하며, SWIG를 통해 다양한 언어 지원 가능
- UNIX 계열 OS (Linux/Max OSX)
- GPU버전은 Linux 만 지원
텐서플로우를 설치하기에 앞서 PIP를 설치 해야 합니다.
텐서플로우 파일 받을 주소를 세팅합니다. Python 버전에 따라 맞추어 골라주면 됩니다.
그 다음, 텐서플로우를 설치합니다.
(출처: http://blog.danggun.net/4064)
Inception V3는 ImageNet의 데이터를 사용하여 훈련된 구글이 개발한 이미지 인식의 가장 최신 모델이에요. ImageNet은 구조화된 이미지 데이터베이스라고 생각하시면 되요.
Inception V3 모델을 다운받은 뒤 사진을 인풋으로 주어 분류합니다.
위의 그림을 보면 더 이해가 쉬울 텐데요, Inception V3 가 제공하는 이미지 분류 라벨과 퍼센트로 각각 나타나게 됩니다. 이미 학습이 되어있는 모델이기 때문에 단순히 사진을 인풋으로 주는 것만으로 위와 같은 결과를 얻을 수 있습니다. 저희의 목적인 입구 판별을 위해서 미리 모아둔 입구 사진 약 1500장과 입구가 아닌 사진 약 1500장을 가지고 Inception V3 모델로 분류해 입구 사진일 때에 어떤 라벨이 높은 확률로 나타나는지 실험해 보았습니다. 그리고 입구가 아닌 사진들을 돌렸을 때도 동일하게 실험해보았어요.
입구 사진 1380개를 돌렸을 때 결과로 출력된 라벨들이 전체 사진에서 몇 퍼센트를 차지하는지, 그리고 나타나는 빈도수를 분석한 결과 다음과 같이 나타났습니다. 그리고 입구가 아닌 사진을 돌렸을 때 나타나는 라벨들도 함께 분석해 보았는데요, 입구 사진이 아님에도 불구하고 입구인 사진에서 많이 나타나는 라벨과 겹치는 것들이 있는 것을 볼 수 있습니다. 저희가 실제 어플리케이션에 사용한 Inception V3 그래프는 기존의 약 만 개 라벨을 가진 모델이 아니라 좀더 속도를 낼 수 있기 위해서 천 개의 라벨을 가진 그래프를 사용했는데요, 아래 사진은 입구에 해당되는 라벨을 천 개 모델의 라벨에 적용시켜 최종적으로 걸러진 입구 라벨을 보여줍니다.
안드로이드 스튜디오에서 작업하던 기존 애플리케이션을 봅니다. Assets 폴더를 생성해 준 뒤 그래프 라벨 정보를 담은 imagenet_comp_graph_label_strings.txt 파일과 Inception V3 그래프 파일은 tensorflow_inception_graph.pb를 다음과 같이 넣어줍니다.
그래프 이외의 소스 코드는 TensorFlowMachineLearningExample여기를 참고 했으니 더 궁금한 게 있으시다면 여기를 참고해주세요! 필요한 소스 코드와 그래프 파일을 갖추면 이제 안드로이드에서 사용할 준비가 완료되었습니다!
준비가 되었다면 구체적으로 시설에 대한 이미지를 어떻게 가져오는지 설명해 드리겠습니다. HTML parsing을 통해 검색하고자 하는 시설의 이미지 url들을 구글 이미지 검색으로 가져옵니다. 그리고 그 url들을 값으로 입력 받아 Bitmap 형식으로 바꾼 뒤 Inception 모델을 거쳐 사진에 해당되는 라벨들을 가져옵니다. 아래는 사진의 라벨들을 어떻게 입구 사진으로 판별하는지에 대한 알고리즘 시각화 자료입니다.
이와 같은 과정을 거쳐 해당 사진이 입구 사진 혹은 건물 사진인지를 판별하여 사용자에게 보여주게 됩니다.
지금 까지 어플리케이션에서 이미지 분석 부분을 알아보았는데요, 다음으로 리뷰를 보겠습니다
Wheelric의 두 번째 기능은 리뷰 작성 기능입니다. 작성된 정보를 체계적으로 관리하기 위해서 데이터베이스 시스템을 이용하는데요. 이 시스템은 서버 안에 설치되어, 어플리케이션과 실시간으로 상호작용하게 됩니다. 이번 파트에서는 안드로이드와 DB를 연동하는 방법을 알아보겠습니다.
연동에 필요한 구성은 위의 그림과 같습니다. 안드로이드 App을 제외한 위의 네가지 요소를 일컬어 LAMP라 부르는데, 이는 Linux(서버), Apache(웹서버), MySQL(데이터베이스), Php(웹 스크립트 언어)를 의미합니다. AWS(Amazon Web Service)는 다양한 서비스를 제공하며, EC2 인스턴스는 쉽게 말해 가상의 컴퓨터 한대를 빌리는 것입니다. 자신의 필요에 따라 OS를 선택할 수 있으며 wheeliric은 Linux를 사용합니다. 리뷰 플랫폼 운용에 필요한 데이터는 모두 MySQL 내부의 데이터베이스에 저장됩니다. MySQL이 안드로이드 application과 통신하기 위해서는 웹서버 Apache가 필요하며, php는 웹 스크립트 언어로, php 파일은 apache 웹서버 내에서 동작합니다.
그런데, 혹시 Eclipse를 사용해서 서버의 mysql과 연동되는 console 프로그램을 작성해보셨나요? 이클립스+ Java 환경에서는 JDBC라이브러를 사용, 웹서버를 쓰지 않고 아래와 같이 바로 mysql과 연동하셨을겁니다.
그렇다면 웹서버, 왜 써야할까요? 바로, 안드로이드의 경우, 보안의 이유로 외부 라이브러리와의 직접 연동을 막아놨기때문입니다. 그래서 중간에 웹서버를 한번 거쳐서 정보를 꺼내옵니다.
Java 코드로 Http 요청을 보내면, Apache 웹서버는 요청받은 php 파일을 읽고, 이에 대한 응답으로 Json 포멧의 데이터를 위와 같이 보냅니다. 위의 json 데이터는 파싱된 형태이며, 실제 가장 처음에 받아지는 데이터의 형태는 아래와 같이 괄호로 중첩되서 나타납니다.
이렇게 하나의 string으로 받아진 데이터는, 자바 코드단에서 파싱을 통해 우리가 필요한 데이터만 뽑아내게 됩니다. 위의 데이터를 예로 들면, John의 가입정보인 month, day, year등만 뽑아내는 경우입니다.
MySQL과의 연동 위주로 이야기해보겠습니다.
(위의 서버 주소는 현재 밀알팀의 서버 주소와 다릅니다.)
이때 php 파일은 EC2 서버의 /var/html/www/html/에 저장됩니다.
Ex. /var/www/html/getReview.php
데이터쓰기는 데이터 읽기와 방법이 거의 같습니다. 다른 점은 2가지입니다.
- 자바 코드 상의 URL
기존에는 php 파일명으로 주소가 끝났다면, 이번에는 아래와 같이, 데이터베이스에 기록하고자하는 파라메터를 추가합니다.
signUp.php?ID=" + id +"&nick="+nick,
- Php 파일 안의 쿼리문
많은 주의사항이 있겠지만, 제 경우 가장 애를 먹었던 경우는 인코딩이었습니다. 한글 데이터의 깨짐을 방지하기 위해 몇가지 설정이 필요합니다.
- /etc/mysql/my.cnf 수정
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
collation-server = utf8_unicode_ci
init-connect='SET NAMES utf8'
character-set-server = utf8
(출처: https://nesoy.github.io/articles/2017-05/mysql-UTF8)
*기존의 Database나 table의 charset은 변경되는것이 아니기 때문에 직접 변경 필요
ALTER DATABASE [DB명] DEFAULT CHARACTER SET utf8;
ALTER TABLE [테이블 명] CONVERT TO CHARACTER SET utf8;
이후 mysql 재시작 해줘야 한다.
- 자바 코드단
- Php 파일
시선에서 오랜 기간 프로젝트를 수행해오면서 가장 많이 했던 고민은 새로운 기술에 대한 욕심과 실질적 사용자의 필요 를 절충하는 일이었습니다. 사용자의 입장에 맞추다보니, 생각보다 결과물이 다른 프로젝트처럼 우와! 탄성이 나오지 않는 단순한 구조로 보여 속상함을 느낄 경우도 많았습니다.
하지만 프로젝트를 마무리하며 든 생각은 그래도 참 뿌듯하다는 점입니다. 세상에 소망을 싹 틔우는 한 톨의 밀알이 되고자, 시작한 프로젝트이기에, 사용자분의 고맙다*는 말 한마디에 저희는 오늘도 보람찹니다. 감사합니다.