제12회 임베디드SW 경진대회 인기상 수상작

이 시스템은 주차장의 남은 자리를 사용자가 쉽게 파악 할 수 있게 도와주는 장치이다. 카메라를 사용하였기 때문에 각 주차공간마다 인식 센서를 설치할 필요 없이 카메라 한대로 광범위하게 인식 할 수 있으며 서버에서 데이터 처리 과정 없이도 무선으로 정보를 사용자에게 전달해 줄 수 있는 것이 큰 장점이다.

카메라로 들어오는 영상을 디지털 이미지 프로세싱 알고리즘을 이용하여 주차장의 특정 자리의 주차상태를 판별해서 서버에 업로드를 시키고 안드로이드가 서버에서 정보를 받아와 사용자가 어플리케이션을 통해 확인하는 방법으로 개발하였다.

이 시스템은 임베디드 보드 라즈베리 파이에서 구동되는 카메라의 영상 인식기술, JAVA 기반의 안드로이드 프로그래밍을 통한 어플리케이션 개발 두 가지의 주요한 기술이 사용되었으며, 두 장치를 연결해주는 아파치 서버를이용한 복합적인 시스템으로 구성되어 있다.

이번 글에서는 나머지 함수별 기능 및 기술적 차별성에 대해 알아보겠다.

 

4.2.2 Android
-MainActivity.java
getWindow( ).setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);

실행 시 보일 화면의 특성을 정의한다. 타이틀 바를 표시하지 않음으로 설정하였다.

setContentView(R.layout.activity_main);

액티비티(java 소스 파일)과 레이아웃(xml) 파일의 연결을 위한 코드, id를 통한 xml 파일에 연결을 해준다.

mListButton = (ImageButton)findViewById(R.id.button_parking);

선언 된 버튼에 대한 정의를 내려준다. mListButton은 ImageButton형식이며 id를 통해 xml 파일 내의 버튼과 연결을 해준다.

mListButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this,ListpasActivity.class);
startActivity(i);}
});

클릭 리스너를 정의해 준다. 버튼을 클릭하는 이벤트가 발생할 시 리스너를 통해 리스너 내부에 정의 된 온클릭 매서드에 의해 매서드 안의 기능이 실행된다. 액티비티 간의 연결을 위해 Intent를 사용하였으며 버튼을 클릭 할 시 startActivity를 통하여 intent가 실행된다.

-ListpasActivity.java, HtmlpasActiviy.java
new Thread( new Runnable() {
public void run() {
loadHtml();
}
}).start();

intent를 통하여 액티비티간 전환이 되어 ListpasActivity가 실행되면 새로운 쓰레드를 통하여 loadHtml() 매서드가 실행된다.
public void loadHtml(){
try{
URL url = new URL(“http://220.149.124.134/opencv/carpark1.html”);
URLConnection conn = url.openConnection();

새로운 URL를 선언하여 서버에서 받아올 주소를 넣고 URL 연결을 정의해 준다.

InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is,”UTF-8”);
BufferedReader br = new BufferedReader(isr);

html을 읽을 InputStream과 Stream Reader를 생성해준다. InputStreamReader는 html파일을 UTF-8규격으로 읽는다.

while(true){
String line = br.readLine();

Stream에 저장된 html의 정보를 String형 변수 line에 저장한다.

if(line == null){
for(int i=0; i<10;i++)
{
sum=sum+PasArray[i];

html의 내용에 다음 정보가 없으면 (line == null일때) PasArray에 저장된 배열 값들의 합을 sum변수에 넣는다.

}
sum=10-sum;

10은 주차장 총 자리의 개수이고, 그 개수에 차있는 자리의 개수의 합인 sum변수를 뺀다. 뺀 값은 주차장의 총 공석의 개수가 된다.

break;
}
StringTokenizer st = new StringTokenizer(line,” “);
for(int i=0; st.hasMoreTokens(); i++) {
PasArray[i] = Integer.parseInt(st.nextToken());

StringTokenizer로 (java.util.StringTokenizer 안의 StringTokenizer를 Override하여 구현) 버퍼에 들어있는 정보를 띄어쓰기 단위(공백)로 구분한다. 구분된 정보를 주차장 공석여부를 담는 PasArray에 넣는다.

}
}
} catch(Exception e){
Log.e(“URL Error”, e.getMessage());

URL이 잘못 되었을 때의 예외처리.

}
try{
URL url2 = new URL(“http://220.149.124.134/opencv/carpark2.html”);
URLConnection conn2 = url2.openConnection();
InputStream is2 = conn2.getInputStream();
InputStreamReader isr2 = new InputStreamReader(is2,”UTF-8”);
BufferedReader br2 = new BufferedReader(isr2);
while(true){
String line2 = br2.readLine();
if(line2 == null){
for(int i=0; i<10;i++)
{
sum2=sum2+PasArray2[i];
}
sum2=10-sum2;
Link();
break;
}
StringTokenizer st2 = new StringTokenizer(line2,” “);
for(int i=0; st2.hasMoreTokens(); i++) {
PasArray2[i] = Integer.parseInt(st2.nextToken());
}
}
} catch(Exception e){
Log.e(“URL Error”, e.getMessage());
}
}}
2번째 나온 try~catch구문은, 그 위의 html상의 정보를 읽고 PasArray안의 넣는 작업을 한 주차장 내의 다른 구역 또는 다른 주차장에 대하여 실행하는 것이다.

public void Link(){
Intent in=new Intent(ListpasActivity.this,ListActivity.class);
in.putExtra(“psum” , sum);
in.putExtra(“psum2” , sum2);
startActivity(in);
finish();
}

intent를 이용하여 ListActivity에 주차장의 공석 개수를 보내고 실행시킨다.
※ ListpasActivity.java와 HtmlpasActiviy.java는 기능이 같다. 다만 각각 실행시키는 액티비티가 다르다. (ListpasActivity는 ListActivity를, HtmlpasActiviy는 SignalActivity를 실행)

-ListActivity.java, CListActivity.java
Intent intent = getIntent();
sum1 = intent.getExtras().getInt(“psum”);
sum2 = intent.getExtras().getInt(“psum2”);
putExtras로 인해 보내진 값들을 getExtras를 통해 각각의 변수에 받아 저장한다.

setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_icon1);
setTitle(“~~~”);

타이틀 바의 제목을 “”안의 ~~~ 로 지정해준다. (사용자에게는 보이지 않는다)

data = new ArrayList<String>();
data.add(“무궁관(남은자리 : “+sum1+”)”);
data.add(“다산관(남은자리 : “+sum2+”)”);
data.add(“테크노파크(남은자리 : “+sum3+”)”);
data.add(“기숙사(남은자리 : “+sum4+”)”);

ListView를 표현할 ArrayList를 선언 하고 각각의 List에 장소정보를 추가해준다.

ArrayAdapter<String> arrayAdapter ;
ListView listView ;
arrayAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,data);
listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(arrayAdapter);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

ArrayAdapter를 통해 xml의 ListView와 연결을 해주고 CHOICE_MODE_SINGLE을 통해 한가지 항목만 선택되게 
한다.

listView.setOnItemClickListener(new OnItemClickListener(){public void
onItemClick(AdapterView<?> parent, View view, int position, long id)

ArrayList를 선언하게 되면 각각의 항목의 포지션 값이 생성이 된다. 
포지션 값을 통하여 OnClickListener 안에서 항목들의 클릭여부를 구별한다.

{
if(data.get(position)==data.get(0))

포지션 값이 ArrayList의 0번째 값과 같을 시에 if문이 실행된다. 
0번째값은 List의 첫 번째 값이 선택되었다는 것을 의미한다.
{
select=1;
Intent j= new Intent(ListActivity.this,htmlPas.class);
j.putExtra(“select” , select);
finish();
startActivity(j);

intent를 통하여 htmlPasActivity가 실행이 되고, select 값을 1로 보내주어 두 개의 액티비티 중 첫 번째 액티비티가 실행이 되도록 한다. 이때 두 개의 액티비티는 각각의 주차장이거나 한 주차장 내의 다른 구역이다.

}
else if(data.get(position)==data.get(1))

포지션 값이 ArrayList의 1번째 값과 같을 시에 실행되는 if문이다. List의 2번째 항목이
선택되었을 때이다.

{
select=2;
Intent k= new Intent(ListActivity.this,htmlPas.class);
k.putExtra(“select” , select);
finish();
startActivity(k);

intent를 통하여 htmlPas.class 가 실행이 되고, select 값을 2로 보내주어 두 개 중 두 번째 액티비티가 실행이 되도록 한다.

}
else{
Toast.makeText(ListActivity.this, “해당 건물의 주차장 데이터가 없습니다.”,
Toast.LENGTH_SHORT).show();

주차장 데이터가 없는 항목을 누를시 “해당 건물의 주차장 데이터가 없습니다.” 라는 정보가 나오는 토스트 메시지를 띄운다.

}
});
-SignalActvity.java, Signal2Activity.java
mButtonfresh =(Button)findViewById(R.id.button11);
mButton[0] = (Button)findViewById(R.id.button1);
mButton[1] = (Button)findViewById(R.id.button2);
mButton[2] = (Button)findViewById(R.id.button3);
mButton[3] = (Button)findViewById(R.id.button4);
mButton[4] = (Button)findViewById(R.id.button5);
mButton[5] = (Button)findViewById(R.id.button6);
mButton[6] = (Button)findViewById(R.id.button7);
mButton[7] = (Button)findViewById(R.id.button8);
mButton[8] = (Button)findViewById(R.id.button9);
mButton[9] = (Button)findViewById(R.id.button10);
mImage[0] = (ImageView)findViewById(R.id.imageView00);
mImage[1] = (ImageView)findViewById(R.id.imageView01);
mImage[2] = (ImageView)findViewById(R.id.imageView02);
mImage[3] = (ImageView)findViewById(R.id.imageView03);
mImage[4] = (ImageView)findViewById(R.id.imageView04);
mImage[5] = (ImageView)findViewById(R.id.imageView05);
mImage[6] = (ImageView)findViewById(R.id.imageView06);
mImage[7] = (ImageView)findViewById(R.id.imageView07);
mImage[8] = (ImageView)findViewById(R.id.imageView08);
mImage[9] = (ImageView)findViewById(R.id.imageView09);

각각의 버튼의 id값을 버튼 배열의 정보에 대입한다.

mButtonfresh.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
Intent j= new Intent(SignalActivity.this,htmlPas.class);
j.putExtra(“select” , select);
startActivity(j);
}
});

새로고침 버튼을 클릭할 시 발생하는 이벤트다. intent를 통해 htmlPas.class 액티비티를 실행시키고, 다시 SignalActiviy.class 액티비티가 실행됨으로써 업데이트 된 정보를 받아온다. 이때 select값은 ListActivity에서 받아온 값이다. 이를 이용하여 현재 어떤 주차장 또는 구역의 정보를 업데이트를 하는 것인지 구분할 수 있다. 

다음 호에서는 나머지 함수별 기능과 차별성을 알아보겠다.

 

 

글 : Convergence (김건형, 신용준 외 8명 / 서울과학기술대학교)
자료제공 : 임베디드소프트웨어·시스템산업협회

회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지