인공지능캡스톤디자인 계획서

캡스톤디자인 번호	2022-01
캡스톤디자인 분야	웹
캡스톤디자인 지도교수	노기섭 교수님
캡스톤디자인 명	(국문) 사진을 이용한 웹기반 퀴즈 게임(WITH)
	(영문) Photo WebOS Quiz Game
캡스톤디자인 책임자	팀 명		WITH – WhatIsTHis (1팀)
	학 과		인공지능소프트웨어학과
	성 명					학 번
	휴대폰					E-mail
캡스톤디자인 세부현황	번 호	세부역할			성 명		전 공		학 번
	1	영상처리
	2	웹코딩 및 DB작성
	3	웹코딩 및 DB작성
캡스톤디자인 수행기간	2021년 3월 21일부터 2021년 6월 14일 까지(12주)
2021년도 캡스톤디자인을 성실히 수행하고자 캡스톤디자인 계획서를 제출합니다. 2021 . 03 . 25 . 캡스톤디자인 책임자 인공지능소프트웨어 전공PD 귀하

1. 요약서

※ 본 요약서는 캡스톤디자인 전체에 대한 요약서임. 캡스톤디자인 전체의 총괄적인 내용을 위주로 간략하게  1page 이내로 작성함

캡스톤디자인 번호	2022-01
캡스톤디자인 명	사진을 이용한 웹기반 퀴즈 게임
캡스톤디자인 책임자

○ 캡스톤디자인 목표

현재 캐치마인드나 끝말잇기, 갈틱폰 등 사용자들과 간단한 게임을 플레이하는 사이트들이 있다. 앞의 예시 사이트들과는 다르게 우리는 영상처리 기술을 이용해서 사진을 변형하여 좀 더 어렵거나 난해한 퀴즈를 내고 맞추는 새로운 웹 게임을 구상하였다.

○ 캡스톤디자인 내용

퀴즈를 위한 퀴즈 이미지 예시 데이터를 저장하여 랜덤한 문제를 낸다. 같은 사진이더라도 외곽선만 출력하거나 일부분을 출력하는 방법을 포함한 여러 가지 변형을 이용하여 문제를 어렵게 내고 이를 본 사용자가 맞춘 순서 시간에 따라 점수가 달라지는 게임을 구상하였다. 사이트에 있는 퀴즈 데이터뿐만 아니라 사용자가 사진을 찍어 업로드를 할 경우 새로운 퀴즈를 만들어서 풀 수도 있다. 문제점이나 개선해야 할 사항이 있다면 점차 보완하여 게임의 완성도를 높인다.

○ 캡스톤디자인 개발에 따른 기대성과

현재 코로나19로 인해 외부에서 만나기 힘든 상황이다. 하지만 이 게임은 어디서나 손쉽게 플레이를 할 수 있으며 친구들과의 소통을 하고 친해지는 계기가 될 수 있다. 또한 전연령층이 즐길 수 있는 게임으로 변형된 사진을 보고 재치와 순발력으로 푸는 방식으로 색다른 접근을 할 수 있으며 상상력을 키울 수 있다. 더 나아가 교육 분야로 진출할 수 있을 것이라고 생각한다.

캡스톤디자인 계획서

캡스톤디자인 명 : WITH (What Is THis? - 사진 퀴즈 게임)

캡스톤디자인 책임자 :

1. 캡스톤디자인의 필요성

현재 코로나19가 심해지는 환경에서 여러 사람들과 만나는 것이 힘들다. 게다가 게임의 추세는 정형화된 게임이 많고 거기서 파생된 게임이 많다. 그로 인해 새로운 시도는 점점 적어지는 추세이고 비슷한 장르의 게임이 주를 이루고 있다. 우리가 구상한 What Is This(WITH)는 간단한 게임으로 전연령층이 쉽게 즐길 수 있는 게임이다. 누구나 손쉽게 접근할 수 있는 게임으로 별도의 다운로드 없이 즐길 수 있다. 공개방에서는 다양한 사람들과 친해지는 계기가 되고 초대방에서는 지인들과 서로 소통할 수 있다. 사람들과의 소통이 힘들고 새로운 게임이 적은 추세에서 간단하면서 접근성도 좋은 새로운 게임을 만들고자 하여 이러한 게임을 구상하였다.

2. 캡스톤디자인의 목표 및 내용

가. 캡스톤디자인 디자인 목표

요즘 갈틱폰, 캐치마인드 등과 같이 웹사이트 기반으로 간단하게 즐길 수 있는 게임들도 많다. 또한 인터넷이 활발해지고 코로나19로 인하여 온라인에서 사람과 접하는 경우가 많아지는 추세이다. 그래서 웹사이트에서 간단한 게임을 통해 사람들과 접할 수 있는 게임을 생각하였다. 디자인은 간편함과 접근성을 위하여 단순하지만 눈에 잘 들어오는 UI로 구성한다. 또한 별도의 로그인없이 별명을 만들어서 사용자와 손쉽게 플레이 하는 방식이다. 이를 활용하여 단순한 게임만이 아니라 전연령층이 즐길 수 있으며, 교육 및 친밀감을 도모하는 목적을 갖고 프로젝트를 구상하였다.

나. 캡스톤디자인 내용

	사용자들은 별도의 로그인없이 생성된 방에 들어가거나 초대코드를 이용하여 방에 참가한다. 게임을 플레이하면 중앙에 사진이 나오고 타이머가 흐르며 현재 사진의 모습과 가장 비슷한 답을 고르는 방식이다. 또한 문제에서 제공되는 사진뿐만 아니라 사용자가 직접 사진을 찍으면 규격에 맞게 자른 후 영상처리를 이용하여 변형된 사진이 문제로 출제된다.

3. 캡스톤디자인의 추진전략 및 체계

웹개발프레임워크, 서버, DBMS, IDE, 협업 툴을 이용하여 진행한다.

2. 웹페이지를 제작하고 목적에 맞는 영상처리 소스코드를 작성한다. 작동이 순조롭게 될 때까지 수정 및 보완작업을 실행한다.

3. 작품이 완성되면 담당 교수님께 보여주고 피드백을 받아서 추가적인 수정 및 보완 또는 문제점들을 적절하게 조치한다.

4. PPT에 일부코드 및 작동영상을 보여주어 제품의 완성도를 전달한다.

5. 작품이 완성되면 제품을 홍보한다. 좋은 아이디어로 채택되면 더 많은 테마를 만들고 타 OS에서도 호환가능하게 개발한다.

4. 캡스톤디자인의 기대효과 및 활용방안

요즘 게임의 추세는 정형화된 게임이 많고 거기서 파생된 게임이 많다. 그로 인해 새로운 시도는 점점 적은 추세이고 비슷한 장르의 게임이 주를 이루고 있다. 또한 현재는 4차 산업혁명의 시기로 전세계 사람들이 온라인으로 손쉽게 만날 수 있다. 이러한 세상에서 저희 팀은 What Is This(WITH)라는 간단한 게임으로 전세계의 전연령층이 할 수 있는 게임을 구상하였다. 간단한 조작법과 UI를 통해 남녀노소 불문하고 가볍게 즐길 수 있으며 새로운 소통 방안으로 활용할 수 있다. 게다가 누구나 손쉽게 접근할 수 있는 게임으로 별도의 다운로드 없이 초대코드만을 이용하여 다른 공간에서도 서로 소통할 수 있다. 사람들과의 소통이 힘들어지고 새로운 게임이 적어지는 추세에서 간단하면서 접근성도 좋은 새로운 게임을 만들고자 하여 이러한 게임을 구상하였다. 이로 인해 친구들과의 친밀감이 형성되고 간단한 사진 퀴즈를 통해서 순발력과 재치를 키울 수 있다.

교육 프로그램도 디지털화하는 시점에서 사진을 통한 퀴즈 풀이 게임은 여러 가지 사진을 보고 맞추는 방식으로 유아층 및 초등교육에서의 교육적 기대효과를 볼 수 있다.

6. 작업분할 구조도(WBS, Work Breakdown Structure)

7. 소요장비 및 재료

장비 및 재료 명	규격	수량	용 도	비 고
개인용 컴퓨터 (PC)		3	작업
웹 브라우저 (Chrome)		3	정보 및 자료 검색
한컴오피스 한글 2010		3	문서 작성
Microsoft Power Point		3	PPT 제작
VScode		3	소스코드 작성
git, github		3	소스코드 공유 및 프로젝트 진행
anaconda		3	소스코드 작성 및 개발환경
Django		3	가상환경
sqlite		3	DB
discord		3	팀원 간 연락
스마트폰		3	팀원 간 연락
ovenapp		3	전체적인 UI 구상
aws		1	웹서버 가동

8. 캡스톤디자인 추진일정 계획

	세부 추진 내용				추진일정(월)
					7	8	9	10
WITH (퀴즈 게임)	1	프로그래밍	socket channels	지식 습득
	2			구축
	3		사진 DB 작업
	4		게임 플레이
	5		중간 점검
	6	웹 UI	디자인
	7		적용
	8	서버	서버 연동 및 테스트
	9	최종수정	최종 수정

물품명 및 가격	스펙 및 부품	주소
총액	0원

9. 구매 품목

캡스톤디자인 지도교수 동의서

번호	학번	성명	연락처	비고
1
2
3

위의 학생(들)에 대한 캡스톤디자인 지도교수 선임에 다음과 같이 동의합니다.

- 다              음 -

전 공	직 위	지도교수 성명	날 인
인공지능 소프트웨어	교수	노기섭	노기섭

2022년   03월   25일

청주대학교 인공지능소프트웨어 전공PD 귀하

캡스톤 디자인 결과보고서(結果報告書)

목  차

1. 시스템 구조 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	15
1.1. 시스템 설계도 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	15
2. Django ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	18
2.1. Django ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	18
2.2. 환경설정 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	18
2.2.1. Pycharm 설치 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	18
2.2.2. 프로젝트 생성 및 깃 연동 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	21
2.2.3. anaconda 설치 및 가상환경 생성 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	22
2.2.4. MySQL 설치 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	27
2.3. 장고 설치 과정 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	31
2.3.1. Django 설치	31
2.3.2. 환경 변수 설정과 .env 파일 .gitignore에 등록	31
2.3.3. DB 연동	32
2.4. 룸 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	35
2.4.1. index ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	37
2.4.2. 방목록 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	38
2.4.3. 방생성 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	38
2.4.4. 대기실 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	39
2.5. 플레이 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	41
2.5.1. 라운드 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	42
2.5.2. 라운드 별 결과 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	45
2.5.3. 최종 결과판 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	46
2.5. 패키지 관리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	47
3. OpenCV ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	48
3.1. OpenCV ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	48
3.1.1. OpenCV 설치 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	48
3.1.2. OpenCV 테스트 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	49
3.2. 사진 변형 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	49
3.2.1. 외곽선 검출 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	49
3.2.2. 모자이크, 블러 처리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	53
3.2.3. 렌즈(왜곡) 처리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	55
3.2.4. 랜덤 이미지 처리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	58
5. 마무리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	60
5.1. 향후 추진 계획 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	60
5.2. 정리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	60

1. 시스템 구조

1.1. 시스템 설계

본 프로젝트는 Django 프레임워크를 활용한 사진 퀴즈 게임을 구상하였다. 주로 사용된 언어는 python으로 개발하였고 javascript도 활용했다.

WITH 프로젝트의 wbs 초안이다. 분야를 크게 유저, 메인화면, 인게임으로 나눴다. 유저는 휘발성으로

간단한 별명을 설정하면 쉽게 접속이 가능하고 게임 플레이를 할 수 있다.

메인화면은 크게 room과 quiz로 나눌 수 있다. quiz는 OpenCV를 활용하였으며 문제를 만드는데 있어 가장 중요한 부분 중 하나이다. 원본 이미지를 기준으로 여러 가지 방법으로 사진을 변형한다. 변형된

이미지는 MariaDB에 저장되고 각각의 사진마다 원본 이미지를 기준으로 매칭된다.

room은 quiz와 밀접한 관계가 있다. 앞서 변형된 이미지와 원본 이미지를 기준으로 방을 생성하며 퀴즈를 등록하게 된다. 등록된 퀴즈를 기준으로 문제가 나오게 되며 라운드나 테마를 정할 수 있다. 방이

생성되면 방목록에 있는 방을 클릭하거나 초대코드를 이용하여 방에 접속한다.

방에 접속하게 되면 방에 있는 이용자 현황을 볼 수 있고 안에 있는 유저들과 채팅을 할 수 있다.

채팅은 jquery 기반으로 만든다. 채팅은 실시간으로 진행된다.

마지막으로 인게임을 계획했다. 인게임은 상단에 프로그래스바(타이머)가 있으며 우측에는 문제에 해당되는 사진이 나온다. 좌측에는 지문에 해당되는 버튼이 있고 해당되는 사진과 일치하는 버튼을 누른다.

버튼을 누르면 타이머 시간이 끝나기 전에는 다음 라운드로 넘어갈 수 없다.

해당 라운드의 종료와 동시에 문제 사진과 정답 사진이 화면에 나타나고 플레이어들의 점수가 출력된다. 모든 라운드가 종료되면 총점을 보여주는 최종 결과판으로 이동한다.

2. Django

2.1. Django

- django 로고 -

장고는 웹 프로그램을 쉽고 빠르게 만들 수 있도록 도와주는 웹 프레임워크이다. 웹 개발을 하는데 많은 도움을 주기 때문에 새롭게 웹 개발을 시작할 필요없이 그저 프레임워크를 활용하여 앱 개발에만 집중할 수 있다. 무료 오픈소스인데다가, 활발한 커뮤니티들이 있고, 좋은 참고자료와 무료 및 유료 지원을 하는 옵션들이 제공된다.

2.2 환경설정

2.2.1 Pycharm 설치

- 파이참 다운로드 화면 및 주소 -

https://www.jetbrains.com/pycharm/download/#section=windows

- 파이참 설치화면 1 -

- 파이참 설치화면 2 -

- 파이참 설치화면 3 -

- 파이참 설치화면 4 -

- 파이참 설치화면 5 -

- 파이참 설치화면 6 -

- 파이참 설치완료 -

2.2.2 프로젝트 생성 및 깃 연동

- 파이참 실행시 화면과 깃헙에서 프로젝트 클론 및 깃 연동 -

- 깃헙에서 불러온 프로젝트 화면 -

2.2.3 anaconda 설치 및 가상환경 생성

- 아나콘다 다운로드 화면 -

https://www.anaconda.com/products/distribution

- 아나콘다 설치 화면 1 -

- 아나콘다 설치 화면 2 -

- 아나콘다 설치 화면 3 -

- 아나콘다 설치 화면 4 -

- 아나콘다 설치 화면5 -

기존에 아나콘다 path 설정을 해두었기 때문에 현재 저 항목이 비활성화 되어있다.

처음 설치한다면 임의적으로 체크한 것 처럼 체크해주고 설치를 진행하면 된다.

- 아나콘다 설치 화면 6 -

- 아나콘다 설치 화면 7 -

- 아나콘다 설치 화면 8 -

- 아나콘다 설치 완료 -

- 가상환경 생성1 -

- 가상환경 생성 2 -

- 가상환경 생성 후 결과 -

2.2.4 MySQL 설치

- mysql community 다운로드 화면 -

https://dev.mysql.com/downloads/file/?id=511553

설정을 해줘야 되는 부분만 과정을 올렸다.

- mysql 설치 화면 1 -

기존에 설치했었기 때문에 체크하지 않고 넘어간다. 처음 설치한다면 체크를 하고 넘어간다.

- mysql 설치 화면 2 -

- mysql 설치 화면 3 -

- mysql 설치 화면 4 -

기본값은 3306이지만 해당 포트를 타 프로젝트에서 쓰고 있기때문에 포트는 3307로 해두었다.

- mysql 설치 화면 5 -

- mysql 설치 화면 6 -

앞으로 mysql 터미널이나 pycharm 터미널에서 해당 dbms에 접근하기 위해서 쓰이는 비밀번호이기 때문에 반드시 기억해야한다.

- mysql 설치 화면 7 -

- mysql 설치 화면 8 -

설정을 건드리지 않고 바로 Finish를 눌러준다.

해당 root 비밀번호를 넣어주고 check후에 Next를 누른다.

- mysql 설치 화면 9 -

- mysql 설치 완료 -

2.3 장고 설치 과정

2.3.1 Django 설치

- django 설치하는 명령어 -

‘pip install django’ 명령어를 입력하여 django를 설치해준다.

- django 설치 확인 -

4.0.3 버전의 django가 설치된 것을 확인할 수 있다.

2.3.2 환경 변수 설정과 .env 파일 .gitignore에 등록

프로젝트를 진행하다 보면 코드에 서버 접속 정보를 기입해야 할 때가 있다.

git repo가 private으로 되어있다면 상관없지만, 언제까지나 모든 프로젝트를 private으로 할 수는 없다. 그래서 외부에 감추고 싶은 정보들이 코드에 들어가야 한다면, 환경변수로 설정하여 코드에서 import하여 사용한다.

환경 변수 파일을 사용하기 위해 dotenv 라이브러리를 설치한다. 설치가 끝나면 .env 파일에서 아래와 같이 중요한 정보를 기입한다. .gitignore 파일에 .env 파일의 경로를 추가하면 env 파일은 git repo에 올라가지 않고 로컬에 저장이 되어 외부에 감출 수 있다.

- 좌: .env 파일, 우: .gitignore 파일 -

2.3.3 DB 연동

먼저 mysql Client 앱을 열어 with_db라는 dbms를 생성해준다.

- with_db database 생성 -

pycharm에서 우측 상단의 Database 탭을 클릭한다.

- pycharm 우측 상단 database 탭 -

순서에 맞게 클릭 후 우측 사진과 같이 입력해주고 Test Connection으로 연결이 잘되는지 확인한다.

- mysql의 with_db와 연동 확인 -

- makemigations, migrate로 db 테이블 생성 -

pycharm의 database탭이나 mysql workbench의 Schema 탭에서 위에 migration 한 것들을 확인할 수 있다.

- 좌: pycharm, 우: mysql workbench -

2.3. 룸

퀴즈 게임에서 룸은 이용자가 플레이를 하기위한 준비 단계이다. 룸에서는 사이트에 접속한 화면인

index, 방목록, 방생성, 대기실 순으로 진행하겠다.

- 접속시 나오는 첫 화면 -

사이트에 접속하게 되면 별명을 입력하는 란이 나온다. 여기서 사용자는 간단한 이름으로 로그인

할 수 있다.

- 방목록 -

index 화면에서 넘어가게 되면 나오는 화면이다. 해당 화면에는 방목록이 나와 있으며 상단에는

방만들기, 퀴즈 만들기가 있고 방을 클릭하거나 초대 코드를 입력하여 방에 들어갈 수 있다.

- 방생성 -

방생성 화면이다. 방제목, 라운드, 제한 시간, 퀴즈 선택과 같은 배너가 있으며 어떤 테마의 퀴즈인지를

정할 수 있다. 퀴즈 선택은 아직 구현하지 못했다.

- 대기실 -

대기실 화면이다. 대기실에 들어오면 방에 있는 인원이 보이며 채팅창에서 채팅을 할 수 있다.

시작을 누르면 “2.4 플레이”로 넘어가게 된다.

2.3.1. index

- index -

- quiz app -

views.py
1	def index(request): if not request.user.is_authenticated: return redirect('signup') room_list = QuizRoom.objects.all() context = {'room_list': room_list} return render(request, 'quiz/room_list.html', context) def signup_login(request): if request.user.is_authenticated: return redirect('rooms') if request.method == "POST": form = PlayerForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') raw_password = form.cleaned_data.get('password1') auth = form.cleaned_data.get('auth') user = authenticate(username=username, password=raw_password, auth=auth) login(request, user) # return redirect('rooms') return redirect('rooms') else: form = PlayerForm() return render(request, 'quiz/signup_login.html', {'form': form})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

2.3.2. 방목록

- 방목록 -

views.py에 index가 담당한다. 로그인을 해야지만 목록으로 넘어갈 수 있고 settings.py에서 redirect를

시킨다.

2.3.3. 방생성

- 방생성 -

방생성은 form 객체로 온 정보를 확인하고 담는 과정이 들어간다. 앞서 말했던 것과 같이 아직 퀴즈

선택 부분이 없으며 초대코드, 비밀번호 부분이 없이 가장 기본 상태이다.

- quiz app -

views.py
1	def create_room(request): if not request.user.is_authenticated: return redirect('signup') if request.method == "POST": form = RoomForm(request.POST) # print(form.fields[str('room_name')]) # print(form.fields['room_name']) if form.is_valid(): room = form.save(commit=False) room.room_host = request.user room.save() # print(f'dd {room.id}') # return render(request, 'quiz/in_room.html') return redirect('in_room', room_id=room.id) else: form = RoomForm() return render(request, 'quiz/create_room.html', {'form': form})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

2.3.4. 대기실

- 대기실 -

방에 들어온 상태인 대기실 화면이다. 대기실에서는 이용자가 나오며 하단에 있는 채팅을 하고 전송을

누를 경우 방에 있는 이용자들에게 채팅이 보이게 되며 실시간으로 진행된다. 채팅은 ajax로 구현하였다.

- quiz app -

views.py
1	def in_room(request, room_id): if not request.user.is_authenticated: return redirect('signup') room = get_object_or_404(QuizRoom, pk=room_id) print(f'room type : {room, type(room), room.id}') # room_details = QuizRoom.objects.get(room_name=room) # print(room_details) player = str(request.user) # room_details if player not in room.room_user: room.room_user += f'{player} ' room.save() # print(f'room.room_??? types : {room.room_user, type(room.room_user), type(request.user)}') # print(f'request.GET.get("room_name") : {request.GET.get("room_name")}') context = {'room': room, 'username': player} return render(request, 'quiz/in_room.html', context) def send(request): message = request.POST['message'] username = request.POST['username'] room_id = request.POST['room_id'] print(message) print(f'send : {message, username, room_id}') new_message = Message.objects.create(value=message, user=username, room=room_id) new_message.save() return HttpResponse('메시지 보내기 성공') def getMessages(request, room_id): messages = Message.objects.filter(room=room_id) # print(f'getMessages : {messages}') return JsonResponse({"messages": list(messages.values())})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

2.4. 플레이

- 초기 계획한 플레이 화면 -

퀴즈 게임에서 가장 중요한 부분 중 하나인 플레이 파트이다. 게임을 하기 위해서는 게임이 진행되는

상황이 매우 중요하다. 우측에 x 모양에 변형된 사진이 나오고 좌측에 있는 버튼으로 정답을 누르면

방에 있는 인원이 상단에 있는 타이머가 끝나거나 이용자가 전부 문제를 풀 때까지 기다린다.

- round 종료 화면 -

퀴즈 라운드가 종료되면 나오는 화면이다. 문제 이미지와 원본 이미지가 출력되고 점수가 집계된다.

일정 시간이 지나면 자동으로 다음 라운드가 진행된다.

- round 종료 화면 -

모든 라운드가 종료되면 나오는 결과화면이다. 결과화면에는 게임에 참가한 모든 플레이어가 나오고

플레이어의 집계 점수, 등수가 출력된다.

2.4.1. 라운드

- round 시작 화면 -

- play app -

views.py
1	def index(request): quiz = Quiz.objects.get(id=1) # player = Player.objects.get(id=request.user.id) player = QuizPlayers.objects.get(id=request.user.id) # 제한시간 참조하는 부분 limit_time = QuizRoom.objects.filter(room_user=request.user.username).last() print(limit_time.room_round_limit_time) print(player) player.player_score = 0 player.save() return render(request, 'play/play_round.html', {'quiz': quiz, 'limit_time': limit_time}) def play_round(request): round = request.POST['round'] limit_time = QuizRoom.objects.filter(room_user=request.user.username).last() quiz = Quiz.objects.get(id=int(round) + 1) return render(request, 'play/play_round.html', {'quiz': quiz, 'limit_time': limit_time})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

play_round.html에서 타이머 파트

play_round.html
1	{#타이머 기능#} <script> var i = 110; function start() { if (i == 110) { i = 110; var digit = document.getElementById("digit"); var elem = document.getElementById("myBar"); var width = 110; var id = setInterval(frame, {{ limit_time.room_round_limit_time }} * 100); function frame() { if (width <= 0) { clearInterval(id); i=14; digit.innerHTML = width + "초"; if(ans == 1){ document.getElementById('ans-1').submit(); }else if (ans == 2){ document.getElementById('ans-2').submit(); }else if (ans == 3){ document.getElementById('ans-3').submit(); }else if (ans == 4){ document.getElementById('ans-4').submit(); }else{ document.getElementById('time-out').submit(); } } else { digit.innerHTML = width/10-1 + "초"; width-=10; elem.style.width = width + "%"; } } } } start() </script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

2.4.2. 라운드 별 결과

- round 별 결과 화면 -

- play app -

views.py
1	def play_round_after(request): round = request.POST['round'] U_ans = request.POST['U_ans'] print(type(U_ans)) quiz = Quiz.objects.get(id=round) print(type(quiz.quiz_answer)) player = QuizPlayers.objects.get(id=request.user.id) # player = Player.objects.get(id=request.user.id) if (quiz.quiz_answer == int(U_ans)): player.player_score += 10 player.save() return render(request, 'play/play_round_after.html', {'quiz': quiz, 'U_ans': int(U_ans), 'player': player})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

2.4.3. 최종 결과판

- 최종 결과화면 -

- play app -

views.py
1	def play_result(request): # player_list = Player.objects.order_by('id') player = QuizPlayers.objects.get(id=request.user.id) context = {'player': player} return render(request, 'play/play_result.html', context)
2
3
4
5
6
7
8

2.6 패키지 관리

pip list로 지금 설치되어 있는 패키지를 볼 수 있다.

- pip list 결과 -

다른 사용자가 나와 같은 환경에서 이 소스코드를 실행시키려면 이 패키지들이 필요하다.

그래서 requirements.txt로 이 패키지들을 저장하여 다른 사용자에게도 나와 같은 환경을 만들어주어야 한다. 해당 명령어를 통해 패키지들이 저장되어 아래와 같은 결과가 나온다.

<좌: 패키지 저장, 우: 결과 확인>

다른 사용자가 해당 패키지를 설치하려면 아래와 같은 명령어를 이용하면 된다.

- 패키지 설치 명령어와 설치 완료 -

3. OpenCV

3.1. OpenCV

- OpenCV 로고 -

OpenCV는 영상처리와 컴퓨터 비전 관련 오픈 소스 라이브러리이다. 이 라이브러리는 최첨단 알고리즘으로 얼굴 검출과 인식, 객체 인식, 객체의 3D 모델 추출 등 여러 가지 기능을 갖고 있다. 또한 구글,

야후, 마이크로소프트 등 여러 대기업과 신생기업들이 OpenCV 라이브러리를 사용하고 있다.

우리 팀은 OpenCV로 변형된 이미지를 화면에 띄우는게 목적이 아닌 저장을 하고 저장된 사진을 활용하는 것이 목적이므로 각각의 폴더에 변형된 사진을 저장하였다.

3.1.1. OpenCV 설치

- OpenCV-python 설치 명령어 -

사진 변형을 위해 OpenCV를 설치하였습니다. 버전은 “opencv-python==4.5.5.64” 버전으로 설치하였다.

3.1.2. OpenCV 테스트

- Draw circle 테스트 -

설치가 완료됐는지 확인하기 위해 cv2 기능을 활용하여 도형을 그려보았다.

3.2. 사진 변형

3.2.1. 외곽선 검출

외곽선 검출을 할 수 있는 방법은 여러 가지가 있다. 그 중에서 findContours와 edge를 사용하는

두 가지 방법으로 크게 나누었다. findContours에서는 cv2.RETR_EXTERNAL로 최외곽에 있는 선을 검출하였다. 또한 threshold 이미지도 사용하였다. edge에서는 canny edge를 사용하였다.

- Canny edge -

Canny 엣지에 대한 소스코드는 아래와 같다.

contours_canny_save.py
1	import glob import cv2 file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count = 0 for i in file_list: print(i) img_name_list.append(i[6:]) gray_img = cv2.imread(i, cv2.IMREAD_GRAYSCALE) # gray_img = cv2.imread('./img/elephant.jpg', cv2.IMREAD_GRAYSCALE) # threshold 값에 따라 결과 달라짐 - 클수록 긴 선만 나옴 threshold1 = 200 threshold2 = 200 edge_img = cv2.Canny(gray_img, threshold1, threshold2) # cv2.imwrite('sample_edge.jpg', edge_img) # cv2.imshow("edge_img", edge_img) cv2.imwrite('./canny_img/canny_{0}'.format(img_name_list[count]), edge_img) cv2.waitKey(0) cv2.destroyAllWindows() count += 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

- findContours & threshold -

contours_findContours_save.py - 1
1	import glob import cv2 import numpy as np file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count = 0 for i in file_list: print(i) img_name_list.append(i[6:]) img = cv2.imread(i) h, w, c = img.shape black = np.zeros((h, w, c), np.uint8) white = np.zeros((h, w, c), np.uint8) white.fill(255) # color -> gray gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) ret, binary = cv2.threshold(gray, 210, 255, cv2.THRESH_BINARY) binary = cv2.bitwise_not(binary) # 이진화
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

contours_findContours_save.py - 2
30	# RETR_EXTERNAL 최와곽 라인만 찾음 contours, hierachy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) cv2.drawContours(black, contours, -1, (0, 0, 255), 2) cv2.drawContours(white, contours, -1, (0, 0, 255), 2) cv2.imwrite('./threshold_img/threshold_{0}'.format(img_name_list[count]), 255-binary) cv2.imwrite('./contours_img/contour_{0}'.format(img_name_list[count]), black) cv2.waitKey(0) cv2.destroyAllWindows() count += 1s() count += 1
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

3.2.2. 모자이크, 블러 처리

모자이크, 블러 처리로 모자이크는 이미지를 확대 축소를 할 때 생기는 픽셀 개수 차이를 이용하였다.

블러는 cv2.blur를 이용하여 블러 이미지 처리를 하였다.

- mosaic -

mosaic_all_save.py
1	import glob import cv2 def mosaic(img, ratio=0.1): small = cv2.resize(img, None, fx=ratio, fy=ratio, interpolation=cv2.INTER_NEAREST) return cv2.resize(small, img.shape[:2][::-1], interpolation=cv2.INTER_NEAREST) file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count = 0 for i in file_list: print(i) img_name_list.append(i[6:]) img = cv2.imread(i) result2 = mosaic(img, ratio=0.05) cv2.imwrite('./mosaic_img/mosaic_{0}'.format(img_name_list[count]), result2) cv2.waitKey() cv2.destroyAllWindows() count += 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

- blur -

mosaic_blur_save.py
1	import glob import cv2 file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count = 0 for i in file_list: print(i) img_name_list.append(i[6:]) img = cv2.imread(i) ksize = 60 # 블러 처리에 사용할 커널 크기 win_title = 'mosaic' # 창 제목 # img = cv2.imread('./img/elephant.jpg') # 이미지 읽기 roi = cv2.blur(img, (ksize, ksize)) # 블러(모자이크) 처리 # cv2.imshow(win_title, roi) cv2.imwrite('./blur_img/blur_{0}'.format(img_name_list[count]), roi) cv2.waitKey() cv2.destroyAllWindows() count += 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

3.2.3. 렌즈(왜곡) 처리

모자이크, 블러 처리로 모자이크는 이미지를 확대 축소를 할 때 생기는 픽셀 개수 차이를 이용하였다.

블러는 cv2.blur를 이용하여 블러 이미지 처리를 하였다. 크게 볼록, 오목 렌즈와 같은 렌즈처리와

remapping으로 sin, cos 함수와 같은 함수를 통한 왜곡 처리를 활용하였다.

- lens -

remapping_len_save.py – 1
1	import glob import cv2 import numpy as np file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count = 0 for i in file_list: print(i) img_name_list.append(i[6:]) img = cv2.imread(i) print(img.shape) rows, cols = img.shape[:2] indows() count += 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

remapping_len_save.py – 2
20	exp = 2 # 볼록, 오목 지수 (오목 : 0.1 ~ 1, 볼록 : 1.1~) scale = 1 # 변환 영역 크기 (0 ~ 1) # 매핑 배열 생성 mapy, mapx = np.indices((rows, cols),dtype=np.float32) # 좌상단 기준좌표에서 -1~1로 정규화된 중심점 기준 좌표로 변경 mapx = 2*mapx/(cols-1)-1 mapy = 2*mapy/(rows-1)-1 # 직교좌표를 극 좌표로 변환 r, theta = cv2.cartToPolar(mapx, mapy) # 왜곡 영역만 중심확대/축소 지수 적용 r[r< scale] = r[r<scale] ** exp # 극 좌표를 직교좌표로 변환 mapx, mapy = cv2.polarToCart(r, theta) # 중심점 기준에서 좌상단 기준으로 변경 mapx = ((mapx + 1)*cols-1)/2 mapy = ((mapy + 1)*rows-1)/2 # 재매핑 변환 distorted = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) cv2.imwrite('./lens_img/lens_{0}'.format (img_name_list[count]), distorted) cv2.waitKey() cv2.destroyAllWindows
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

- remapping -

remapping_function_save.py
1	import glob import cv2 import numpy as np file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count = 0 for i in file_list: print(i) img_name_list.append(i[6:]) img = cv2.imread(i) l = 20 # 파장(wave length) amp = 15 # 진폭(amplitude) rows, cols = img.shape[:2] # 초기 매핑 배열 생성 ---① mapy, mapx = np.indices((rows, cols),dtype=np.float32) # sin, cos 함수를 적용한 변형 매핑 연산 ---② sinx = mapx + amp * np.sin(mapy/l) cosy = mapy + amp * np.cos(mapx/l) # 영상 매핑 ---③ img_sinx=cv2.remap(img, sinx, mapy, cv2.INTER_LINEAR) # x축만 sin 곡선 적용 img_cosy=cv2.remap(img, mapx, cosy, cv2.INTER_LINEAR) # y축만 cos 곡선 적용 # x,y 축 모두 sin, cos 곡선 적용 및 외곽 영역 보정 img_both=cv2.remap(img, sinx, cosy, cv2.INTER_CUBIC, \ None, cv2.BORDER_REPLICATE) cv2.imwrite('./remapping_img/remapping_{0}'.format(img_name_list[count]), img_both) cv2.waitKey() cv2.destroyAllWindows() count += 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

3.2.4. 랜덤 이미지 처리

랜덤 이미지를 자르기 위해 roi(관심영역)을 지정하고 이미지의 모양값을 기준으로 분할하고 합치는

로직을 이용하였다.

- random -

random_image_save.py - 1
1	import glob import random import cv2 import numpy as np file_list = glob.glob('.\\img\\*.jpg') img_name_list = [] count_jdg = 0 for i in file_list: print(i) img_name_list.append(i[6:]) img = cv2.imread(i) # img = cv2.blur(img, (20, 20)) for j in range(9): globals()['org_{0}'.format(j)] = img.copy() print(img.shape) row, col = img.shape[:2] row_list = [row/3, row*2/3, row] col_list = [col/3, col*2/3, col]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

random_image_save.py - 2
27	row_list = list(map(int, row_list)) col_list = list(map(int, col_list)) img_list = [] first_col = 0 count = 0 for col in row_list: first_row = 0 for row in col_list: img_list.append(globals()['org_{0}'.format(count)][first_col:col, first_row:row]) first_row = row first_col = col count += 1 avg_row = int(row/3) avg_col = int(col/3) print(len(img_list)) resize_img_list = [] for x in img_list: resize_img_list.append(cv2.resize(x, (avg_row, avg_col))) cv2.waitKey(0) cv2.destroyAllWindows() # 랜덤으로 순서 섞기 random.shuffle(resize_img_list) test_img_list = [] for k in [0, 3, 6]: x = resize_img_list[k+0] y = resize_img_list[k+1] z = resize_img_list[k+2] test_img_list.append(cv2.hconcat([x, y, z])) test_img = cv2.vconcat([test_img_list[0], test_img_list[1], test_img_list[2]]) # 이미지 출력할 필요가 없다.. cv2.imwrite('./random_img/random_{0}'.format(img_name_list[count_jdg]), test_img) cv2.waitKey(0) count_jdg += 1
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

5. 마무리

5.1. 향후 추진 계획

1학기 발표에서 이용자가 접속을 하고 방을 생성한 후 대기실에 들어간다. 대기실에 들어가면 사용자가 있으며 채팅을 할 수 있고 게임을 할 수 있지만 솔로플레이만 할 수 있었다. 이는 WebSocket과 channels에 대한 지식 부족이 많이 컸었다. 그래서 우리는 기능적인 부분에서 퀴즈 생성 부분, 새로운 기능과 다양한 문제 만들기 등 여러 가지 기능의 필요성을 느꼈다. 앞으로 남은 과정까지 싱글플레이에서 멀티플레이를 하는 게임을 만들고 DB에서 부족한 부분을 추가하며 좀 더 보완되고 추가된 기능 구현을 중심으로 개발 할 것이다.

“What is This?” 줄여서 WITH 프로젝트는 간편하고 손쉬운 방법으로 사용자가 접근할 수 있으며 시간과 장소의 제약없이 여러 사람들과 만날 수 있으며 손쉬운 소통을 할 수 있는 프로젝트이다. 1학기 기간동안 우리의 기대만큼 만들어진 부분도 있었으나 부족하다 생각되는 부분도 많았다. 향후 계획으로 서버를 운영하여 localhost가 아닌 url을 이용하여 접속을 하고 언제 어디서나 인터넷이 있으면 접속해서 가벼운 게임을 즐기고 소통할 수 있는 사이트를 만들 예정이다. 특히 AWS와 도메인 등을 활용하여 접근성을 높일 예정이다.

현재 프로토타입 모델로 기능도 부족하지만 css 부분도 많이 부족한게 사실이다. 게임에서 기능도 중요하지만 UI도 큰 비중으로 들어간다. 현재와 같이 뼈대만 있는 형태가 아닌 css를 통해 좀 더 퀄리티가 높은 사이트를 만들 계획이다.

5.2. 정리

팀장을 많이 해본 편이 아니라서 프로젝트 진행할 때 다소 어려움이 있었다. 하지만 우리의 프로젝트가 좋은 성과를 이루기 위해서는 팀장으로서 팀원을 이끄는 것도 중요한 덕목이다. 이를 위해 매번 팀원들과 스케줄을 조정하고 부족한 부분을 보완하는 것을 중점으로 하였다. 처음에는 부족한 부분도 많았고 막힌 부분도 많았다. 하지만 회의를 통해 조율하고 각자 임무를 분담하면서 능률이 많이 올랐다. 회의를 하면서 서로가 얘기하고 도움을 주면서 만들다보니 예상보다 더 높은 결과물을 도출할 수 있었다. 발표까지 막힘없이 진행되어 큰 행운이였고 앞으로 남은 기간도 좋은 결과가 나오도록 노력할 것이다.

이번 프로젝트에서 channels (web socket)에 대해서 어려움이 많았었다. 우리 프로젝트에 있는 채팅기능과 해당 멀티플레이어 같은 핵심기능들이 모두다 websocket으로 처리가 되어야만 진도를 뺄 수 있는 상황이었는데 socket 부분에서 막히다보니  모든게 잘 안되었다.그나마 jquery로 채팅쪽 부분은 어느정도 구현을 하였다. 이번 방학때 1학기때 부족한 부분들을 학습하여 좀더 완성된 결과물이 나오도록 해야겠다.

이번 프로젝트를 진행하면서 아직 활용하지 못하는 기술들이 많다고 느꼈다. 웹 내에서의 멀티플레이 방식에 있어서 장고의 channels 기능(웹 소켓 기능)을 하나도 활용할 수가 없어 많은 좌절을 겪었다. 방학때 최대한 소켓을 공부하여 마지막 결과물이 나올때 시구상한 대로 바로 실행이 되는 앱이 되었으면 한다. 또한 진행하던 프로젝트를 진행하면서 막혔던 부분도 분명히 많았었다. 하지만 팀원, 팀장의 도움으로 같이 고민하고 헤쳐나가면서 코딩을 진행하였는데 다 같이 고민하고 문제를 해결하는 과정에서 프로젝트의 즐거움을 알았다. 코딩을 하면서 다른 팀원들에게 도움도 같이 줄 수 있을 정도의 정보를 습득하여 다른 팀원이 막혔을 때 도움이 될 수 있는 내가 되도록 노력해야겠다.