Programming

화살표 그리기 회전까지 성공

 2015. 7. 29. 16:26
반응형

//  STREET VIEW ver0.1 :: HANDONG

//

//  Created by Seongho Hong / Mihyun Wendy Yang / on 2015. 7. 16..

//  Copyright (c) 2015년 Seongho Hong. All rights reserved.

//


#define _CRT_SECURE_NO_WARNINGS


#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <iostream>

#include <fstream> // 텍스트 파일 읽기

#include <conio.h> // 방향키 읽기

#include <math.h>


#include <opencv2\core\core.hpp>

#include <opencv2\highgui\highgui.hpp>

#include <opencv2\opencv.hpp>


#define MAX_PICTURE 100

#define MAX_DIRECTION 4

#define MAX_TEXT 256

#define MAX_DIST 10000000000



using namespace std;

using namespace cv;


//입력받은 점의 인덱스와 좌표값

typedef struct pts_info{

int id;

double direc[4];

double length[4]; //0=동, 1=서, 2=남, 3=북

double x, y;

int capturedCompass; // 캡쳐된 당시의 나침반 방향, 자이로센서의 x 축

}PTS_INFO;


// 마우스 이벤트 처리

typedef struct MouseChange{

int direction = -1;

int change = 0;

Size frameSize; // 버튼 영역 설정하려고 받음

int user_dir; // 유저가 바라보는 방향

}MOUSECHANGE;


// 위치 관계표 만들 때 사용

double F_dist(double x1, double y1, double x2, double y2); // 두점 거리

double F_ang(double x1, double y1, double x2, double y2); // 두점 각도

void makeDirectionMap(PTS_INFO dstMap[MAX_PICTURE],int &out_num_pic); // 관계표 만들기


// 스트리트 뷰 화면 구현에 사용

void showRelation(int(*map)[MAX_DIRECTION]); // 콘솔창에 사진간의 관계 보여주기

void showDirMap(PTS_INFO *dirMap,int in_num_pic); // 콘솔창에 사진간의 관계 보여주기

int getDirection(int inputKey); // eswn 으로 동서남북 이동

int getAsciiDirection(int inputKey); // 방향키로 동서남북 이동

String getFileName(PTS_INFO map, int compass); // 숫자 넣으면 .jpg로 만들어주기

void readText(String fileName, PTS_INFO* &io_dstMap); // 텍스트 파일에서 사진 관계 불러오기

void slideImage(Mat & io_streetImage, PTS_INFO map, MOUSECHANGE & io_mouse, int & io_user_compass, int in_indexNum); //좌우 화면 전환


// 스트리트 뷰 화면 컨트롤

//void drawArrow(Mat img, int map[MAX_DIRECTION]); // 화살표 그리기

void drawArrowAndGps(Mat img, PTS_INFO mapint, int & in_user_compass);

void callBackFunc(int event, int x, int y, int flags, void* userdata); // 마우스 클릭 이벤트


// 창 이름

const char* win_name = "STREET VIEW ver0.1 :: HANDONG";

const char* txtFileName = "20150729151637.txt";

const int N = 0, W = 1, S = 2, E = 3;


int main(){


PTS_INFO dirMap[MAX_PICTURE];

int num_pic;


makeDirectionMap(dirMap,num_pic);

showDirMap(dirMap, num_pic);


//변수 초기화

int index = 0;

int indexNum = 0;

int user_compass = 0;


//인덱스 받고 첫화면

cout << "input index number : ";

cin >> indexNum;

if ((MAX_PICTURE < indexNum) || (indexNum < 0)){

cout << "Error : out of range !" << endl;

cout << "You have to input 0 < input < " << MAX_PICTURE << endl;

return -1;

}

Mat streetImage = imread(getFileName(dirMap[indexNum], 0)); //사진 불러오기 

MOUSECHANGE mouse;

namedWindow(win_name, WINDOW_NORMAL);

setMouseCallback(win_name, callBackFunc, &mouse); // 마우스 클릭 이벤트 설정

drawArrowAndGps(streetImage, dirMap[indexNum], user_compass);// 화살표 생성

imshow(win_name, streetImage);

resizeWindow(win_name, 640, 480);

mouse.frameSize = streetImage.size();


while ((mouse.change == 0) || (dirMap[indexNum].direc[mouse.direction] == -1)){

waitKey(20);

}


Mat temp = streetImage.clone();


while (1){

if ((mouse.change == 1) && (dirMap[indexNum].direc[mouse.direction] != -1) ){ // 가고자 하는 방향에 사진이 있을 때만

indexNum = dirMap[indexNum].direc[mouse.direction]; //indexNUm에 그 사진 index 넣어주기

streetImage = imread(getFileName(dirMap[indexNum], user_compass), 1); // 사진 불러오기

drawArrowAndGps(streetImage, dirMap[indexNum], user_compass); // 화살표 생성


imshow(win_name, streetImage);

mouse.frameSize = streetImage.size();

}

slideImage(streetImage, dirMap[indexNum], mouse, user_compass, indexNum); // 왼쪽 오른쪽 UI


mouse.change = 0; // 0으로 바꿔주어 다시 마우스 클릭 됐을 때를 알 수 있도록

waitKey(200);

}


//종료

destroyWindow(win_name);

return 0;

}


///////////////////////////////////

//////스트리트 뷰 화면 컨트롤//////

///////////////////////////////////


// jpg 파일 이름 받아오기

// compass에는 사용자가 바라보고 있는 방향 정보를 받아옴

// 기본값으로 동쪽으로 설정 0 

String getFileName(PTS_INFO map, int compass){

// 0 북 1 서 2 남 3 동

char buf[MAX_TEXT];

sprintf(buf, "OH3F\\idx%d_camera%d.jpg", map.id,compass);

//sprintf(buf, "%d.jpg", fileIndex,compass);


String dst = buf;

cout << buf << endl;

return dst;

}


// index들의 관계 보여주기

void showRelation(int(*map)[MAX_DIRECTION]){


cout << "########### STREET VIEW ver1.0 ##########" << endl;

cout << "#index\t북\t서\t남\t동\t#" << endl;


for (int i = 0; i < MAX_PICTURE; i++){

cout << "# " << i << '\t';

for (int j = 0; j < MAX_DIRECTION; j++){

cout << map[i][j] << '\t';

}

cout << "#" << endl;

}

cout << "#########################################" << endl;

}


// 좌표 받은 것의 관계 보여주기

void showDirMap(PTS_INFO* in_dstMap,int in_num_pic){

cout << "########### STREET VIEW ver1.0 ##########" << endl;

cout << "#index\t북\t서\t남\t동\t#" << endl;


for (int i = 0; i < in_num_pic; i++){

cout << "# " << i << '\t';

for (int j = 0; j < MAX_DIRECTION; j++){

cout << in_dstMap[i].direc[j] << '\t';

}

cout << "#" << endl;

}

cout << "#########################################" << endl;

}


// txt 읽기

void readText(String fileName, PTS_INFO* &io_dstMap){

ifstream file(fileName);

if (!file.is_open()){

cout << "file is not exist" << endl;

return;

}

char buffer[MAX_TEXT];

char* token;

int i = 0;

while (!file.eof()){


file.getline(buffer, 100);

token = strtok(buffer, "\"id");


for (int j = 0; token != NULL; j++){

if (j == 0){

io_dstMap[i].id = atoi(token);

cout << token << endl;

}

else if (j == 2){ // 3번째

io_dstMap[i].y = atof(token);

cout << i << " : y 좌표 " << token << endl;

}

else if (j == 3){ // 4번째

io_dstMap[i].x = atof(token);

cout << i << " : x 좌표 " << token << endl;

}

else if (j == 5) { //6번째

io_dstMap[i].capturedCompass = atoi(token);

cout << i << " : 촬영 될 때 나침반 각도" <<token << endl;

}

token = strtok(NULL, "\";");

}

i++;

cout << endl;

}

file.close();

}


// 마우스 이벤트

void callBackFunc(int event, int x, int y, int flags, void* userdata){


MOUSECHANGE* mouse = (MOUSECHANGE*)userdata;

int rows = mouse->frameSize.height;

int cols = mouse->frameSize.width;

if (event == EVENT_LBUTTONDOWN){

//cout << "Left button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;

// if 화살표 위를 클릭하면 동, 서, 남, 북

//cout << "cols가로" << cols/2 << endl;

//cout << "rows세로" << rows / 2 << endl;


if (((x> cols / 2) && (x < cols / 2 + 100)) && (y>rows / 2 - 25) && (y < rows / 2 + 25)){

mouse->direction = 3; //동

mouse->change = 1;

}

else if (((x>cols / 2-100) && (x < cols / 2)) && (y>rows / 2 - 25) && (y < rows / 2 + 25)){

mouse->direction = 1; //서

mouse->change = 1;

}

else if (((x>cols / 2 -25 ) && (x < cols / 2 + 25)) && (y>rows / 2 ) && (y < rows / 2 + 50)){

mouse->direction = 2; //남

mouse->change = 1;

//cout << "남" << endl;

}

else if (((x>cols / 2 - 25) && (x < cols / 2 + 25)) && (y>rows / 2 -50 ) && (y < rows / 2)){

mouse->direction = 0; //북

mouse->change = 1;

//cout << "북" << endl;

}


// 왼쪽 오른쪽 여백

if ((x > 0) && (x < cols * 1 / 15) && (y>0) && (y < rows)){

//cout << "hi" << endl;

mouse->change = 2;

}

else if ((x> cols * 14 / 15) && (x < cols) && (y>0) && (y < rows)){

//cout << "there" << endl;

mouse->change = 3;

}


}

else if (event == EVENT_RBUTTONDOWN){

//cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;

}

else if (event == EVENT_MBUTTONDOWN){

//cout << "Middle button of the mouse is clicked - position (" << x << ", " << y << ")" << endl;

}

else if (event == EVENT_MOUSEMOVE){

//cout << "Mouse move over the window - position (" << x << ", " << y << ")" << endl;

}

}


//화살표 그려주기

void drawArrowAndGps(Mat img, PTS_INFO map,int & in_user_compass){

// user compass에서 0번 카메라의 나침반을 가져왔다고 생각하면



if (map.direc[in_user_compass % 4] != -1){ // 북

arrowedLine(img, Point(img.cols / 2, img.rows / 2), Point(img.cols / 2, img.rows / 2 - 50), Scalar(255, 255, 255), 5);

}

if (map.direc[(in_user_compass + 1) % 4] != -1){ // 서

arrowedLine(img, Point(img.cols / 2, img.rows / 2), Point(img.cols / 2 - 100, img.rows / 2), Scalar(255, 255, 255), 5);

}

if (map.direc[(in_user_compass + 2) % 4] != -1){ // 남

arrowedLine(img, Point(img.cols / 2, img.rows / 2), Point(img.cols / 2, img.rows / 2 + 50), Scalar(255, 255, 255), 5);

}

if (map.direc[(in_user_compass + 3) % 4] != -1){ // 동

arrowedLine(img, Point(img.cols / 2, img.rows / 2), Point(img.cols / 2 + 100, img.rows / 2), Scalar(255, 255, 255), 5);

}

char xText[MAX_TEXT];

char yText[MAX_TEXT];

sprintf(xText, "X :%f", map.x);

sprintf(yText, "Y :%f", map.y);


putText(img, xText, Point(img.cols * 4 / 5, img.rows * 8 / 10), FONT_HERSHEY_PLAIN, 1, Scalar(255, 255, 255),2);

putText(img, yText, Point(img.cols * 4 / 5, img.rows * 9 / 10), FONT_HERSHEY_PLAIN, 1, Scalar(255, 255, 255), 2);

}



// 좌우 화면 전환

// 마우스 이벤트, 사용자의 시점을 고려

// 이미지, 관계정보, 마우스 처리, 사용자 시점, 인덱스

void slideImage(Mat & io_streetImage, PTS_INFO map, MOUSECHANGE & io_mouse, int & io_user_compass, int in_indexNum){

if (io_mouse.change == 2)

{

if (io_user_compass == E){

io_user_compass = S;

io_streetImage = imread(getFileName(map, io_user_compass), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);

}

else if (io_user_compass == S){

io_user_compass = W;

io_streetImage = imread(getFileName(map, io_user_compass), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);

}

else if (io_user_compass == W){

io_user_compass = N;

io_streetImage = imread(getFileName(map, io_user_compass), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);

}

else if (io_user_compass == N){

io_user_compass = E;

io_streetImage = imread(getFileName(map, io_user_compass), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);

}

io_mouse.user_dir = io_user_compass;


io_mouse.frameSize = io_streetImage.size();


}


else if (io_mouse.change == 3)

{

if (io_user_compass == E){

io_user_compass = N;

io_streetImage = imread(getFileName(map, N), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);

}

else if (io_user_compass == N){

io_user_compass = W;

io_streetImage = imread(getFileName(map, W), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);


}

else if (io_user_compass == W){

io_user_compass = S;

io_streetImage = imread(getFileName(map, S), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);


}

else if (io_user_compass == S){

io_user_compass = E;

io_streetImage = imread(getFileName(map, E), 1);

drawArrowAndGps(io_streetImage, map, io_user_compass); // 화살표 생성

imshow(win_name, io_streetImage);


}

io_mouse.user_dir = io_user_compass;

io_mouse.frameSize = io_streetImage.size();


}

}


/////////////////////////////////////

//////좌표로 부터 관계표 만들기//////

/////////////////////////////////////


//두 점의 거리 계산

double F_dist(double x1, double y1, double x2, double y2){

return sqrt(((x1 - x2)*(x1 - x2)) + ((y1 - y2)*(y1 - y2)));

}


//두 점의 각도 계산

double F_ang(double x1, double y1, double x2, double y2){

return (atan2((double)(y2 - y1), (double)(x2 - x1))*180.0f / 3.14159265);

}


//관계표 만들기

void makeDirectionMap(PTS_INFO* io_dstMap, int &out_num_pic) {



int i = 0, n = 0, j = 0;

printf("점의 갯수를 입력하시오 \n");

cin >> n;


double ang_result[MAX_PICTURE][MAX_PICTURE], dis_result[MAX_PICTURE][MAX_PICTURE];


for (i = 0; i<n; i++){

io_dstMap[i].x = io_dstMap[i].y = 0.0;


for (j = 0; j<4; j++){

io_dstMap[i].length[j] = MAX_DIST;

io_dstMap[i].direc[j] = -1;

}


for (j = 0; j<n; j++)

ang_result[i][j] = dis_result[i][j] = 0.0;

}


readText(txtFileName, io_dstMap);


for (i = 0; i<n; i++){

for (j = 0; j<n; j++){

if (i == j) continue;


ang_result[i][j] = F_ang(io_dstMap[i].x, io_dstMap[i].y, io_dstMap[j].x, io_dstMap[j].y);

dis_result[i][j] = F_dist(io_dstMap[i].x, io_dstMap[i].y, io_dstMap[j].x, io_dstMap[j].y);


//printf("i:%d j:%d %f %f ang %f\n", i, j, io_dstMap[i].x, io_dstMap[i].y, ang_result[i][j]);


if (-45 <= ang_result[i][j] && ang_result[i][j]<45){

//동쪽 0과 1. 0과 3

if (io_dstMap[i].length[3] >= dis_result[i][j]){

io_dstMap[i].direc[3] = j;

io_dstMap[i].length[3] = dis_result[i][j];

}

}


else if (45 <= ang_result[i][j] && ang_result[i][j]<135){

//북쪽

if (io_dstMap[i].length[0] >= dis_result[i][j]){

io_dstMap[i].direc[0] = j;

io_dstMap[i].length[0] = dis_result[i][j];

}

}


else if (135 <= ang_result[i][j] || ang_result[i][j]<-135){

//서쪽

if (io_dstMap[i].length[1] >= dis_result[i][j]){

io_dstMap[i].direc[1] = j;

io_dstMap[i].length[1] = dis_result[i][j];

}

}


else if (-135 <= ang_result[i][j] && ang_result[i][j]<-45){

//남쪽

if (io_dstMap[i].length[2] >= dis_result[i][j]){

io_dstMap[i].direc[2] = j;

io_dstMap[i].length[2] = dis_result[i][j];

}

}

}

}


/*for (i = 0; i<n; i++){

printf("점 %d의 동쪽에는 점: %d, 서쪽에는 점: %d, 남쪽에는 점: %d, 북쪽에는점: %d가 있습니다 \n",

i, io_dstMap[i].direc[0], io_dstMap[i].direc[1], io_dstMap[i].direc[2], io_dstMap[i].direc[3]);

}*/

out_num_pic = n;

}



반응형