▶호롭터와 파눔융합역이란?


호롭터와 파눔융합역은 모두 양안 비젼(두 눈을 사용해서 세상을 바라봄)에서 흔히 사용되는 용어들입니다. 우리의 두 눈은 수평으로 일정한 거리를 두고 분리되어 있습니다. 그래서 두 눈이 바라보는 장면은 거의 같지만 수평적으로 약간 다릅니다. 이 다름(시차, disparity)을 통해 뇌는 깊이에 대한 정보를 얻습니다. 


호롭터는 관찰자로부터 동일한 거리에 위치한 점들을 잇는 곡선을 의미합니다. 즉, 두 눈으로부터 같은 거리에 위치하여 디스패리티가 존재하지 않는 점들을 이은 곡선입니다. 따라서 호롭터 위에 있는 점들은 깊이감 없이 융합됩니다. 그리고 파눔융합역은 두 망막 이미지들이 하나로 융합될 수 있는 호롭터 주변의 구역을 말합니다. 호롭터 위를 제외한 나머지 파눔융합역에서는 디스패리티가 있기 때문에 깊이감을 가지면서 융합됩니다. 디스패리티가 너무 커서 파눔융합역을 벗어나면, 뇌는 융합에 실패하여 복시현상(diplopia)이 나타나고 눈은 상당한 피로를 느끼게 됩니다 [1][2][3]


그림1. 호롭터와 파눔융합역을 설명하는 그림 [1]

  


<참고 자료>

[1] http://www1.appstate.edu/~kms/classes/psy3203/Depth/horopter2.htm

[2] Lambooij M, Fortuin M, Heynderickx I, et al. Visual Discomfort and Visual Fatigue of Stereoscopic Displays: A Review[J]. Journal of Imaging Science & Technology, 2009, volume 53(3):30201-1-30201-14(14).

[3] Park J, Lee S, Bovik A C. 3D Visual Discomfort Prediction: Vergence, Foveation, and the Physiological Optics of Accommodation[J]. IEEE Journal of Selected Topics in Signal Processing, 2014, 8(3):415-427.


오늘 묵상한 본문은 열왕기상 2:7입니다.

마땅히 길르앗 바르실래의 아들들에게 은총을 베풀어 그들이 네 상에서 먹는 자 중에 참여하게 하라 내가 네 형 압살롬의 낯을 피하여 도망할 때에 그들이 내게 나왔느니라

출처: 개역개정 성경

바르실래는 다윗이 자신의 아들인 압살롬에게 반역을 당해서 도망할 때 다윗과 그와 함께 도망친 백성들을 위해 음식을 준비해서 먹게 했습니다. 그 장면은 사무엘하 17:27-29에서 확인할 수 있습니다.

다윗이 마하나임에 이르렀을 때에 암몬 족속에게 속한 랍바 사람 나하스의 아들 소비와 로데발 사람 암미엘의 아들 마길과 로글림 길르앗 사람 바르실래

침상과 대야와 질그릇과 밀과 보리와 밀가루와 볶은 곡식과 콩과 팥과 볶은 녹두와

꿀과 버터와 양과 치즈를 가져다가 다윗과 그와 함께 한 백성에게 먹게 하였으니 이는 그들 생각에 백성이 들에서 시장하고 곤하고 목마르겠다 함이더라

출처: 개역개정 성경

또한 바르실래는 다윗의 군대가 반역군을 진압하고 다시 예루살렘으로 귀환할 때 다윗을 배웅하러 나옵니다 (사무엘하 19:31-36). 

길르앗 사람 바르실래가 왕이 요단을 건너가게 하려고 로글림에서 내려와 함께 요단에 이르니

바르실래는 매우 늙어 나이가 팔십 세라 그는 큰 부자이므로 왕이 마하나임에 머물 때에 그가 왕을 공궤하였더라

왕이 바르실래에게 이르되 너는 나와 함께 건너가자 예루살렘에서 내가 너를 공궤하리라

바르실래가 왕께 아뢰되 내 생명의 날이 얼마나 있사옵겠기에 어찌 왕과 함께 예루살렘으로 올라가리이까

내 나이가 이제 팔십 세라 어떻게 좋고 흉한 것을 분간할 수 있사오며 음식의 맛을 알 수 있사오리이까 이 종이 어떻게 다시 노래하는 남자나 여인의 소리를 알아들을 수 있사오리이까 어찌하여 종이 내 주 왕께 아직도 누를 끼치리이까

당신의 종은 왕을 모시고 요단을 건너려는 것뿐이거늘 왕께서 어찌하여 이같은 상으로 내게 갚으려 하시나이까

그저 바르실래는 다윗이 다시 왕으로 귀환하는 그 사실 자체가 감사했던 것 같습니다. 자신이 마하나임에서 다윗에게 베푼 선행에 대한 어떤 보상을 받고자하는 마음을 조금도 찾아볼 수 없습니다. 이제 죽음을 앞두고 있는 다윗은 바르실래에게 받은 은혜를 기억합니다. 그리고 아들 솔로몬에게 바르실래의 아들들에게 은총을 베풀라고 유언을 남깁니다. 

지금껏 30년을 살아가면서 형용할 수 없는 은혜를 하나님께, 부모님께, 친척분들께, 그리고 수많은 선배, 친구, 후배들에게 받아왔습니다. 너무나 당연하게 여기며 살았던 것 같습니다. 갚을 수 없다는 것 잘 알지만, 그 은혜를 기억하고 최선으로 보답하려는 행동이 부족하지 않았나 생각됩니다. 주변의 누군가에게 관심을 갖고 마음과 시간과 돈을 들여 돕는다는 것이 쉽지 않은 일인데, 왜 이렇게 저는 당연하게만 생각해왔던 것일까요? 주님, 철저히 자기 중심적이고 이기적인 제 생각을 고쳐주세요. 은혜를 기억하고 감사하고 보답하는 사람되게 해주세요. 

optic flow software 매트랩 소스코드는 [1]에서 다운로드 받으실 수 있습니다. 그리고 이 소프트웨어와 관련된 논문은 [2]입니다. [3] 논문에서 이 소프트웨어를 활용해서 디스패리티 맵을 산출한 것을 따라서 저도 디스패리티 맵을 산출해보려고 합니다. 소프트웨어를 통해 산출된 모션 벡터들에서 수평 성분을 수평 디스패리티로 사용했습니다.



1. 소스코드 테스트


그림 1은 테스트에 사용된 이미지들[4]과 ground truth 디스패리티 맵과 산출된 디스패리티 맵을 보여줍니다. 밝을 수록 카메라로부터 가깝고, 어두울 수록 멀다는 것을 의미합니다. 이 소프트웨어를 활용해서 산출한 디스패리티 맵이 상당히 거리감을 잘 나타냄을 그림을 통해 알 수 있습니다. 

그림1. 왼쪽 뷰, 오른쪽 뷰, ground truth disparity map, 산출된 disparity map





2. 참고 자료

[1] http://ps.is.tue.mpg.de/person/black#tabs-code 

[2] Secrets of optical flow estimation and their principles, Sun, D., Roth, S., and Black, M. J., IEEE Conf. on Computer Vision and Pattern Recog., CVPR, June 2010.

[3] J Park, S Lee, AC Bovik, 3d visual discomfort prediction: vergence, foveation, and the physiological optics of accommodation. IEEE J. Sel. Top. Sign. Process. 8(3), 415–427 (2014)

[4] http://vision.middlebury.edu/stereo/data/



원래 GBVS 매트랩 소스코드는 [1]에서 받을 수 있습니다. 근데 지금 이 사이트가 안들어가지네요. 그래서 혹시 소스코드 필요하신 분은 댓글에 이메일주소 남기시면 보내드리겠습니다. 그리고 GBVS에 대한 논문은 [2]입니다.


1. 소스코드 테스트

소스코드를 다운 받으시면 폴더 내에 readme.txt에 어떻게 사용하는지 구체적으로 자세히 나와있습니다. 혹시 잘 모르시겠다면 댓글 달아주세요. 네 장의 사진의 GBVS를 통해 얻은 saliency 맵은 그림1에 있습니다. 밝을 수록 시각적으로 중요하다고 판단한 부분입니다. 

 

그림1. gbvs로 얻은 saliency 맵들


첫번째 빨간 차가 있는 사진을 제외하고는 적절하게 시각적 중요도에 따라 saliency 맵들이 산출된 것 같습니다. GBVS로 얻은 saliency 맵만 봐서는 GBVS가 효과적인지 아닌지 판단하기 어려우니 다른 saliency 알고리즘도 사용해보겠습니다. 위에 소개드린 GBVS 매트랩 소스코드를 담은 폴더 내에 [3]에서 제안한 알고리즘의 소스코드도 포함되어 있습니다. 그림2는 [3]을 사용해 얻은 saliency 맵들입니다. 


그림2. [3]이 제안하는 모델로 얻은 saliency 맵들


이 방법도 괜찮은 결과를 산출하는 것 같습니다. 개인적인 소견으로 사람이 있는 사진에서는 GBVS가 좀 더 나은 saliency 맵을 만들어내는 것 같고, 풍경 사진에서는 [3]이 좀 더 나은 결과를 내는 것 같습니다. 


2. 참고 자료

[1] http://www.klab.caltech.edu/~harel/share/gbvs.php 

[2] J. Harel, C. Koch, and P. Perona. "Graph-Based Visual Saliency", NIPS 2006

[3] L. Itti, C. Koch, & E. Niebur "A model of saliency based visual attention for rapid scene analysis", IEEE Transactions on Pattern Analysis and Machine 1998


오늘은 http://opencvexamples.blogspot.com/p/learning-opencv-functions-step-by-step.html에 있는 세번째 예제를 따라해보도록 하겠습니다. 


3. Basic drawing examples

1) 선 그리기

소스코드부터 보시죠. 

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 


// Draw a line 

line(image, Point(15, 20), Point(300, 350), Scalar(0, 255, 0), 10, 8); 

imshow("Image", image);

imwrite("result.bmp", image);


waitKey(0);

return(0);

}

링크의 예제에서는 #include <opencv2/imgproc/imgproc.hpp>가 없는데, 이걸 포함해줘야 line 함수를 사용할 수 있습니다. 

line 함수에 대해서 아는 한 설명을 해보겠습니다. 

line(image, Point(15, 20), Point(300, 350), Scalar(0, 255, 0), 10, 8); 

  • 1번째 인수: 도화지가 되어줄 이미지를 넣어줍니다. 
  • 2번째, 3번째 인수: 어디서부터 어디까지 선을 그릴지 픽셀 위치들을 뜻합니다. 즉 (15, 20)부터 (300, 350)을 잇는 선을 그리겠다는 것입니다. 

  • 4번째 인수: 선의 색을 결정지어줍니다. Scalar(0, 255, 0)은 녹색 선을 그리겠다는 것입니다. BGR순서로 되어 있습니다. 만약 Scalar(0, 0, 255)라고 세팅-하면 빨간색 선이 될 것입니다. 
  • 5번째 인수: 선의 굵기를 선택합니다. 클수록 굵어집니다.
  • 6번째 인수: 라인의 타입을 결정해줍니다. (이것의 역할은 잘 몰라서, 일단 그냥 default값으로 놔두겠습니다.)

실행결과 아래와 같은 이미지가 전시되고, 저장됩니다.



2) 원 그리기

이번에는 원을 그려보도록 하겠습니다. 

소스코드는 아래와 같습니다. 

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 


// Draw a circle 

circle(image, Point(200, 200), 32.0, Scalar(0, 0, 255), 5, 8); 

  circle(image, Point(100, 300), 40.0, Scalar(255, 0, 255), 10, 8);

imshow("Image", image);

imwrite("result.bmp", image);


waitKey(0);

return(0);

}

circle 함수 

  • 1번째 인수: 역시 도화지가 되어줄 이미지입니다. 여기서는 400 x 400의 검정 이미지이겠지요? 
  • 2번째 인수: 원의 중심의 픽셀 위치입니다. 
  • 3번째 인수: 원의 반지름입니다. 
  • 4번째 인수: 원의 색깔로 역시 BGR순서로 되어 있습니다. 첫번째 원은 빨간 색이 되게 Scalar(0, 0, 255)로 설정했습니다. 
  • 5번째 인수: 원의 두께를 결정해주는 것입니다. 클수록 두꺼워집니다. 
  • 6번째 인수: 라인의 타입을 결정해주는 것입니다. 

line함수의 인수들의 진행패턴과 크게 다르지 않습니다. 아래 그림은 결과로 그려진 두 개의 원을 보여줍니다. 



3) 타원 그리기

이번에는 타원을 그리겠습니다. 

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 


// Draw a ellipse

        ellipse(image, Point(200, 200), Size(100.0, 160.0), 45, 0, 360, Scalar(255, 0, 0), 1, 8);

ellipse(image, Point(200, 200), Size(100.0, 160.0), 0, 0, 360, Scalar(255, 0, 0), 5, 8);

ellipse(image, Point(200, 200), Size(100.0, 160.0), 135, 0, 360, Scalar(255, 0, 0), 10, 8);

imshow("Image", image);

imwrite("result.bmp", image);


waitKey(0);

return(0);

}

ellipse 함수가 타원을 그릴 때 사용하는 함수입니다. 

  • 1번째 인수: 도화지가 될 이미지입니다. 
  • 2번째 인수: 타원의 중심위치입니다. 
  • 3번째 인수: 타원축들의 길이를 의미합니다. 즉, 세번째 인수가 Size(100,0, 160,0)라면 x축으로는 100만큼, y축으로는 160만큼 긴 모양의 타원을 만들겠다는 것입니다. 
  • 4번째 인수: 타원이 회전된 각도입니다. 첫번째 타원의 경우 45도만큼 오른쪽으로 회전시키겠다는 것입니다. 
  • 5번째, 6번째 인수: 타원이 시작하는 각도와 끝나는 각도를 결정지어주는 것인데 완전한 타원을 그리고 싶다면 0, 360으로 설정해주면 됩니다. 
  • 7번째 인수: 색을 결정해주는 것입니다. 세 타원 모두 파란색으로 설정해줬습니다. 
  • 8번째 인수: 타원의 굵기를 결정해주는 것입니다. 크면 클수록 굵어집니다. 
  • 9번째 인수: 역시 선의 타입을 결정해주는 것입니다. 

아래 그림은 결과적으로 그려진 3개의 타원을 보여줍니다. 뭔가 멋있네요. 



4) 직사각형 그리기

직사각형 그리는 코드입니다.

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 


// Draw a rectangle

rectangle(image, Point(15, 20), Point(70, 50), Scalar(0, 55, 255), +1, 4); 

rectangle(image, Point(200, 300), Point(300, 350), Scalar(100, 100, 0), -1, 8); 

imshow("Image", image);

imwrite("result.bmp", image);


waitKey(0);

return(0);

}

직사각형을 그려주는 rectangle 함수를 살펴봅시다. 

  • 1번째 인수: 도화지가 되어줄 이미지입니다.
  • 2번째 인수: 직사각형의 왼쪽 상단 모서리 픽셀 위치입니다.
  • 3번째 인수: 직사각형의 오른쪽 하단 모서리 픽셀 위치입니다.
  • 4번째 인수: 색을 결정해줍니다.
  • 5번째 인수: 양수면 빈 직사각형, 음수면 채워진 직사각형을 만듭니다.
  • 6번째 인수: 라인의 타입을 결정해줍니다. 

구현된 결과이미지입니다. 하나의 빈 직사각형과 하나의 채워진 직사각형을 보실 수 있습니다.




5) 다각형 그리기

이번에는 채워져있는 다각형을 그려보겠습니다. 

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 


int w = 400;

/** Create some points */

Point rook_points[1][20]; // 여기서 rook는 체스의 말의 이름입니다.

rook_points[0][0] = Point(w / 4.0, 7 * w / 8.0);

rook_points[0][1] = Point(3 * w / 4.0, 7 * w / 8.0);

rook_points[0][2] = Point(3 * w / 4.0, 13 * w / 16.0);

rook_points[0][3] = Point(11 * w / 16.0, 13 * w / 16.0);

rook_points[0][4] = Point(19 * w / 32.0, 3 * w / 8.0);

rook_points[0][5] = Point(3 * w / 4.0, 3 * w / 8.0);

rook_points[0][6] = Point(3 * w / 4.0, w / 8.0);

rook_points[0][7] = Point(26 * w / 40.0, w / 8.0);

rook_points[0][8] = Point(26 * w / 40.0, w / 4.0);

rook_points[0][9] = Point(22 * w / 40.0, w / 4.0);

rook_points[0][10] = Point(22 * w / 40.0, w / 8.0);

rook_points[0][11] = Point(18 * w / 40.0, w / 8.0);

rook_points[0][12] = Point(18 * w / 40.0, w / 4.0);

rook_points[0][13] = Point(14 * w / 40.0, w / 4.0);

rook_points[0][14] = Point(14 * w / 40.0, w / 8.0);

rook_points[0][15] = Point(w / 4.0, w / 8.0);

rook_points[0][16] = Point(w / 4.0, 3 * w / 8.0);

rook_points[0][17] = Point(13 * w / 32.0, 3 * w / 8.0);

rook_points[0][18] = Point(5 * w / 16.0, 13 * w / 16.0);

rook_points[0][19] = Point(w / 4.0, 13 * w / 16.0);


const Point* ppt[1] = { rook_points[0] };

int npt[] = { 20 };


fillPoly(image, ppt, npt, 1, Scalar(255, 255, 255), 8);

imshow("Image", image);

imwrite("result.bmp", image);


waitKey(0);

return(0);

}

fillPoly함수의 인수들을 살펴봅시다. 

  • 1번째 인수: 도화지가 될 이미지입니다.
  • 2번째 인수: 꼭지점들을 담고 있는 배열입니다. (Array of polygons where each polygon is represented as an array of points)
  • 3번째 인수: 꼭지점들의 갯수를 담고 있는 배열입니다. (Array of polygon vertex counters)
  • 4번째 인수: 색으로 채워진 지역을 감싸는 가장자리의 갯수를 설정해줍니다. (Number of contours that bind the filled region)
  • 5번째 인수: 다각형의 색을 설정합니다.
  • 6번째 인수: 라인의 타입을 결정해줍니다.

아래 그림과 같이 체스의 rook가 그려집니다.


이번에는 fillPoly 함수를 사용해서 다각형 중의 하나인 삼각형을 하나 그려보겠습니다. 코드는 아래와 같습니다.

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 


int w = 400;

/** Create some points */

Point rook_points[1][3]; // 여기서 rook는 체스의 말의 이름입니다.

rook_points[0][0] = Point(w / 2.0, w / 4.0); // Point(가로 픽셀 위치, 세로 픽셀 위치)

rook_points[0][1] = Point(w / 4.0, 3 * w / 4.0);

rook_points[0][2] = Point(3 * w / 4.0, 3 * w / 4.0);

const Point* ppt[1] = { rook_points[0] };

int npt[] = { 3 };


fillPoly(image, ppt, npt, 1, Scalar(255, 255, 255), 8);

imshow("Image", image);

imwrite("result.bmp", image);


waitKey(0);

return(0);

}

삼각형을 그리므로 세 점만 있으면 됩니다. 그려진 그림은 아래와 같습니다.




6) 이미지에 텍스트 넣기

이제 마지막으로 이미지에 텍스트 넣는 것을 따라해보겠습니다. 
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;

int main()
{
// Create black empty images
Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검정 이미지를 만든다. 

putText(image, "God is good!", Point(50, 100), FONT_HERSHEY_PLAIN, 2, Scalar(0, 200, 200), 3); //이미지에 텍스트 넣기
imshow("Image", image);
imwrite("result.bmp", image);

waitKey(0);
return(0);
}
putText 함수를 살펴봅시다.
  • 1번째 인수: 도화지가 될 이미지입니다.
  • 2번째 인수: 텍스트 내용을 적어줍니다.
  • 3번째 인수: 이미지에서 텍스트가 배치될 위치를 결정해줍니다. 텍스트 스트링의 왼쪽 아래 위치가 됩니다. 
  • 4번째 인수: 폰트를 선택합니다. FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_PLAIN,FONT_HERSHEY_DUPLEX, FONT_HERSHEY_COMPLEX, FONT_HERSHEY_TRIPLEX,FONT_HERSHEY_COMPLEX_SMALL, FONT_HERSHEY_SCRIPT_SIMPLEX, FONT_HERSHEY_SCRIPT_COMPLEX
  • 5번째 인수: 글자의 크기를 결정합니다. 
  • 6번째 인수: 글자의 색을 선택합니다.
  • 7번째 인수: 글자의 두께를 선택합니다. 
실행결과를 보시죠.

이번 예제는 조금 길었네요. 그리기 함수들을 이용해서 간단한 이미지를 하나 그려보겠습니다. 재미를 위해서..ㅎㅎ 아래 그림 중에서 왼쪽 아래에 있는 집을 한번 따라 그려보겠습니다. 그림의 출처는 http://cafe.naver.com/logo12/1692719입니다.


사실 노가다지만, 그래도 함수들 확실히 익힐겸 해봤습니다. 코드는 아래와 같습니다.

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;


int main()

{

// Create black empty images

Mat image = Mat::zeros(400, 400, CV_8UC3); // 세로, 가로 각각 400, 400 사이즈의 검은색 이미지를 만든다. 

rectangle(image, Point(0, 0), Point(399, 399), Scalar(255, 255, 255), -1, 8); // 흰색 도화지로 바꿔준다. 

// 큰 지붕, 다각형 함수 활용

int w = 400;

Point roof1_points[1][4];

roof1_points[0][0] = Point(140, 40);   

roof1_points[0][1] = Point(260, 40);

roof1_points[0][2] = Point(360, 160);

roof1_points[0][3] = Point(40, 160);

const Point* ppt1[1] = { roof1_points[0] };

int npt1[] = { 4 };

fillPoly(image, ppt1, npt1, 1, Scalar(30, 30, 30), 8);


// 건물의 몸통. 직사각형 함수 활용

rectangle(image, Point(70, 161), Point(330, 340), Scalar(150, 150, 150), -1, 8);

rectangle(image, Point(70, 341), Point(330, 360), Scalar(30, 30, 30), -1, 8);


// 작은 지붕

Point roof2_points[1][4];

roof2_points[0][0] = Point(160, 100);

roof2_points[0][1] = Point(240, 100);

roof2_points[0][2] = Point(300, 172);

roof2_points[0][3] = Point(100, 172);


const Point* ppt2[1] = { roof2_points[0] };

int npt2[] = { 4 };

fillPoly(image, ppt2, npt2, 1, Scalar(60, 60, 60), 8);


// 중간에 회색 두 줄

rectangle(image, Point(150, 173), Point(160, 340), Scalar(100, 100, 100), -1, 8);

rectangle(image, Point(240, 173), Point(250, 340), Scalar(100, 100, 100), -1, 8);

//굴뚝

Point chimney_points[1][4];

chimney_points[0][0] = Point(70, 60);

chimney_points[0][1] = Point(92, 60);

chimney_points[0][2] = Point(92, 97);

chimney_points[0][3] = Point(70, 124);


const Point* ppt3[1] = { chimney_points[0] };

int npt3[] = { 4 };

fillPoly(image, ppt3, npt3, 1, Scalar(60, 60, 60), 8);


//굴뚝 덮개 

rectangle(image, Point(67, 48), Point(95, 59), Scalar(30, 30, 30), -1, 8);


//문

rectangle(image, Point(172, 252), Point(228, 340), Scalar(70, 70, 90), -1, 8);


//문에 있는 창문 두 개

rectangle(image, Point(180, 264), Point(190, 288), Scalar(255, 200, 150), -1, 8);

rectangle(image, Point(210, 264), Point(220, 288), Scalar(255, 200, 150), -1, 8);


//문에 있는 점 두 개, 원 그리기 활용

circle(image, Point(190, 300), 2, Scalar(30, 30, 30), 2, 8);

circle(image, Point(210, 300), 2, Scalar(30, 30, 30), 2, 8);


//중간 원형 창문의 테두리

circle(image, Point(200, 210), 18, Scalar(55, 55, 55), 10, 8);


//중간 원형 창문

circle(image, Point(200, 210), 8, Scalar(255, 200, 150), 18, 8);


//중간 원형 창문 십자

rectangle(image, Point(199, 190), Point(201, 230), Scalar(55, 55, 55), -1, 8);

rectangle(image, Point(180, 209), Point(220, 211), Scalar(55, 55, 55), -1, 8);


//왼쪽 상단 창문 회색 틀

rectangle(image, Point(85, 240), Point(135, 247), Scalar(55, 55, 55), -1, 8);


//왼쪽 상단 창문 검은 틀

Point win1_points[1][4];

win1_points[0][0] = Point(88, 248);

win1_points[0][1] = Point(132, 248);

win1_points[0][2] = Point(127, 255);

win1_points[0][3] = Point(93, 255);


const Point* win1_ppt[1] = { win1_points[0] };

int win1_npt[] = { 4 };

fillPoly(image, win1_ppt, win1_npt, 1, Scalar(30, 30, 30), 8);


//왼쪽 상단 창문

rectangle(image, Point(88, 190), Point(132, 239), Scalar(255, 200, 150), -1, 8);


//왼쪽 상단 창문 십자

rectangle(image, Point(88, 215), Point(132, 217), Scalar(55, 55, 55), -1, 8);

rectangle(image, Point(109, 190), Point(111, 239), Scalar(55, 55, 55), -1, 8);

//오른쪽 상단 창문 회색 틀

rectangle(image, Point(265, 240), Point(315, 247), Scalar(55, 55, 55), -1, 8);


//오른쪽 상단 창문 검은 틀

Point win2_points[1][4];

win2_points[0][0] = Point(268, 248);

win2_points[0][1] = Point(312, 248);

win2_points[0][2] = Point(307, 255);

win2_points[0][3] = Point(273, 255);


const Point* win2_ppt[1] = { win2_points[0] };

int win2_npt[] = { 4 };

fillPoly(image, win2_ppt, win2_npt, 1, Scalar(30, 30, 30), 8);


//오른쪽 상단 창문

rectangle(image, Point(268, 190), Point(312, 239), Scalar(255, 200, 150), -1, 8);


//오른쪽 상단 창문 십자

rectangle(image, Point(268, 215), Point(312, 217), Scalar(55, 55, 55), -1, 8);

rectangle(image, Point(289, 190), Point(291, 239), Scalar(55, 55, 55), -1, 8);


//왼쪽 하단 창문 회색 틀

rectangle(image, Point(85, 315), Point(135, 322), Scalar(55, 55, 55), -1, 8);


//왼쪽 하단 창문 검은 틀

Point win3_points[1][4];

win3_points[0][0] = Point(88, 323);

win3_points[0][1] = Point(132, 323);

win3_points[0][2] = Point(127, 330);

win3_points[0][3] = Point(93, 330);


const Point* win3_ppt[1] = { win3_points[0] };

int win3_npt[] = { 4 };

fillPoly(image, win3_ppt, win3_npt, 1, Scalar(30, 30, 30), 8);

//왼쪽 하단 창문

rectangle(image, Point(88, 265), Point(132, 314), Scalar(255, 200, 150), -1, 8);


//왼쪽 하단 창문 십자

rectangle(image, Point(88, 290), Point(132, 292), Scalar(55, 55, 55), -1, 8);

rectangle(image, Point(109, 265), Point(111, 314), Scalar(55, 55, 55), -1, 8);

//오른쪽 하단 창문 회색 틀

rectangle(image, Point(265, 315), Point(315, 322), Scalar(55, 55, 55), -1, 8);


//오른쪽 하단 창문 검은 틀

Point win4_points[1][4];

win4_points[0][0] = Point(268, 323);

win4_points[0][1] = Point(312, 323);

win4_points[0][2] = Point(307, 330);

win4_points[0][3] = Point(273, 330);


const Point* win4_ppt[1] = { win4_points[0] };

int win4_npt[] = { 4 };

fillPoly(image, win4_ppt, win4_npt, 1, Scalar(30, 30, 30), 8);


//오른쪽 하단 창문

rectangle(image, Point(268, 265), Point(312, 314), Scalar(255, 200, 150), -1, 8);


//오른쪽 하단 창문 십자

rectangle(image, Point(268, 290), Point(312, 292), Scalar(55, 55, 55), -1, 8);

rectangle(image, Point(289, 265), Point(291, 314), Scalar(55, 55, 55), -1, 8);



imshow("Image", image);

imwrite("result.bmp", image);



waitKey(0);

return(0);

}


구현된 이미지는 밑에 있습니다. 사실 그냥 노가다였지만 나름 성취감이 있네요. ㅋㅋ 창문에 햇살 비친 것까지 하긴 너무 귀찮아서 패스했습니다. 






오늘 묵상한 본문은 요한복음 18:3-6입니다.

유다가 군대와 대제사장과 바리새인들에게서 얻은 아랫사람들을 데리고 등과 횃불과 무기를 가지고 그리로 오는지라

예수께서 그 당할 일을 아시고 나아가 이르시되 너희가 누구를 찾느냐

대답하되 나사렛 예수라 하거늘 이르시되 내가 그니라 하시니라

예수께서 그들에게 내가 그니라 하실 때에 그들이 물러가서 땅에 엎드러지는지라

출처: 개역개정 성경


이 부분에 해당하는 매일성경 해설은 아래와 같습니다. 


주도적으로 누구를 찾느냐고 묻고, 신적 정체를 밝히십니다. 군인들은 "나사렛 사람" 예수를 찾지만, 예수님은 하나님의 이름인 "내가 그다"(출 3:14) 하고 답하십니다. 예수님의 정체가 이름을 통해 드러나자, 군인들은 그 권세에 압도당해서 저절로 뒤로 밀려나 땅에 엎드립니다. 하나님이신 분에게 합당한 경배의 자세입니다. 내 신앙과 사랑을 감추지 마십시오. 누구냐고 묻거든 담대함과 겸손함으로 대답하십시오. "나는 그리스도인입니다."

출처: 매일성경 2017년 3,4월호 p.126

오늘 본문은 유다의 배신 하에 군병들이 예수님을 붙잡으러 온 장면입니다. 이 때 예수님은 되려 그들에게 누구를 찾고 있냐고 물으십니다. 그들은 예수를 찾고 있다고 말하고, 그에 예수님은 내가 바로 그라고 답변하십니다. 여기서 "내가 그니라", 즉 "I am he"는 예수님 자신이 하나님임을 드러내는 것이라고 합니다. 신성모독이라는 프레임을 씌워서 자신을 붙잡으러 온 그들에게 자신의 정체성을 전혀 숨기지 않으십니다. 충분히 도망치실 수 있으셨고, 자신의 정체를 숨기실 수도 있으셨지만, 그러지 않으셨습니다. 자신의 정체성을 있는 그대로 드러내셨습니다. 나의 정체성은 무엇일까요? 저의 가장 중요한 정체성은 하나님의 자녀, 즉 그리스도인이라는 것입니다. 예수님을 믿는 사람입니다. 하나님은 제가 그리스도인들과 교회가 욕먹고 있는 이 시대 가운데에서도 정체성을 분명히 드러내길 원하십니다. 세계 곳곳에서는 예수님을 믿는 사람이라고 말하는 것 자체로도 목숨의 위협을 받고 있는 사람들이 많이 있습니다. 그 상황이 설령 닥쳐오더라도 제가 담대하게 겸손함으로 그리스도인임을 밝힐 수 있길 소원합니다. 그리고 매일의 일상에서도 말과 삶으로 제가 그리스도인임을 분명히 드러내길 원합니다. 정체성을 잊지 맙시다. 그리고 잃지 맙시다.

오늘 묵상한 말씀은 요한복음 16:8-11입니다.

그가 와서 죄에 대하여, 의에 대하여, 심판에 대하여 세상을 책망하시리라 죄에 대하여라 함은 그들이 나를 믿지 아니함이요 의에 대하여라 함은 내가 아버지께로 가니 너희가 다시 나를 보지 못함이요 심판에 대하여라 함은 이 세상 임금이 심판을 받았음이라
출처: 개역개정 성경

이 부분에 대한 매일성경 큐티책의 해설은 아래와 같습니다.

성령님은 죄와 의와 심판에 관하여 세상을 책망하실 것입니다. 예수님을 고의로 거부하고 악의적으로 방해한 세상의 죄상을 낱낱이 들추어내십니다. 또 십자가와 부활을 통해 그리스도의 의와 세상의 불의를 드러내시고, 세상 임금인 사탄과 사망의 세력을 깨뜨리십니다. 성령이 내주하는 신자의 삶 또한 세상을 책망합니다. 우리의 말과 삶이 세상의 불의한 민낯을 그대로 보여주어야 합니다. 나는 세상을 책망합니까, 아니면 세상이 나를 책망합니까?
출처: 매일성경 2017년 3, 4월호 p.112

성령은 죄와 의와 심판에 관하여 세상을 책망하십니다. 우선 예수님을 믿지 않는 것 자체가 죄라고 말씀하십니다. 그것을 책망하신다는 것입니다. 이 말씀을 좀 더 생각해볼 필요가 있는 것 같습니다. 예수님을 믿지 않는 사람들을 책망하는 것에 그치는 것이 아니라, 예수님을 믿는 저를 포함한 여러 사람들이 과연 예수님을 제대로 믿고 있는가도 점검해봐야합니다. 저만 생각해봐도 예수님을 믿는다고 말하지만 삶으로 예수님의 가르침을 제대로 따르지 않을 때가 많기 때문입니다. 두번째로 사람들의 의롭지 못함에 대해서도 책망하십니다. 우리는 일상을 살아가면서 크고 작은 죄와 불의를 많이 범합니다. 어떤 죄는 법적인 처벌을 받아야하는 것도 있지만, 꼭 법정에 서지 않아도 하나님의 완전하신 기준에는 벗어난 죄들도 많이 있습니다. 예를 들어 우리가 밥먹듯이 하는 거짓말, 남을 시기하고 미워하는 것, 결혼 밖에서의 성관계 등이 있죠. 이러한 우리의 불의에 대해서 책망하신다는 것입니다. 세번째로 심판에 대해서 책망하십니다. 이 부분에 대해서는 아직 잘 모르겠네요. 주석을 참고하고 좀 더 생각한 후에 다시 정리하겠습니다.
성령은 예수님을 믿는 사람들 안에 내주하시는데 내주하신다면 우리를 통해 이러한 책망하심이 드러나야 합니다. 과연 저의 삶을 보고 느끼고 있는 주변 사람들이 각자가 행하고 있는 크고 작은 죄와 불의에 대해 양심에 가책을 받고 있을까요? 아니면 오히려 제가 믿지 않는 사람들에게 책망받고 있을까요? 또 아니면 다른 사람들에게는 엄격한 기준을 말하고, 저 스스로에게는 지극히 낮은 기준을 적용하고 있진 않을까요? 부디 첫번째가 제 삶이 되었으면 좋겠습니다.

오늘은 http://opencvexamples.blogspot.com/p/learning-opencv-functions-step-by-step.html에 있는 두번째 예제를 공부해보겠습니다!


2. Capture video from camera


카메라를 작동시켜 촬영된 비디오를 캡쳐하는 방법입니다. 우선 코드부터 보시죠. 

위 링크에서 소개하고 있는 예제에 좀 더 덧붙여 캡쳐한 비디오를 그레이영상으로 전환한 것도 함께 출력하도록 코드를 변경했습니다.

#include "opencv2/opencv.hpp"

using namespace cv;


int main(int, char**)

{

VideoCapture cap(0); // open the default camera

if (!cap.isOpened())  // check if we succeeded

return -1;


namedWindow("Video", 1);

        namedWindow("Video1", 1);

while (1) // 무한루프

{

Mat frame, gray_frame;

cap >> frame;         // 카메라로부터 새 프레임을 얻는다. 

cvtColor(frame, gray_frame, COLOR_BGR2GRAY);    // 얻은 프레임을 그레이이미지로 변환한다. 

imshow("Video1", frame);    // 컬러영상 전시

imshow("Video", gray_frame);    // 그레이 영상 전시


if (waitKey(30) == 'c') break;    // c를 타이핑해줘야 무한루프 탈출! 

}

return 0;

}

소스코드에서 VideoCapture cap(0);에 있는 VideoCapture는 동영상 캡쳐를 위한 클래스라고 하네요. 

이 코드를 실행해보면, default camera로 설정되어 있는 웹캠에서 찍히고 있는 장면이 전시됩니다. 아래는 영상으로 출력되고 있는 장면을 스샷찍은 장면입니다. 





오늘부터 티스토리를 시작합니다. 

평생 읽고 공부하고 삶에 적용해야 할 성경을 묵상한 것도 정리하려고 하고, 독서하고 감상평도 남기려고 합니다.  

또 제가 전공중인 영상처리에 대해 공부한 내용들을 잘 정리해서 저 스스로도 공부하고, 관심 있는 분들의 이해를 돕고자 합니다.

배운 것을 출력하는 것이 공부에 있어서 매우 중요하다고 최근에 읽은 <완벽한 공부법>이란 책에서 그러더라구요.

저는 티스토리를 통해서 출력해보려고 합니다.

참고로 지금까지는 네이버 블로그를 이용해왔습니다. http://blog.naver.com/tlarygns0211

좀 더 퀄리티 있는 포스팅을 위해 티스토리를 주로 활용할 계획입니다. 

많은 분들과 소통하며 성장하길 기대합니다. :D

'공지' 카테고리의 다른 글

톈진난만 블로그 활용법  (10) 2017.10.23
포스팅의 목적, 가르침이 아닌 배움.  (2) 2017.06.04
티스토리 시작!  (4) 2017.05.12
  1. 2017.06.12 09:16 신고

    이제 똥 외에 뭔가를 더 출력하겠군

  2. BlogIcon 노정호 2017.10.30 11:33 신고

    파란하늘을보다님도 이런 시작이 있었군요.ㅎㅎ
    저도 시작해보고 싶네요. 화이팅하시고, 계획한 목표 꼭
    달성하시기 바랍니다. GOOD LUCK!!!

당분간 http://opencvexamples.blogspot.com/p/learning-opencv-functions-step-by-step.html 에 있는 초보자들을 위한 예제들을 따라하면서 opencv를 공부하려고 합니다. 총 13개의 예제로 구성되어 있습니다. 참고로 영문사이트입니다.  

오늘은 첫번째 예제를 공부해보겠습니다. :D 


1. Load, Display and Save an image


첫번째 예제는 이미지를 불러와서 전시하고 저장하는 방법을 담고 있습니다. 

우선 코드를 아래에 첨부하겠습니다. 저는 opencv 3.2.0 버전과 visual studio 2017을 사용했습니다. 


main.cpp

여기서 주요한 함수들을 살펴보겠습니다.

imread는 이미지를 불러오는 함수입니다. 저는 tsuL.png를 불러왔습니다.

image = imread("tsuL.png", CV_LOAD_IMAGE_COLOR)에서 CV_LOAD_IMAGE_COLOR는 이미지를 컬러로 불러와서 image변수에 대입하겠다는 뜻입니다.

이 자리에 쓰일 수 있는 것은 4가지가 있습니다. 


  • CV_LOAD_IMAGE_ANYDEPTH - return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
  • CV_LOAD_IMAGE_COLOR(>0) - If set, always convert image to the color one.
  • CV_LOAD_IMAGE_GRAYSCALE (0)- If set, always convert image to the grayscale one.
  • CV_LOAD_IMAGE_UNCHANGED (<0) loads the image as is (including the alpha channel if present)


CV_LOAD_IMAGE_GRAYSCALE은 그레이영상으로 이미지를 변환해서 불러온다는 것이고, CV_LOAD_IMAGE_UNCHANGED는 있는 그대로 불러온다는 의미인 것 같습니다. CV_LOAD_IMAGE_ANYDEPTH는 잘 모르겠네요.. ㅎㅎ (아시는 분 계시면 댓글 부탁드립니다!)


imshow는 이미지를 전시해주는 함수입니다. imshow("window", image)에서 "window"라고 쓰여진 이 부분은 사진을 전시해주는 창의 이름을 의미합니다. 코드 실행결과 아래와 같은 이미지가 전시됩니다. 만약에 imshow("test_image", image)라고 코딩했다면 아래 출력된 이미지에서 창의 이름이 test_image가 되었을 것입니다. 


imwrite는 이미지를 저장해주는 함수입니다. imwrite("result.jpg", image)는 이미지를 result.jpg로 저장해준다는 것입니다. 폴더를 보면 result.jpg가 생성되었음을 확인할 수 있습니다.




+ Recent posts

티스토리 툴바