개발성 향상을 위한 JavaScript의 주석

JavaScript는 type이 불명확하므로 문서화를 통해 그 상세정보를 남겨야 합니다. 그러나 소스코드와 분리된 문서는 사실상 그 활용가치가 매우 떨어집니다. 소스코드와 일원화된 방식으로 문서화가 되어야 하는데, 바로 주석입니다. 아래는 어떤 클래스의 특정함수에 대한 주석을 통한 문서화에 대한 간단한 예시입니다.

/**
 * 메뉴 항목을 추가한다.
 * @param {string} id 항목에 대한 고유 식별자 
 * @param {string} url 항목 아이콘 
 * @param {string} title 항목 타이틀
 * @param {function} callback 실행에 대한 호출 함수
 * @returns {boolean} 성공 여부
 */
addMenu(id, url, title, callback) {
   ...

IDE는 이 주석을 실시간으로 해석해 개발자에게 매우 직관적인 힌트를 제공합니다. 예를들어서 VSCode에서는 아래와 같은 힌트를 제공합니다.

아울러 이러한 주석은 다양한 문서 형식으로써, 예를들어 pdf, docx, html 등과 같은 별도의 문서를 자동으로 생성해 낼 수 있습니다.

Python과 OpenCV – 2 : 비디오를 가지고 시작하기

원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_gui/py_video_display/py_video_display.html 입니다. OpenCV에는 카메라를 통해서도 이미지를 받을 수 있습니다. 아래의 코드는 컴퓨터에 연결된 카메라를 통해 영상을 받아 표시하는 코드입니다.

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

print(cap.get(3), cap.get(4))

ret = cap.set(3,320)
ret = cap.set(4,240)

while(True):
    ret, frame = cap.read() 

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    cv2.imshow('frame', gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

4번 코드에서 첫번째(0) 카메라를 VideoCapture 타입의 객체로 얻어옵니다. 6번은 이 카메라의 영상에 대한 가로, 세로에 대한 픽셀 길이를 출력합니다. 필자의 경우 640 480이 출력되었습니다. 8,9번 코드를 통해 가로와 세로의 크기를 각각 320×240으로 변경합니다. q 키를 누를때까지 11번의 반복문이 무한 반복됩니다. 12번에서 카메라로부터 현재의 영상 하나를 읽어오고, 14번에서 이 영상을 Gray로 변환합니다. 16번에서 이 Gray 영상을 Window에 표시합니다. q 키를 눌러 Window를 닫게 되면 프로그램이 종료되는데, 이때 사용한 카메라에 대한 리소스 해제에 대한 코드가 20번입니다.

카메라로부터 영상을 표시할 수도 있지만, 이를 파일로 기록할 수도 있습니다. 이래의 코드처럼요.

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('d:/output.mp4', fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret == True:
        frame = cv2.flip(frame, 0)
        out.write(frame)

        cv2.imshow('frame', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

cap.release()
out.release()
cv2.destroyAllWindows()

7번의 코드에서 기록할 동영상 파일명과 프레임률(20), 영상의 크기(640, 480)을 지정합니다. 파일명의 확장자는 mp4나 avi 등이 가능한데, 확장자에 따라 만들어지는 영상의 포멧이 결정됩니다. 실제 영상의 저장은 13번 코드입니다. 테스트로 12번 코드에서 영상을 뒤집어 기록하도록 하였습니다. q 키를 눌러 영상을 기록하는 반복문이 종료되면 비디오 객체를 해제해야 하는데 해당 코드가 바로 21, 22번입니다.

카메라가 아닌 동영상 파일로부터도 영상을 얻어 표시할 수 있는데, 해당 코드는 아래와 같습니다.

import numpy as np
import cv2

cap = cv2.VideoCapture('./data/vtest.avi')

while(cap.isOpened()):
    ret, frame = cap.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

카메라를 통한 영상 표시에 대한 코드와 모두 동일한데, 차이점은 단지 4번의 VideoCapture 함수의 인자가 카메라 인덱스가 아닌 파일명이라는 점입니다.

mustache.js를 이용한 HTML Tag에 Data를 Binding

이 글은 Include HTML이라는 글을 기초로 작성된 글입니다. Include HTML은 동적으로 외부의 HTML 리소스를 원하는 위치에 Include 해주는 방법을 설명합니다. 이제 이렇게 Include HTML을 통해 HTML 리소스를 원하는 위치에 포함할 때, 원하는 데이터를 Binding 해주는 방법을 설명합니다. 이를 위해 mustache.js 라이브러리를 이용합니다. mustache.js 라이브러리는 많은 프로그래밍 언어를 지원하는데, 여기서는 JS를 이용하였으며 관련 링크는 https://github.com/janl/mustache.js 입니다.

먼저 메인 페이지는 다음과 같습니다.

위의 id가 containerA인 DOM 요소에 A.html 리소스를 포함하고자 합니다. A.html의 내용은 다음과 같습니다.

조회결과

{{name}}
{{age}}
{{vision}}

위의 {{ .. }}로 묶인 3개의 항목이 보입니다. 이 {{ .. }} 위치에 원하는 데이터를 바인딩하는 것인데요. 바인딩하고자 하는 데이터는 아래와 같습니다.

let data = {
    name: "홍길동",
    age: function () {
        let birthYear = 1576;
        return new Date().getFullYear() - birthYear;
    },
    vision: "모든 세상 사람이 배 부르게 사는 그날까지.."
};

name, age, vision이 {{ .. }}에 지정된 단어와 동일합니다. 이렇게 각 데이터가 1:1로 매칭됩니다. 위의 data는 DBMS 조회를 통해 네트워크를 통해 가져올 수도 있겠죠. 이제 아래의 코드를 통해 외부의 HTML 리소스를 불러오면서 위의 데이터를 바인딩해 화면에 표시해 줍니다.

includeHTML(document.querySelector('#containerA'), 'A.html', data);

실행해보면 결과는 다음과 같습니다.

앞서 작성한 includeHTML 함수는 다음과 같습니다.

function includeHTML(divContainer, urlHTML, data) {
    let xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (this.readyState == 4) {
            if (this.status == 200) {
                var result = Mustache.render(this.responseText, data);
                divContainer.innerHTML = result;
            } else if (this.status == 404) { divContainer.innerHTML = "Page not found."; }
        }
    }

    xhttp.open("GET", urlHTML, true);
    xhttp.send();
}

위의 코드 중 Mustache 코드가 보이는데, 이 라이브러리를 사용하기 위해서는 아래의 코드가 필요합니다.


Include HTML

GIS는 하나의 페이지에서 다양한 기능을 구현하는 경우가 대부분이다. 그러다보니 새로운 컨텐츠를 표시하기 위해 현재 표시되는 페이지(html)에 새로운 Tag를 생성해야 한다. 만약 ASP나 JSP와 같은 서버측 페이지 기술을 사용하지 않고 오로지 Javascript만을 사용하는 경우라면 Javascript 코드로 Tag 생성을 위해 매우 긴 문자열을 기술했을 것이다. 늘 이부분이 걸려왔는데.. 이번에 진행하는 프로젝트에서는 Javascript의 문자열을 통한 Tag의 생성이 아닌 HTML 파일을 원하는 곳에 Include ! 하는 방식을 적용해 본다.

그중 한가지 방법으로 W3School에서 제공하는 방식인데, 약간의 커스터마이징을 거친 버전을 정리해 본다. 예를들어 하나의 메인 페이지가 다음의 DOM 요소로 구성되어 있다고 하자.

위의 containerA에는 A.html을, containerB에는 B.html을 Include해 보고자 하는 것인데.. 먼저 A.html 파일의 내용은 다음과 같다.


  1. 안녕하세요!
  2. Hello!

B.html 파일의 내용은 다음과 같다.


  • 사과
  • 포도

이제 위의 2개의 html 리소스(파일)을 원하는 DIV 요소에 Include 하는 코드는 아래와 같다.

includeHTML(document.querySelector('#containerA'), 'A.html');
includeHTML(document.querySelector('#containerB'), 'B.html');

includeHTML라는 함수는 아래와 같다.

function includeHTML(divContainer, urlHTML) {
        let xhttp = new XMLHttpRequest();

        xhttp.onreadystatechange = function () {
        if (this.readyState == 4) {
            if (this.status == 200) { divContainer.innerHTML = this.responseText; }
            if (this.status == 404) { divContainer.innerHTML = "Page not found."; }
        }
    }

    xhttp.open("GET", urlHTML, true);
    xhttp.send();
}

결과는 아래와 같다.

Python과 OpenCV – 1 : 이미지를 가지고 시작하기

원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_gui/py_image_display/py_image_display.html#display-image 입니다.

OpenCV는 단일 이미지나 동영상의 이미지를 원하는 결과를 분석 및 추출하기 위한 API입니다. OpenCV는 C/C++ 언어로 개발되었고, 이 API를 사용할 수 있는 언어는 C/C++, Java, Python 등입니다. 그리고 활용할 수 있는 플랫폼은 Windows, Linix, Android, iOS 등입니다. 이 글은 OpenCV를 Python 언어를 이용해 학습하면서 정리할 필요가 있다고 판단되는 핵심내용을 꼼꼼이 기록하기 위한 목적을 갖습니다. 각 글에 대한 원문은 글의 서문에 언급해 두고 있으니, 참고하시기 바랍니다. 아울리 이 글은 필자가 원문의 내용을 통해 학습하고 필자 나름대로 재해석하여 글을 작성하고 있습니다. 이 글과 이후의 Python과 OpenCV 관련글은 모두 이와 같습니다.

OpenCV와 Python의 설치 방법은 생략합니다. 검색을 통해 각자 자신에 맞는 환경에 설치하기 바랍니다.

OpenCV는 이미지를 대상으로 어떤 처리를 수행하므로 이미지를 읽고 화면에 표시하는 것은 매우 중요하고 기초적인 내용입니다. 이 글은 바로 이미지를 읽어 화면에 표시하는 내용에 대한 글입니다. 가장 먼저 작성된 코드는 다음과 같습니다.

import numpy as np
import cv2

img = cv2.imread('./data/quark-particle-flavors.jpg', cv2.IMREAD_GRAYSCALE)

cv2.imshow('image', img)

k = cv2.waitKey()

if k == ord('s'):
    cv2.imwrite('d:/z.jpg', img)

cv2.destroyAllWindows()

1,2번 코드는 OpenCV API 사용을 위한 모듈을 불러들이는 코드입니다. OpenCV는 이미지 데이터를 numpy의 자료구조를 사용합니다. 그러므로 OpenCV의 사용에 있어 numpy 모듈은 항상 함께 합니다.

실제 이미지를 불러 들이는 코드는 4번의 cv2.imread 함수인데, 첫번째 인자는 불러드릴 이미지 파일명이며 두번째는 해당 이미지를 불러와 어떤 포맷으로 메모리에 적재해 numpy 자료 구조의 객체를 생성할 것인지입니다. 위의 코드에서는 cv.IMREAD_GRAYSCALE로써 비록 해당 원본 이미지가 RGB의 칼라 이미지이지만 Gray 색상으로 해석해 이미지 객체를 반환하라는 것입니다. cv.IMREAD_GRAYSCALE 이외에도 사용할 수 있는 값은 다음과 같습니다.

  • cv2.IMREAD_COLOR : 별도로 지정하지 않을 경우 사용되는 기본값이며 칼라 이미지로 읽어드림. 이미지의 투명도값은 무시된다.
  • cv2.IMREAD_GRAYSCALE : 이미지를 Grayscale로 읽는다
  • cv2.IMREAD_UNCHANGED : 투명도인 Alpha 채널을 포함하여 읽는다.

반환된 이미지는 img 변수에 담기며 img 변수의 type을 확인해 보면 ‘numpy.ndarray’라는 타입으로 표시됩니다. 이제 이 이미지를 표시하기 위해 6번의 코드인 cv2.imshow 함수가 사용되는데 첫번째 인수는 이미지가 표시되는 Window의 식별자인 이름이고 두번째가 표시되는 이미지 객체입니다. 표시되는 이미지 객체는 4번 코드에서 정의된 변수입니다.

8번 코드는 사용자가 키 입력을 기다리는 함수인 cv2.waitKey로 인자값이 없거나 0일 경우 시간 제한없이 사용자의 키 입력을 기다립니다. 인자가 지정되면 해당값의 시간만큼만 키 입력을 기다립니다.>/p>

10번 코드는 입력된 키값이 소문자 s일 경우 img 객체의 저장된 이미지를 또 다른 파일로 저장하라는 cv2.imwrite 함수입니다.

13번은 프로그램의 종료를 위해 표시된 모든 Window을 닫으라는 코드입니다. 실행해보면 다음 화면과 같습니다.

이미지의 표시는 OpenCV 방식만 있는것이라 아니고 Matplotlib를 사용할 수도 있습니다. 이미지 처리의 결과를 그래프를 통해 효과적으로 표시하기 위해 Matplotlib를 사용합니다. Matplotlib를 이용한 이미지 표시의 코드는 아래와 같습니다.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('./data/quark-particle-flavors.jpg', 0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([])
plt.show()

실행 결과는 다음과 같습니다.